Azure_RTOS_USBX_Device_Stack_User_Guide
Azure_RTOS_USBX_Device_Stack_User_Guide
This document does not provide you with any legal rights to any intellectual property in any Microsoft product. You
may copy and use this document for your internal, reference purposes.
Microsoft Azure RTOS, Azure RTOS FileX, Azure RTOS GUIX, Azure RTOS GUIX Studio, Azure RTOS NetX, Azure
RTOS NetX Duo, Azure RTOS ThreadX, Azure RTOS TraceX, Azure RTOS Trace, event-chaining, picokernel, and
preemption-threshold are trademarks of the Microsoft group of companies. All other trademarks are property of their
respective owners.
Revision 6.0
2
Contents
Contents .................................................................................................... 3
About This Guide ...................................................................................... 6
3
Chapter 4: Description of USBX Device Services ................................ 25
ux_device_stack_alternate_setting_get ......................................................... 26
ux_device_stack_alternate_setting_set.......................................................... 27
ux_device_stack_class_register ..................................................................... 28
ux_device_stack_class_unregister ................................................................. 30
ux_device_stack_configuration_get ............................................................... 31
ux_device_stack_configuration_set................................................................ 32
ux_device_stack_descriptor_send ................................................................. 33
ux_device_stack_disconnect .......................................................................... 34
ux_device_stack_endpoint_stall ..................................................................... 35
ux_device_stack_host_wakeup ...................................................................... 36
ux_device_stack_initialize .............................................................................. 37
ux_device_stack_interface_delete ................................................................. 41
ux_device_stack_interface_get ...................................................................... 42
ux_device_stack_interface_set ...................................................................... 43
ux_device_stack_interface_start .................................................................... 44
ux_device_stack_transfer_request ................................................................. 45
ux_device_stack_transfer_abort .................................................................... 47
ux_device_stack_uninitialize .......................................................................... 48
4
USB Device HID Class ....................................................................................... 79
ux_device_class_hid_event_set ..................................................................... 81
hid_callback ................................................................................................... 82
Index ........................................................................................................ 83
5
About This Guide
This guide provides comprehensive information about USBX, the high performance
USB foundation software from Microsoft
It is intended for the embedded real-time software developer. The developer should be
familiar with standard real-time operating system functions, the USB specification, and
the C programming language.
For technical information related to USB, see the USB specification and USB Class
specifications that can be downloaded at http://www.USB.org/developers
Organization
Chapter 2 gives the basic steps to install and use USBX with your ThreadX
application
6
Chapter 1: Introduction to USBX
USBX is a full-featured USB stack for deeply embedded applications. This chapter
introduces USBX, describing its applications and benefits.
USBX features
USBX support the three existing USB specifications: 1.1, 2.0 and OTG. It is designed to
be scalable and will accommodate simple USB topologies with only one connected
device as well as complex topologies with multiple devices and cascading hubs. USBX
supports all the data transfer types of the USB protocols: control, bulk, interrupt, and
isochronous.
USBX supports both the host side and the device side. Each side is comprised of three
layers:
• Controller layer
• Stack layer
• Class layer
7
Class Driver Class Driver
Software
Host Stack Device Stack
Hardware
Host Controller Device Controller
Product Highlights
Complete ThreadX processor support
No royalties
Complete ANSI C source code
Real-time performance
Responsive technical support
Multiple class support
Multiple class instances
Integration of classes with ThreadX, FileX and NetX
Support for USB devices with multiple configuration
Support for USB composite devices
Support for USB power management
Support for USB OTG
Export trace events for TraceX
8
Complete USB Device Framework Support
USBX can support the most demanding USB devices, including multiple configurations,
multiple interfaces, and multiple alternate settings.
Easy-To-Use APIs
USBX provides the very best deeply embedded USB stack in a manner that is easy to
understand and use. The USBX API makes the services intuitive and consistent. By
using the provided USBX class APIs, the user application does not need to understand
the complexity of the USB protocols.
9
Chapter 2: USBX Installation
Host Considerations
Computer Type
Embedded development is usually performed on Windows PC or Unix host computers.
After the application is compiled, linked, and located on the host, it is downloaded to the
target hardware for execution.
Download Interfaces
Usually the target download is done over an RS-232 serial interface, although parallel
interfaces, USB, and Ethernet are becoming more popular. See the development tool
documentation for available options.
Debugging Tools
Debugging is done typically over the same link as the program image download. A
variety of debuggers exist, ranging from small monitor programs running on the target
through Background Debug Monitor (BDM) and In-Circuit Emulator (ICE) tools. Of
course, the ICE tool provides the most robust debugging of actual target hardware.
Target Considerations
USBX requires between 24 KBytes and 64 KBytes of Read Only Memory (ROM) on the
target in host mode. The amount of memory required is dependent on the type of
controller used and the USB classes linked to USBX. Another 32 KBytes of the target’s
Random Access Memory (RAM) are required for USBX global data structures and
memory pool. This memory pool can also be adjusted depending on the expected
number of devices on the USB and the type of USB controller. The USBX device side
requires roughly 10-12K of ROM depending on the type of device controller. The RAM
memory usage depends on the type of class emulated by the device.
USBX also relies on ThreadX semaphores, mutexes, and threads for multiple thread
protection, and I/O suspension and periodic processing for monitoring the USB bus
topology.
10
Product Distribution
The exact content of the distribution CD depends on the target processor, development
tools, and the USBX package. Following is a list of the important files common to most
product distributions:
readme_usbx.txt This file contains specific information about the USBX port,
including information about the target processor and the
development tools.
All filenames are in lower-case. This naming convention makes it easier to convert the
commands to Unix development platforms.
Step 1: Backup the USBX distribution disk and store it in a safe location.
Step 2: Use the same directory in which you previously installed ThreadX on the host
hard drive. All USBX names are unique and will not interfere with the
previous USBX installation.
Step 3: Add a call to ux_system_initialize at or near the beginning of
tx_application_define. This is where the USBX resources are initialized.
Step 4: Add a call to ux_device_stack_initialize.
Step 5: Add one or more calls to initialize the required USBX classes (either host
and/or devices classes)
Step 6: Add one or more calls to initialize the device controller available in the
system.
Step 7 It may be required to modify the tx_low_level_initialize.c file to add low level
hardware initialization and interrupt vector routing. This is specific to the
hardware platform and will not be discussed here.
11
Step 8: Compile application source code and link with the USBX and ThreadX run
time libraries (FileX and/or Netx may also be required if the USB storage
class and/or USB network classes are to be compiled in), ux.a (or ux.lib) and
tx.a (or tx.lib). The resulting can be downloaded to the target and executed!
12
Configuration Options
There are several configuration options for building the USBX library. All options are
located in the ux_user.h.
The list below details each configuration option. Additional development tool options are
described in the readme_usbx.txt file supplied on the distribution disk:
UX_PERIODIC_RATE
This value represents how many ticks per seconds for a specific hardware platform. The
default is 1000 indicating 1 tick per millisecond.
UX_THREAD_STACK_SIZE
This value is the size of the stack in bytes for the USBX threads. It can be typically 1024
or 2048 bytes depending on the processor used and the host controller.
UX_THREAD_PRIORITY_ENUM
This is the ThreadX priority value for the USBX enumeration threads that monitors the
bus topology.
UX_THREAD_PRIORITY_CLASS
This is the ThreadX priority value for the standard USBX threads.
UX_THREAD_PRIORITY_KEYBOARD
This is the ThreadX priority value for the USBX HID keyboard class.
UX_THREAD_PRIORITY_DCD
This is the ThreadX priority value for the device controller thread.
UX_NO_TIME_SLICE
This value actually defines the time slice that will be used for threads. For example, if
defined to 0, the ThreadX target port does not use time slices.
UX_MAX_SLAVE_CLASS_DRIVER
This is the maximum number of USBX classes that can be registered via
ux_device_stack_class_register.
UX_MAX_SLAVE_LUN
13
This value represents the current number of SCSI logical units represented in the
device storage class driver.
UX_SLAVE_CLASS_STORAGE_INCLUDE_MMC
If defined, the storage class will handle Multi-Media Commands (MMC) i.e. DVD-ROM.
UX_DEVICE_CLASS_CDC_ECM_NX_PKPOOL_ENTRIES
This value represents the number of NetX packets in the CDC-ECM class’ packet pool.
The default is 16.
UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH
This value represents the maximum number of bytes received on a control endpoint in
the device stack. The default is 256 bytes but can be reduced in memory constraint
environments.
UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH
This value represents the the maximum length in bytes of a HID report.
UX_DEVICE_CLASS_HID_MAX_EVENTS_QUEUE
this value represents the the maximum number of HID reports that can be queued at
once.
UX_SLAVE_REQUEST_DATA_MAX_LENGTH
This value represents the maximum number of bytes received on a bulk endpoint in the
device stack. The default is 4096 bytes but can be reduced in memory constraint
environments.
14
Source Code Tree
The USBX files are provided in several directories.
USBX Core
USBX Device Stack USBX Host Stack USBX Network USBX Examples Windows host files
USBX OTG
15
In order to make the files recognizable by their names, the following convention has
been adopted:
Input parameters:
Not all systems require the definition of cache safe memory. In such a system, the
values passed during the initialization for the memory pointer will be set to UX_NULL
and the size of the pool to 0. USBX will then use the regular memory pool in lieu of the
cache safe pool.
16
In a system where the regular memory is not cache safe and a controller requires to
perform DMA memory it is necessary to define a memory pool in a cache safe zone.
ux_dcd_controller_initialize(0x7BB00000, 0, 0xB7A00000);
The following example is the initialization of USBX in device mode with the storage
device class and a generic controller controller:
17
/* Initialize USBX Memory */
ux_system_initialize(memory_pointer,(128*1024), 0, 0);
/* The code below is required for installing the device portion of USBX */
status = ux_device_stack_initialize(&device_framework_high_speed,
DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED,
&device_framework_full_speed,
DEVICE_FRAMEWORK_LENGTH_FULL_SPEED,
&string_framework, STRING_FRAMEWORK_LENGTH,
&language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH,
UX_NULL);
/* Store the number of LUN in this device storage instance: single LUN. */
storage_parameter.ux_slave_class_storage_parameter_number_lun = 1;
/* Initialize the storage class parameters for reading/writing to the Flash Disk. */
storage_parameter.ux_slave_class_storage_parameter_lun[0].
ux_slave_class_storage_media_last_lba = 0x1e6bfe;
storage_parameter.ux_slave_class_storage_parameter_lun[0].
ux_slave_class_storage_media_block_length = 512;
storage_parameter.ux_slave_class_storage_parameter_lun[0].
ux_slave_class_storage_media_type = 0;
storage_parameter.ux_slave_class_storage_parameter_lun[0].
ux_slave_class_storage_media_removable_flag = 0x80;
storage_parameter.ux_slave_class_storage_parameter_lun[0].
ux_slave_class_storage_media_read =
tx_demo_thread_flash_media_read;
storage_parameter.ux_slave_class_storage_parameter_lun[0].
ux_slave_class_storage_media_write =
tx_demo_thread_flash_media_write;
storage_parameter.ux_slave_class_storage_parameter_lun[0].
ux_slave_class_storage_media_status =
tx_demo_thread_flash_media_status;
/* Initialize the device storage class. The class is connected with interface 0 */
status = ux_device_stack_class_register(ux_system_slave_class_storage_name,
ux_device_class_storage_entry,
ux_device_class_storage_thread,0,
(VOID *)&storage_parameter);
18
Troubleshooting
USBX is delivered with a demonstration file and a simulation environment. It is always a
good idea to get the demonstration platform running first—either on the target hardware
or a specific demonstration platform.
USBX Version ID
The current version of USBX is available both to the user and the application software
during run-time.
The programmer can obtain the USBX version from examination of the
readme_usbx.txt file. In addition, this file also contains a version history of the
corresponding port. Application software can obtain the USBX version by examining the
global string _ux_version_id, which is defined in ux_port.h.
19
Chapter 3: Functional Components of
USBX Device Stack
This chapter contains a description of the high performance USBX embedded USB
device stack from a functional perspective.
Execution Overview:
USBX for the device is composed of several components:
Initialization
Application interface calls
Device Classes
USB Device Stack
Device controller
VBUS manager
Atmel USB Device OKI USB Device Philips USB Device Other USB Device
controller Driver controller Driver controller Driver controller Driver
Initialization
In order to activate USBX, the function ux_system_initialize must be called. This
function initializes the memory resources of USBX.
20
In order to activate USBX device facilities, the function ux_device_stack_initialize must
be called. This function will in turn initialize all the resources used by the USBX device
stack such as ThreadX threads, mutexes, and semaphores.
It is up to the application initialization to activate the USB device controller and one or
more USB classes. Contrary to the USB host side, the device side can have only one
USB controller driver running at any time. When the classes have been registered to the
stack and the device controller(s) initialization function has been called, the bus is active
and the stack will reply to bus reset and host enumeration commands.
Normally, a USBX application should not have to call any of the USB device stack APIs.
Most applications will only access the USB Class APIs.
Device Framework
The USB device side is responsible for the definition of the device framework. The
device framework is divided into three categories, as described in the following sections.
USBX supports device component definition for both high and full speed (low speed
being treated the same way as full speed). This allows the device to operate differently
21
when connected to a high speed or full speed host. The typical differences are the size
of each endpoint and the power consumed by the device.
The definition of the device component takes the form of a byte string that follows the
USB specification. The definition is contiguous and the order in which the framework is
represented in memory will be the same as the one returned to the host during
enumeration.
Following is an example of a device framework for a high speed USB Flash Disk.
#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60
UCHAR device_framework_high_speed[] = {
/* Device descriptor */
0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02,
0x03, 0x01,
/* Configuration descriptor */
0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0,
0x32,
/* Interface descriptor */
0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50,
0x00,
The main strings are indexes embedded in the device descriptors. Additional strings
indexes can be embedded into individual interfaces.
Assuming the device framework above has three string indexes embedded into the
device descriptor, the string framework definition could look like this:
22
/* String Device Framework:
Byte 0 and 1: Word containing the language ID: 0x0904 for US
Byte 2 : Byte containing the index of the descriptor
Byte 3 : Byte containing the length of the descriptor string
*/
#define STRING_FRAMEWORK_LENGTH 38
UCHAR string_framework[] = {
If different strings have to be used for each speed, different indexes must be used as
the indexes are speed agnostic.
The encoding of the string is UNICODE-based. For more information on the UNICODE
encoding standard refer to the following publication:
The Unicode Standard, Worldwide Character Encoding, Version 1., Volumes 1
and 2, The Unicode Consortium, Addison-Wesley Publishing Company, Reading
MA.
#define LANGUAGE_ID_FRAMEWORK_LENGTH 2
UCHAR language_id_framework[] = {
/* English. */
0x09, 0x04
};
To support additional languages, simply add the language code double-byte definition
after the default English code. The language code has been defined by Microsoft in the
document:
23
Developing International Software for Windows 95 and Windows NT, Nadine
Kano, Microsoft Press, Redmond WA
VBUS Manager
In most USB device designs, VBUS is not part of the USB Device core but rather
connected to an external GPIO, which monitors the line signal.
As a result, VBUS has to be managed separately from the device controller driver.
It is up to the application to provide the device controller with the address of the VBUS
IO. VBUS must be initialized prior to the device controller initialization.
Depending on the platform specification for monitoring VBUS, it is possible to let the
controller driver handle VBUS signals after the VBUS IO is initialized or if this is not
possible, the application has to provide the code for handling VBUS.
If the application wishes to handle VBUS by itself, its only requirement is to call the
function
ux_device_stack_disconnect()
when it detects that a device has been extracted. It is not necessary to inform the
controller when a device is inserted because the controller will wake up when the BUS
RESET assert/deassert signal is detected.
24
Chapter 4: Description of USBX Device
Services
25
ux_device_stack_alternate_setting_get
Get current alternate setting for an interface value
Prototype
UINT ux_device_stack_alternate_setting_get(ULONG interface_value)
Description
This function is used by the USB host to obtain the current alternate setting for a
specific interface value. It is called by the controller driver when a
GET_INTERFACE request is received.
Input Parameter
Return Values
Example
ULONG interface_value;
UINT status;
status = ux_device_stack_alternate_setting_get(interface_value);
26
ux_device_stack_alternate_setting_set
Set current alternate setting for an interface value
Prototype
Description
This function is used by the USB host to set the current alternate setting for a
specific interface value. It is called by the controller driver when a
SET_INTERFACE request is received. When the SET_INTERFACE is
completed, the values of the alternate settings are applied to the class.
Parameters
Return Values
UX_SUCCESS (0x00)
The data transfer was
completed.
UX_INTERFACE_HANDLE_UNKNOWN (0x52) No interface attached.
UX_FUNCTION_NOT_SUPPORTED (0x54) Device is not configured.
UX_ERROR (0xFF) Wrong interface value.
Example
ULONG interface_value;
ULONG alternate_setting_value;
27
ux_device_stack_class_register
Register a new USB device class
Prototype
Description
This function is used by the application to register a new USB device class. This
registration starts a class container and not an instance of the class. A class
should have an active thread and be attached to a specific interface.
Some classes expect a parameter or parameter list. For instance, the device
storage class would expect the geometry of the storage device it is trying to
emulate. The parameter field is therefore dependent on the class requirement
and can be a value or a pointer to a structure filled with the class values.
Parameters
Return Values
28
Example
UINT status;
29
ux_device_stack_class_unregister
Unregister a USB device class
Prototype
Description
Parameters
Return Values
Example
30
ux_device_stack_configuration_get
Get the current configuration
Prototype
UINT ux_device_stack_configuration_get(VOID)
Description
This function is used by the host to obtain the current configuration running in the
device.
Input Parameter
None
Return Value
Example
UINT status;
31
ux_device_stack_configuration_set
Set the current configuration
Prototype
Description
This function is used by the host to set the current configuration running in the
device. Upon reception of this command, the USB device stack will activate the
alternate setting 0 of each interface connected to this configuration.
Input Parameter
Return Value
Example
ULONG configuration_value;
UINT status;
32
ux_device_stack_descriptor_send
Send a descriptor to the host
Prototype
Description
This function is used by the device side to return a descriptor to the host. This
descriptor can be a device descriptor, a configuration descriptor or a string
descriptor.
Parameters
UX_DEVICE_DESCRIPTOR_ITEM
UX_CONFIGURATION_DESCRIPTOR_ITEM
UX_STRING_DESCRIPTOR_ITEM
UX_DEVICE_QUALIFIER_DESCRIPTOR_ITEM
UX_OTHER_SPEED_DESCRIPTOR_ITEM
Return Values
Example
ULONG descriptor_type;
ULONG request_index;
ULONG host_length;
UINT status;
33
ux_device_stack_disconnect
Disconnect device stack
Prototype
UINT ux_device_stack_disconnect(VOID)
Description
The VBUS manager calls this function when there is a device disconnection. The
device stack will inform all classes registered to this device and will thereafter
release all the device resources.
Input Parameter
None
Return Value
Example
UINT status;
34
ux_device_stack_endpoint_stall
Request endpoint Stall condition
Prototype
Description
This function is called by the USB device class when an endpoint should return a
Stall condition to the host.
Input Parameter
Return Value
Example
UINT status;
35
ux_device_stack_host_wakeup
Wake up the host
Prototype
UINT ux_device_stack_host_wakeup(VOID)
Description
This function is called when the device wants to wake up the host. This
command is only valid when the device is in suspend mode. It is up to the device
application to decide when it wants to wake up the USB host. For instance, a
USB modem can wake up a host when it detects a RING signal on the telephone
line.
Input Parameter
None
Return values
Example
UINT status;
36
ux_device_stack_initialize
Initialize USB device stack
Prototype
Description
This function is called by the application to initialize the USB device stack. It does
not initialize any classes or any controllers. This should be done with separate
function calls. This call mainly provides the stack with the device framework for
the USB function. It supports both high and full speeds with the possibility to
have completely separate device framework for each speed. String framework
and multiple languages are supported.
Parameters
Return Values
37
Example
#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50
UCHAR device_framework_full_speed[] = {
/* Device descriptor */
0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08,
0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01,
/* Configuration descriptor */
0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0,
0x32,
/* Interface descriptor */
0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50,
0x00,
#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60
UCHAR device_framework_high_speed[] = {
/* Device descriptor */
0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02,
0x03, 0x01,
/* Configuration descriptor */
0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0,
0x32,
/* Interface descriptor */
0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50,
0x00,
38
/* String Device Framework:
Byte 0 and 1: Word containing the language ID: 0x0904 for US
Byte 2 : Byte containing the index of the descriptor
Byte 3 : Byte containing the length of the descriptor string
*/
#define STRING_FRAMEWORK_LENGTH 38
UCHAR string_framework[] = {
#define LANGUAGE_ID_FRAMEWORK_LENGTH 2
UCHAR language_id_framework[] = {
/* English. */
0x09, 0x04
};
The application can request a call back when the controller changes its state. The two
main states for the controller are:
UX_DEVICE_SUSPENDED
UX_DEVICE_RESUMED
If the application does not need Suspend/Resume signals, it would supply a UX_NULL
function.
UINT status;
status = ux_device_stack_initialize(&device_framework_high_speed,
DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED,
39
&device_framework_full_speed,
DEVICE_FRAMEWORK_LENGTH_FULL_SPEED,
&string_framework,
STRING_FRAMEWORK_LENGTH,
&language_id_framework,
LANGUAGE_ID_FRAMEWORK_LENGTH,
UX_NULL);
40
ux_device_stack_interface_delete
Delete a stack interface
Prototype
UINT ux_device_stack_interface_delete(UX_SLAVE_INTERFACE *interface)
Description
Input Parameter
Return Value
Example
UINT status;
41
ux_device_stack_interface_get
Get the current interface value
Prototype
UINT ux_device_stack_interface_get(UINT interface_value)
Description
This function is called when the host queries the current interface. The device
returns the current interface value.
Input Parameter
Return Values
Example
ULONG interface_value;
UINT status;
42
ux_device_stack_interface_set
Change the alternate setting of the interface
Prototype
Description
This function is called when the host requests a change of the alternate setting
for the interface.
Parameters
Return Values
Example
UCHAR * device_framework
ULONG device_framework_length;
ULONG alternate_setting_value;
UINT status;
43
ux_device_stack_interface_start
Start search for a class to own an interface instance
Prototype
Description
This function is called when an interface has been selected by the host and the
device stack needs to search for a device class to own this interface instance.
Input Parameter
Return Values
Example
UINT status;
44
ux_device_stack_transfer_request
Request to transfer data to the host
Prototype
Description
This function is called when a class or the stack wants to transfer data to the
host. The host always polls the device but the device can prepare data in
advance.
Parameters
Return Values
45
Example
UINT status;
46
ux_device_stack_transfer_abort
Cancel a transfer request
Prototype
UINT ux_device_stack_transfer_abort(UX_SLAVE_TRANSFER *transfer_request,
ULONG completion_code)
Description
Parameters
Return Value
Example
UINT status;
47
ux_device_stack_uninitialize
Unitialize stack
Prototype
UINT ux_device_stack_uninitialize()
Description
This function is called when an application needs to unitialize the USBX device
stack – all device stack resources are freed. This should be called after all
classes have been unregistered via ux_device_stack_class_unregister.
Parameters
None
Return Value
48
Chapter 5: USBX Device Class
Considerations
Device Class registration
Each device class follows the same principle for registration. A structure containing
specific class parameters is passed to the class initialize function :
/* Initilize the device hid class. The class is connected with interface
0 */
status = ux_device_stack_class_register(_ux_system_slave_class_hid_name,
ux_device_class_hid_entry,1,0, (VOID *)&hid_parameter);
Each class can register, optionally, a callback function when an instance of the class
gets activated. The callback is then called by the device stack to inform the application
that an instance was created.
The application would have in its body the 2 functions for activation and deactivation :
VOID tx_demo_hid_instance_activate(VOID *hid_instance)
{
49
It is not recommended to do anything within these functions but to memorise the
instance of the class and synchronize with the rest of the application.
50
USB Device Storage Class
The USB device storage class allows for a storage device embedded in the system to
be made visible to a USB host.
The USB device storage class does not by itself provide a storage solution. It merely
accepts and interprets SCSI requests coming from the host. When one of these
requests is a read or a write command, it will invoke a pre-defined call back to a real
storage device handler, such as an ATA device driver or a Flash device driver.
When initializing the device storage class, a pointer structure is given to the class that
contains all the information necessary. An example is given below.
/* Store the number of LUN in this device storage instance: single LUN. */
storage_parameter.ux_slave_class_storage_parameter_number_lun = 1;
storage_parameter.ux_slave_class_storage_parameter_lun[0].
ux_slave_class_storage_media_last_lba = 0x1e6bfe;
storage_parameter.ux_slave_class_storage_parameter_lun[0].
ux_slave_class_storage_media_block_length = 512;
storage_parameter.ux_slave_class_storage_parameter_lun[0].
ux_slave_class_storage_media_type = 0;
storage_parameter.ux_slave_class_storage_parameter_lun[0].
ux_slave_class_storage_media_removable_flag = 0x80;
storage_parameter.ux_slave_class_storage_parameter_lun[0].
ux_slave_class_storage_media_read_only_flag = UX_FALSE;
storage_parameter.ux_slave_class_storage_parameter_lun[0].
ux_slave_class_storage_media_read = tx_demo_thread_flash_media_read;
storage_parameter.ux_slave_class_storage_parameter_lun[0].
ux_slave_class_storage_media_write =
tx_demo_thread_flash_media_write;
storage_parameter.ux_slave_class_storage_parameter_lun[0].
51
ux_slave_class_storage_media_status =
tx_demo_thread_flash_media_status;
In this example, the driver storage strings are customized by assigning string pointers to
corresponding parameter. If any one of the string pointer is left to UX_NULL, the default
ExpressLogic string is used.
In this example, the drive’s last block address or LBA is given as well as the logical
sector size. The LBA is the number of sectors available in the media –1. The block
length is set to 512 in regular storage media. It can be set to 2048 for optical drives.
The application needs to pass three callback function pointers to allow the storage class
to read, write and obtain status for the media.
Where:
The return value can have either the value UX_SUCCESS or UX_ERROR indicating a
successful or unsuccessful operation. These operations do not need to return any other
error codes. If there is an error in any operation, the storage class will invoke the status
call back function.
52
The calling parameter media_id is not currently used and should always be 0. In the
future it may be used to distinguish multiple storage devices or storage devices with
multiple SCSI LUNs. This version of the storage class does not support multiple
instances of the storage class or storage devices with multiple SCSI LUNs.
The return value is a SCSI error code that can have the following format:
Bits 0-7 Sense_key
Bits 8-15 Additional Sense Code
Bits 16-23 Additional Sense Code Qualifier
53
07 27 00 WRITE PROTECTED MEDIA
0B 4E 00 OVERLAPPED COMMAND ATTEMPTED
There are two additional, optional callbacks the application may implement; one is for
responding to a GET_STATUS_NOTIFICATION command and the other is for
responding to the SYNCHRONIZE_CACHE command.
Where:
The return value indicates whether or not the command succeeded – should be either
UX_SUCCESS or UX_ERROR.
If the application does not implement this callback, then upon receiving the
GET_STATUS_NOTIFICATION command, USBX will notify the host that the command
is not implemented.
Where:
54
number_blocks specifies the number of blocks to synchronize.
lba is the sector address of the first block to synchronize.
media_status should be filled out exactly like the media status callback return
value.
The return value indicates whether or not the command succeeded – should be either
UX_SUCCESS or UX_ERROR.
storage_parameter.ux_slave_class_storage_parameter_lun[0].
ux_slave_class_storage_media_last_lba = 0x7bbff;
storage_parameter.ux_slave_class_storage_parameter_lun[0].
ux_slave_class_storage_media_block_length = 512;
storage_parameter.ux_slave_class_storage_parameter_lun[0].
ux_slave_class_storage_media_type = 0;
storage_parameter.ux_slave_class_storage_parameter_lun[0].
ux_slave_class_storage_media_removable_flag = 0x80;
storage_parameter.ux_slave_class_storage_parameter_lun[0].
ux_slave_class_storage_media_read = tx_demo_thread_flash_media_read;
storage_parameter.ux_slave_class_storage_parameter_lun[0].
ux_slave_class_storage_media_write =
tx_demo_thread_flash_media_write;
storage_parameter.ux_slave_class_storage_parameter_lun[0].
ux_slave_class_storage_media_status =
tx_demo_thread_flash_media_status;
storage_parameter.ux_slave_class_storage_parameter_lun[1].
ux_slave_class_storage_media_last_lba = 0x04caaf;
storage_parameter.ux_slave_class_storage_parameter_lun[1].
ux_slave_class_storage_media_block_length = 2048;
storage_parameter.ux_slave_class_storage_parameter_lun[1].
55
ux_slave_class_storage_media_type = 5;
storage_parameter.ux_slave_class_storage_parameter_lun[1].
ux_slave_class_storage_media_removable_flag = 0x80;
storage_parameter.ux_slave_class_storage_parameter_lun[1].
ux_slave_class_storage_media_read = tx_demo_thread_cdrom_media_read;
storage_parameter.ux_slave_class_storage_parameter_lun[1].
ux_slave_class_storage_media_write =
tx_demo_thread_cdrom_media_write;
storage_parameter.ux_slave_class_storage_parameter_lun[1].
ux_slave_class_storage_media_status =
tx_demo_thread_cdrom_media_status;
/* Initialize the device storage class for a Flash disk and CD-ROM. The
class is connected with interface 0 */
status =
ux_device_stack_class_register(_ux_system_slave_class_storage_name,
ux_device_class_storage_entry, ux_device_class_storage_thread,0,
(VOID *) &storage_parameter);
56
USB Device CDC-ACM Class
The USB device CDC-ACM class allows for a USB host system to communicate with
the device as a serial device. This class is based on the USB standard and is a subset
of the CDC standard.
57
/* Endpoint 2 descriptor 7 bytes */
0x07, 0x05, 0x81,0x02,0x40, 0x00, 0x00,
};
The CDC-ACM class uses a composite device framework to group interfaces (control
and data). As a result care should be taken when defining the device descriptor. USBX
relies on the IAD descriptor to know internally how to bind interfaces. The IAD descriptor
should be declared before the interfaces and contain the first interface of the CDC-ACM
class and how many interfaces are attached.
The CDC-ACM class also uses a union functional descriptor which performs the same
function as the newer IAD descriptor. Although a Union Functional descriptor must be
declared for historical reasons and compatibility with the host side, it is not used by
USBX.
/* Initialize the device cdc class. This class owns both interfaces
starting with 0. */
status =
ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name,
ux_device_class_cdc_acm_entry, 1,0, ¶meter);
The 2 parameters defined are callback pointers into the user applications that will be
called when the stack activates or deactivate this class.
The third parameter defined is a callback pointer to the user application that will be
called when there is line coding or line states parameter change. E.g., when there is
request from host to change DTR state to TRUE, the callback is invoked, in it user
application can check line states through IOCTL function to kow host is ready for
communication.
58
be modified to reflect the PID/VID used by the device. The PID/VID will be specific to
the final customer when the company and the product are registered with the USB-IF.
In the inf file, the fields to modify are located here:
[DeviceList]
%DESCRIPTION%=DriverInstall, USB\VID_8484&PID_0000
[DeviceList.NTamd64]
%DESCRIPTION%=DriverInstall, USB\VID_8484&PID_0000
In the device framework of the CDC-ACM device, the PID/VID are stored in the device
descriptor (see the device descriptor declared above)
When a USB host systems discovers the USB CDC-ACM device, it will mount a serial
class and the device can be used with any serial terminal program. See the host
Operating System for reference.
59
ux_device_class_cdc_acm_ioctl
Perform IOCTL on the CDC-ACM interface
Prototype
This function is called when an application needs to perform various ioctl calls to
the cdc acm interface
Parameters
Return Value
Example
if(status != UX_SUCCESS)
return;
60
Ioctl functions :
UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_CODING 1
UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING 2
UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_STATE 3
UX_SLAVE_CLASS_CDC_ACM_IOCTL_ABORT_PIPE 4
UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_STATE 5
UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START 6
UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_STOP 7
61
ux_device_class_cdc_acm_ioctl:
UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_CODING
Perform IOCTL Set Line Coding on the CDC-ACM interface
Prototype
This function is called when an application needs to Set the Line Coding
parameters.
Parameters
Return Value
Example
status = _ux_slave_class_cdc_acm_ioctl(cdc_acm,
UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_CODING, &line_coding);
if (status != UX_SUCCESS)
break;
62
ux_device_class_cdc_acm_ioctl:
UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING
Perform IOCTL Get Line Coding on the CDC-ACM interface
Prototype
device_class_cdc_acm_ioctl (UX_SLAVE_CLASS_CDC_ACM *cdc_acm, ULONG
ioctl_function, VOID *parameter)
Description
This function is called when an application needs to Get the Line Coding
parameters.
Parameters
Return Value
Example
/* This is to retrieve BAUD rate. */
status = _ux_device_class_cdc_acm_ioctl(cdc_acm_slave,
UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING, &line_coding);
/* Any error ? */
if (status == UX_SUCCESS)
{
/* Decode BAUD rate. */
switch (line_coding.ux_slave_class_cdc_acm_parameter_baudrate)
{
case 1200 :
status = tx_demo_thread_slave_cdc_acm_response("1200", 4);
break;
63
case 2400 :
status = tx_demo_thread_slave_cdc_acm_response("2400", 4);
break;
case 4800 :
status = tx_demo_thread_slave_cdc_acm_response("4800", 4);
break;
case 9600 :
status = tx_demo_thread_slave_cdc_acm_response("9600", 4);
break;
case 115200 :
status = tx_demo_thread_slave_cdc_acm_response("115200", 6);
break;
64
ux_device_class_cdc_acm_ioctl:
UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_STATE
Perform IOCTL Get Line State on the CDC-ACM interface
Prototype
Description
This function is called when an application needs to Get the Line State
parameters.
Parameters
Return Value
65
Example
/* Any error ? */
if (status == UX_SUCCESS)
{
/* Check state. */
if (line_state.ux_slave_class_cdc_acm_parameter_rts == UX_TRUE)
/* State is ON. */
status = tx_demo_thread_slave_cdc_acm_response("RTS ON", 6);
else
/* State is OFF. */
status = tx_demo_thread_slave_cdc_acm_response("RTS OFF", 7);
}
66
ux_device_class_cdc_acm_ioctl:
UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_STATE
Perform IOCTL Set Line State on the CDC-ACM interface
Prototype
Description
This function is called when an application needs to Get the Line State
parameters
Parameters
} UX_SLAVE_CLASS_CDC_ACM_LINE_STATE_PARAMETER;
Return Value
Example
/* This is to set RTS state. */
line_state.ux_slave_class_cdc_acm_parameter_rts = UX_TRUE;
status = _ux_device_class_cdc_acm_ioctl(cdc_acm_slave,
UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_STATE, &line_state);
67
ux_device_class_cdc_acm_ioctl:
UX_SLAVE_CLASS_CDC_ACM_IOCTL_ABORT_PIPE
Perform IOCTL ABORT PIPE on the CDC-ACM interface
Prototype
Description
This function is called when an application needs to abort a pipe. For example, to
abort an ongoing write, UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_XMIT
should be passed as the parameter.
Parameters
Return Value
Example
/* This is to abort the Xmit pipe. */
status = _ux_device_class_cdc_acm_ioctl(cdc_acm_slave,
UX_SLAVE_CLASS_CDC_ACM_IOCTL_ABORT_PIPE,
UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_XMIT);
68
ux_device_class_cdc_acm_ioctl:
UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_STA
RT
Perform IOCTL Transmission Start on the CDC-ACM interface
Prototype
Description
Parameters
UINT (*ux_device_class_cdc_acm_parameter_read_callback)(struct
UX_SLAVE_CLASS_CDC_ACM_STRUCT *cdc_acm, UINT status, UCHAR *data_pointer,
ULONG length);
} UX_SLAVE_CLASS_CDC_ACM_CALLBACK_PARAMETER;
Return Value
69
Example
70
ux_device_class_cdc_acm_ioctl:
UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_STO
P
Perform IOCTL Transmission Stop on the CDC-ACM interface
Prototype
Description
This function is called when an application wants to stop using transmission with
callback.
Parameters
Return Value
Example
71
ux_device_class_cdc_acm_read
Read from CDC-ACM pipe
Prototype
Description
This function is called when an application needs to read from the OUT data pipe
(OUT from the host, IN from the device). It is blocking.
Parameters
Return Value
Example
if(status != UX_SUCCESS)
return;
72
ux_device_class_cdc_acm_write
Write to a CDC-ACM pipe
Prototype
Description
This function is called when an application needs to write to the IN data pipe (IN
from the host, OUT from the device). It is blocking.
Parameters
Return Value
Example
if(status != UX_SUCCESS)
return;
73
ux_device_class_cdc_acm_write_with_callback
Writing to a CDC-ACM pipe with callback
Prototype
UINT ux_device_class_cdc_acm_write_with_callback(UX_SLAVE_CLASS_CDC_ACM
*cdc_acm,UCHAR *buffer, ULONG requested_length)
Description
This function is called when an application needs to write to the IN data pipe (IN
from the host, OUT from the device). This function is non-blocking and the
completion will be done through a callback set in
UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START.
Parameters
Return Value
Example
if(status != UX_SUCCESS)
return;
74
USB Device CDC-ECM Class
The USB device CDC-ECM class allows for a USB host system to communicate with
the device as a ethernet device. This class is based on the USB standard and is a
subset of the CDC standard.
75
/* First alternate setting Endpoint 1 descriptor 7 bytes */
0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00,
The CDC-ECM class uses a very similar device descriptor approach to the CDC-ACM
and also requires an IAD descriptor. See the CDC-ACM class for definition.
In addition to the regular device framework, the CDC-ECM requires special string
descriptors. An example is given below:
The MAC address string descriptor is used by the CDC-ECM class to reply to the host
queries as to what MAC address the device is answering to at the TCP/IP protocol. It
can be set to the device choice but must be defined here.
76
cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_local_node_id[3] =
0x41;
cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_local_node_id[4] =
0xb8;
cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_local_node_id[5] =
0x78;
The initialization of this class expects the same function callback for activation and
deactivation, although here as an exercise they are set to NULL so that no callback is
performed.
The next parameters are for the definition of the node IDs. 2 Nodes are necessary for
the CDC-ECM, a local node and a remote node. The local node specifies the MAC
address of the device, while the remote node specifies the MAC address of the host.
The remote node must be the same one as the one declared in the device framework
string descriptor.
The CDC-ECM class has built-in APIs for transferring data both ways but they are
hidden to the application as the user application will communicate with the USB
Ethernet device through NetX.
The USBX CDC-ECM class is closely tied to ExpressLogic NetX Network stack.
An application using both NetX and USBX CDC-ECM class will activate the NetX
network stack in its usual way but in addition needs to activate the USB network stack
as follows:
77
The USB network stack needs to be activated only once and is not specific to CDC-
ECM but is required by any USB class that requires NetX services.
The CDC-ECM class will be recognized by MAC OS and Linux hosts. But there is no
driver supplied by Microsoft Windows to recognize CDC-ECM natively. Some
commercial products do exist for Windows platforms and they supply their own .inf file.
This file will need to be modified the same way as the CDC-ACM inf template to match
the PID/VID of the USB network device.
78
USB Device HID Class
The USB device HID class allows for a USB host system to connect to a HID device
with specific HID client capabilities.
USBX HID device class is relatively simple compared to the host side. It is closely tied
to the behavior of the device and its HID descriptor.
Any HID client requires first to define a HID device framework as the example below:
UCHAR device_framework_full_speed[] = {
/* Device descriptor */
0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08,
0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01,
/* Configuration descriptor */
0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0, 0x32,
/* Interface descriptor */
0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00,
/* HID descriptor */
0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, 0x3f, 0x00,
};
The HID framework contains an interface descriptor that describes the HID class and
the HID device subclass. The HID interface can be a standalone class or part of a
composite device.
Currently, the USBX HID class does not support multiple report IDs, as most
applications only require one ID (ID zero). If multiple report IDs is a feature you are
interested in, please contact us.
The initialization of the HID class is as follow, using a USB keyboard as an example:
/* Initialize the device hid class. The class is connected with interface
0 */
79
status =
ux_device_stack_class_register(_ux_system_slave_class_hid_name,
ux_device_class_hid_entry, 1,0,
(VOID *)&hid_parameter);
if (status!=UX_SUCCESS)
return;
The application needs to pass to the HID class a HID report descriptor and its length.
The report descriptor is a collection of items that describe the device. For more
information on the HID grammar refer to the HID USB class specification.
In addition to the report descriptor, the application passes a call back when a HID event
happens.
The USBX HID class supports the following standard HID commands from the host:
The Get and Set report are the most commonly used commands by HID to transfer data
back and forth between the host and the device. Most commonly the host sends data on
the control endpoint but can receive data either on the interrupt endpoint or by issuing a
GET_REPORT command to fetch the data on the control endpoint.
The HID class can send data back to the host on the interrupt endpoint by using the
ux_device_class_hid_event_set function.
80
ux_device_class_hid_event_set
Setting an event to the HID class
Prototype
Description
This function is called when an application needs to send a HID event back to the
host. The function is not blocking, it merely puts the report into a circular queue
and returns to the application.
Parameters
Return Value
Example
/* The 6 next bytes are keys. We only have one key here. */
hid_event.ux_device_class_hid_event_buffer[2] = key;
The callback defined at the initialization of the HID class performs the opposite of
sending an event. It gets as input the event sent by the host. The prototype of the
callback is as follows:
81
hid_callback
Getting an event from the HID class
Prototype
UINT hid_callback(UX_SLAVE_CLASS_HID *hid,
UX_SLAVE_CLASS_HID_EVENT *hid_event)
Description
This function is called when the host sends a HID report to the application.
Parameters
Example
The following example shows how to interpret an event for a HID keyboard:
else
82
Index
API interface descriptor, 21, 22, 38, 57, 75,
USB device class, 21 79
USB device stack, 21 LUN, 13, 18, 51, 55
bulk in, 22, 38 memory insufficient, 37
bulk out, 22, 38 NetX, 8, 77, 78
callback, 52, 58, 76, 77, 79, 81, 82 OTG, 7, 8
CDC-ACM class, 57, 58, 59, 76 pipe, 60, 62, 63, 65, 67, 68, 69, 71, 72,
CDC-ECM class, 75 73, 74
class container, 28 power management, 8
class instance, 8, 60, 62, 63, 65, 67, 68, queue, 81
69, 71, 72, 73, 74, 81, 82 SCSI logical unit, 14
Class layer, 7 slave, 18, 29, 30, 37, 45, 46, 51, 52, 55,
configuration, 8, 13, 28, 31, 32, 33 56, 58, 76, 77, 80
configuration descriptor, 21, 22, 38, 79 stack layer, 7
Controller layer, 7 target, 10, 11, 12, 13, 19
device descriptor, 21, 22, 38, 57, 75, 79 ThreadX, 6, 8, 10, 11, 12, 13, 21
device framework, 21, 22, 23, 39 timer tick, 13
device side, 7, 10, 16, 21, 33 TraceX, 8
endpoint descriptor, 21, 22, 38, 75, 79 UNICODE, 23
FileX, 8, 12 USB device, 9, 17, 20, 21, 24, 51, 57,
functional descriptor, 58 75, 79
handle, 24 USB device controller, 17
HID class, 79, 80, 81, 82 USB device stack, 20, 21
host controller, 13 USB IF, 58
host side, 7, 21, 58, 79 USB protocol, 7, 9
host stack, 16 USBX thread, 13
initialization, 11, 16, 17, 21, 24, 40, 55, VBUS, 17, 20, 24, 34
58, 76, 77, 79, 81 version_id, 19
83