From ddf28ed046ad2075b667ab53e1ae81ab891a67d7 Mon Sep 17 00:00:00 2001 From: Mohamed AYED <81168645+ayedm1@users.noreply.github.com> Date: Tue, 21 Jan 2025 22:27:00 +0100 Subject: [PATCH] Update usbx device stack --- rtos-docs/usbx/usbx-device-stack-1.md | 2 +- rtos-docs/usbx/usbx-device-stack-2.md | 164 ++-- rtos-docs/usbx/usbx-device-stack-3.md | 36 +- rtos-docs/usbx/usbx-device-stack-4.md | 247 ++++- rtos-docs/usbx/usbx-device-stack-5.md | 918 ++++++++++++++---- rtos-docs/usbx/usbx-device-stack-about.md | 16 +- .../usbx/usbx-device-stack-supplemental-1.md | 12 +- .../usbx/usbx-device-stack-supplemental-2.md | 682 ++++++++++--- .../usbx/usbx-device-stack-supplemental-4.md | 91 +- .../usbx/usbx-device-stack-supplemental-5.md | 25 +- .../usbx/usbx-device-stack-supplemental-6.md | 459 +++++++++ .../usbx/usbx-device-stack-supplemental-7.md | 303 ++++++ 12 files changed, 2391 insertions(+), 564 deletions(-) create mode 100644 rtos-docs/usbx/usbx-device-stack-supplemental-6.md create mode 100644 rtos-docs/usbx/usbx-device-stack-supplemental-7.md diff --git a/rtos-docs/usbx/usbx-device-stack-1.md b/rtos-docs/usbx/usbx-device-stack-1.md index 2716101..704fd1c 100644 --- a/rtos-docs/usbx/usbx-device-stack-1.md +++ b/rtos-docs/usbx/usbx-device-stack-1.md @@ -29,7 +29,7 @@ The relationship between the USB layers is as follows: - Responsive technical support - Multiple class support - Multiple class instances -- Integration of classes with ThreadX, FileX, and NetX Duo +- Integration of classes with ThreadX, FileX and NetX Duo - Support for USB devices with multiple configurations - Support for USB composite devices - Support for USB power management diff --git a/rtos-docs/usbx/usbx-device-stack-2.md b/rtos-docs/usbx/usbx-device-stack-2.md index 80938b6..a12d490 100644 --- a/rtos-docs/usbx/usbx-device-stack-2.md +++ b/rtos-docs/usbx/usbx-device-stack-2.md @@ -36,7 +36,6 @@ The following is a list of several important files in the repository. * ***ux_api.h***: This C header file contains all system equates, data structures, and service prototypes. * ***ux_port.h***: This C header file contains all development-tool-specific data definitions and structures. -* ***ux.lib***: This is the binary version of the USBX C library. It is distributed with the standard package. * ***demo_usbx.c***: The C file containing a simple USBX demo All filenames are in lower-case. This naming convention makes it easier to convert the commands to Unix development platforms. @@ -55,13 +54,23 @@ You will also find instructions for building the USBX library on the front page The following general instructions apply to virtually any installation: +with RTOS: + 1. 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. -1. Add a call to ***ux_system_initialize*** at or near the beginning of ***tx_application_define***. This is where the USBX resources are initialized. -1. Add a call to ***ux_device_stack_initialize*.** -1. Add one or more calls to initialize the required USBX classes (either host and/or devices classes) -1. Add one or more calls to initialize the device controller available in the system. -1. 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.| -1. Compile application source code and link with the USBX and ThreadX run time libraries (FileX and/or NetX Duo 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! +2. Add a call to ***ux_system_initialize*** at or near the beginning of ***tx_application_define***. This is where the USBX resources are initialized. +3. Add a call to ***ux_device_stack_initialize*.** +4. Add one or more calls to initialize the required USBX classes (either host and/or devices classes) +5. Add one or more calls to initialize the device controller available in the system. +6. 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.| +7. Compile application source code and link with the USBX and ThreadX run time libraries (FileX and/or NetX Duo 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! + +with Standalone (without RTOS): +1. All USBX names are unique and will not interfere with the previous USBX installation. +2. Add a call to ***ux_system_initialize*** This is where the USBX resources are initialized. +3. Add a call to ***ux_device_stack_initialize*.** +4. Add one or more calls to initialize the required USBX classes (either host and/or devices classes) +5. Add one or more calls to initialize the device controller available in the system. +6. Add a call to ***ux_system_tasks_run*.** in main function while(1). ## Configuration Options @@ -69,45 +78,52 @@ There are several configuration options for building the USBX library. All optio The list below details each configuration option. -| Configuration Option | Description | -| --- | --- | -| **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 bytes 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** | 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) that is, 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 maximum length in bytes of a HID report. | -| **UX_DEVICE_CLASS_HID_MAX_EVENTS_QUEUE** | This value represents 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. | -| **UX_DEVICE_BIDIRECTIONAL_ENDPOINT_SUPPORT** | If defined, the device side enables bi-directional-endpoints support, e.g., endpoints addressed 0x01 and 0x81. Otherwise (the default case), endpoint number must be unique in same configuration. Note the feature must be used with compatible DCD and peripheral. | +| Configuration Option | Description | +| ----------------------------------------------- | ----------- | +| **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 bytes or 2048 bytes depending on the processor used and the host controller. | +| **UX_THREAD_PRIORITY_CLASS** | This is the ThreadX priority value for the standard USBX threads. | +| **UX_THREAD_PRIORITY_DCD** | This is the ThreadX priority value for the device controller thread. | +| **UX_ALIGN_MIN** | This value represents minimal allocated memory alignment in number of bytes. The default is UX_ALIGN_8 (0x07) to align allocated memory to 8 bytes. | +| **UX_ENFORCE_SAFE_ALIGNMENT** | This value forces the memory allocation scheme to enforce alignment of memory with the UX_SAFE_ALIGN field. | +| **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 value is the maximum number of classes in the device stack that can be loaded by USBX. | +| **UX_MAX_SLAVE_INTERFACES** | This value is the maximum number of interfaces in the device framework. | +| **UX_DEVICE_ENDPOINT_BUFFER_OWNER** | This value represents the endpoint buffer owner. 0 The default, endpoint buffer is managed by core stack. Each endpoint takes UX_SLAVE_REQUEST_DATA_MAX_LENGTH bytes, 1 Endpoint buffer managed by classes. In this case not all endpoints consume UX_SLAVE_REQUEST_DATA_MAX_LENGTH bytes | +| **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 constrained environments. | +| **UX_SLAVE_REQUEST_DATA_MAX_LENGTH** | This value represents the maximum number of bytes that can be received or transmitted on any endpoint. This value cannot be less than the maximum packet size of any endpoint. The default is 4096 bytes but can be reduced in memory constrained environments. For cd-rom support in the storage class, this value cannot be less than 2048. | +| **UX_DEVICE_BIDIRECTIONAL_ENDPOINT_SUPPORT** | If defined, the device side enables bi-directional-endpoints support, e.g., endpoints addressed 0x01 and 0x81. Otherwise (the default case), endpoint number must be unique in same configuration. Note the feature must be used with compatible DCD and peripheral. | +| **UX_DEVICE_ALTERNATE_SETTING_SUPPORT_DISABLE** | This macro disables interface alternate setting support. | +| **UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE** | This macro disables device framework scan, where max number of endpoints (except EP0) and max number of interfaces are calculated at runtime, as a base to allocate memory for interfaces and endpoints structures and their buffers. Undefined, the following two macros must be defined to initialize memory structures. | +| **UX_MAX_DEVICE_ENDPOINTS** | This value represents max number of endpoints (except EP0) activated at the same time. Works if UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE is defined. | +| **UX_MAX_DEVICE_INTERFACES** | This value represents max number of interfaces activated at the same time. Works if UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE is defined. | +| **UX_NAME_REFERENCED_BY_POINTER** | Defined, the _name in structs are referenced by pointer instead of by contents. By default the _name is an array of string that saves characters, the contents are compared to confirm match. If referenced by pointer the address pointer to const string is saved, the pointers are compared to confirm match. | +| **UX_DEVICE_SIDE_ONLY** | This value will only enable the device side of USBX. | +| **UX_STANDALONE** | This macro will enable the standalone mode of USBX. | +| **UX_DEBUG_LOG_SIZE** | This value represents the size of the log pool. | +| **UX_ENABLE_ASSERT** | This enables the assert checks inside USBX. | +| **UX_ENABLE_ERROR_CHECKING** | This option enables the basic USBX error checking. This define is typically used when the application is debugging and removed after the application is fully debugged. | ## Source Code Tree The USBX files are provided in several directories. -![Source Code Tree](media/usbx-device-stack/source-code-tree.png) +![Source Code Tree](./media/usbx-device-stack/source-code-tree.png) In order to make the files recognizable by their names, the following convention has been adopted: | File Suffix Name | File description | | ----------------- | ----------------------------------------- | -| ux_host_stack | usbx host stack core files | -| ux_host_class | usbx host stack classes files | -| ux_hcd | usbx host stack controller driver files | -| ux_device_stack | usbx device stack core files | -| ux_device_class | usbx device stack classes files | -| ux_dcd | usbx device stack controller driver files | -| ux_otg | usbx otg controller driver related files | -| ux_pictbridge | usbx pictbridge files | -| ux_utility | usbx utility functions | -| demo_usbx | demonstration files for USBX | +| ux_host_stack | usbx host stack core files | +| ux_host_class | usbx host stack classes files | +| ux_hcd | usbx host stack controller driver files | +| ux_device_stack | usbx device stack core files | +| ux_device_class | usbx device stack classes files | +| ux_dcd | usbx device stack controller driver files | +| ux_otg | usbx otg controller driver related files | +| ux_pictbridge | usbx pictbridge files | +| ux_utility | usbx utility functions | +| demo_usbx | demonstration files for USBX | ## Initialization of USBX resources @@ -117,26 +133,24 @@ The following function initializes USBX memory resources with 128 K of regular m ```c /* Initialize USBX Memory */ -ux_system_initialize(memory_pointer,(128*1024),UX_NULL,0); +ux_system_initialize(memory_pointer, (128*1024), UX_NULL, 0); ``` The prototype for the ux_system_initialize is as follows: ```c UINT ux_system_initialize(VOID *regular_memory_pool_start, - ULONG regular_memory_size, - VOID *cache_safe_memory_pool_start, - ULONG cache_safe_memory_size); + ULONG regular_memory_size, + VOID *cache_safe_memory_pool_start, + ULONG cache_safe_memory_size); ``` -Input parameters: +Where: -| Parameter | Description | -| ---------------------------------- | --------------------------------------- | -| VOID *regular_memory_pool_start | Beginning of the regular memory pool | -| ULONG regular_memory_size | Size of the regular memory pool | -| VOID *cache_safe_memory_pool_start | Beginning of the cache safe memory pool | -| ULONG cache_safe_memory_size | Size of the cache safe memory pool | +- *regular_memory_pool_start*: Beginning of the regular memory pool. +- *regular_memory_size*: Size of the regular memory pool. +- *cache_safe_memory_pool_start*: Beginning of the cache safe memory pool. +- *cache_safe_memory_size*: Size of the cache safe memory pool. 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. @@ -147,8 +161,7 @@ In a system where the regular memory is not cache safe and a controller requires USBX can be terminated by releasing its resources. Prior to terminating usbx, all classes and controller resources need to be terminated properly. The following function uninitializes USBX memory resources: ```c -/* Unitialize USBX Resources */ - +/* Uninitialize USBX Resources */ ux_system_uninitialize(); ``` @@ -158,6 +171,27 @@ The prototype for the ux_system_initialize is as follows: UINT ux_system_uninitialize(VOID); ``` +## Task Run of USBX resources + +This function runs USB system tasks, including possible tasks for host, device and OTG. + +```c + + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); +#endif + } + +``` + +The prototype for the ux_system_tasks_run is as follows: + +```c +UINT ux_system_tasks_run(VOID); +``` + ## Definition of USB Device Controller Only one USB device controller can be defined at any time to operate in device mode. The application initialization file should contain this definition. The following line performs the definition of a generic usb controller: @@ -169,17 +203,14 @@ ux_dcd_controller_initialize(0x7BB00000, 0, 0xB7A00000); The USB device initialization has the following prototype: ```c -UINT ux_dcd_controller_initialize(ULONG dcd_io, - ULONG dcd_irq, ULONG dcd_vbus_address); +UINT ux_dcd_controller_initialize(ULONG dcd_io, ULONG dcd_irq, ULONG dcd_vbus_address); ``` -with the following parameters: +Where: -| Parameter | Description | -| ------------------------ | -------------------------------- | -| ULONG dcd_io | Address of the controller IO | -| ULONG dcd_irq | Interrupt used by the controller | -| ULONG dcd_vbus_address | Address of the VBUS GPIO | +- *dcd_io*: Address of the controller IO. +- *dcd_irq*: Interrupt used by the controller. +- *dcd_vbus_address*: Address of the VBUS GPIO . The following example is the initialization of USBX in device mode with the storage device class and a generic controller: @@ -189,11 +220,11 @@ The following example is the initialization of USBX in device mode with the stor 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); +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); /* If status equals UX_SUCCESS, installation was successful. */ @@ -205,13 +236,12 @@ storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage 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[0].ux_slave_class_storage_media_read = demo_thread_flash_media_read; +storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_flash_media_write; +storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = 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); +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); /* Register the device controllers available in this system */ status = ux_dcd_controller_initialize(0x7BB00000, 0, 0xB7A00000); diff --git a/rtos-docs/usbx/usbx-device-stack-3.md b/rtos-docs/usbx/usbx-device-stack-3.md index 9f99ff8..def36e4 100644 --- a/rtos-docs/usbx/usbx-device-stack-3.md +++ b/rtos-docs/usbx/usbx-device-stack-3.md @@ -1,5 +1,4 @@ --- -# Mandatory fields. title: Chapter 3 - Functional Components of USBX Device Stack description: This chapter contains a description of the high performance USBX embedded USB device stack from a functional perspective. --- @@ -11,19 +10,18 @@ This chapter contains a description of the high performance USBX embedded USB de ## Execution Overview USBX for the device is composed of several components. - -- Initialization -- Application interface calls -- USB Device Classes -- USB Device Stack -- Device controller -- VBUS manager +- [Initialization](#initialization) +- [Application interface calls](#application_interface_calls) +- [USB Device Classes](#usb_device_classes) +- [USB Device Stack](#usb_device_stack) +- [USB Device controller](#usb_device_controller) +- [VBUS manager](#vbus_manager) The following diagram illustrates the USBX Device stack. -![USBX Device Stack](media/usbx-device-stack/usbx-device-stack.png) +![USBX Device Stack](./media/usbx-device-stack/usbx-device-stack.png) -### Initialization +## initialization In order to activate USBX, the function ***ux_system_initialize*** must be called. This function initializes the memory resources of USBX. @@ -31,7 +29,7 @@ In order to activate USBX device facilities, the function ***ux_device_stack_ini 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. -### Application Interface Calls +## application_interface_calls There are two levels of APIs in USBX. @@ -40,30 +38,30 @@ There are two levels of APIs in USBX. 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. -### USB Device Classes +## usb_device_classes The Class APIs are very specific to each USB class. Most of the common APIs for USB classes provided services such as opening/closing a device and reading from or writing to a device. -#### Storage Class +### Storage Class The storage class is in charge of answering storage class specific control requests and handling storage class protocol commands. Refer to USB Device Storage Class in Chapter 5 for more information. -#### CDC Class +### CDC Class The CDC class is in charge of answering CDC class specific control requests and offering ways to communicate with host through data pipes. Following functionalities are supported now: * CDC-ACM: communicate with host as a serial device * CDC-ECM: communicate with host as an ethernet device Refer to USB Device CDC-ACM Class and USB Device CDC-ECM Class in Chapter 5 for more information. -#### HID Class +### HID Class The HID class is in charge of answering the HID class specific control requests and offering ways to communicate host with HID class specific reports. Refer to USB Device HID Class in Chapter 5 for more information. -#### Custom Class +### Custom Class For advanced developers, it's possible to create more customized class, to answering customized control requests and handling customized protocol on data pipes. Note such class may also require specific customization on host side, too. -## USB Device Stack +## usb_device_stack The device stack APIs are responsible for the registration of USBX device components such as classes and the device framework. ### Device Framework @@ -163,7 +161,7 @@ To support additional languages, simply add the language code double-byte defini *Developing International Software for Windows 95 and Windows NT, Nadine Kano, Eclipse Foundation Press, Redmond WA* -## Device controller +## usb_device_controller The device controller driver (DCD) interoperates USB Device Stack operations to hardware actions. Normally, a USBX application should not have to call device controller APIs, except initialization function. When the device controller initialization function is called, the bus is active and the stack will reply to bus reset and host enumeration commands through device controller driver. @@ -174,7 +172,7 @@ Here are some possible hardware which USB Device Stack can operate on: * Reneses chip with USB device controller * Other chip with USB device controller, etc. -## VBUS Manager +## 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. diff --git a/rtos-docs/usbx/usbx-device-stack-4.md b/rtos-docs/usbx/usbx-device-stack-4.md index d6a8948..8371d9e 100644 --- a/rtos-docs/usbx/usbx-device-stack-4.md +++ b/rtos-docs/usbx/usbx-device-stack-4.md @@ -5,7 +5,30 @@ description: Learn about the USBX Device Services. # Description of USBX Device Services -### ux_device_stack_alternate_setting_get +This chapter contains a description of USBX device stack services in alphabetic order. + +The USBX device stack API functions available to the application are as follows. +- [ux_device_stack_alternate_setting_get](#ux_device_stack_alternate_setting_get) +- [ux_device_stack_alternate_setting_set](#ux_device_stack_alternate_setting_set) +- [ux_device_stack_class_register](#ux_device_stack_class_register) +- [ux_device_stack_class_unregister](#ux_device_stack_class_unregister) +- [ux_device_stack_configuration_get](#ux_device_stack_configuration_get) +- [ux_device_stack_configuration_set](#ux_device_stack_configuration_set) +- [ux_device_stack_descriptor_send](#ux_device_stack_descriptor_send) +- [ux_device_stack_disconnect](#ux_device_stack_disconnect) +- [ux_device_stack_endpoint_stall](#ux_device_stack_endpoint_stall) +- [ux_device_stack_host_wakeup](#ux_device_stack_host_wakeup) +- [ux_device_stack_initialize](#ux_device_stack_initialize) +- [ux_device_stack_interface_delete](#ux_device_stack_interface_delete) +- [ux_device_stack_interface_get](#ux_device_stack_interface_get) +- [ux_device_stack_interface_set](#ux_device_stack_interface_set) +- [ux_device_stack_interface_start](#ux_device_stack_interface_start) +- [ux_device_stack_transfer_request](#ux_device_stack_transfer_request) +- [ux_device_stack_transfer_abort](#ux_device_stack_transfer_abort) +- [ux_device_stack_uninitialize](#ux_device_stack_uninitialize) +- [ux_device_stack_microsoft_extension_register](#ux_device_stack_microsoft_extension_register) + +## ux_device_stack_alternate_setting_get Get current alternate setting for an interface value @@ -21,7 +44,7 @@ This function is used by the USB host to obtain the current alternate setting fo ### Input Parameter -- *Interface_value*: Interface value for which the current alternate setting is queried +- *interface_value*: Interface value for which the current alternate setting is queried ### Return Values @@ -40,7 +63,7 @@ status = ux_device_stack_alternate_setting_get(interface_value); /* If status equals UX_SUCCESS, the operation was successful. */ ``` -### ux_device_stack_alternate_setting_set +## ux_device_stack_alternate_setting_set Set current alternate setting for an interface value @@ -76,7 +99,6 @@ The function starts status stage of the control transfer in background, and retu ```c ULONG interface_value; - ULONG alternate_setting_value; /* The following example illustrates this service. */ @@ -85,7 +107,7 @@ status = ux_device_stack_alternate_setting_set(interface_value, alternate_settin /* If status equals UX_SUCCESS, the operation was successful. */ ``` -### ux_device_stack_class_register +## ux_device_stack_class_register Register a new USB device class @@ -130,11 +152,10 @@ UINT status; /* The following example illustrates this service. */ /* Initialize the device storage class. The class is connected with interface 1 */ -status = ux_device_stack_class_register(_ux_system_slave_class_storage_name ux_device_class_storage_entry, - 1, 1, (VOID *)¶meter); +status = ux_device_stack_class_register(_ux_system_slave_class_storage_name ux_device_class_storage_entry, 1, 1, (VOID *)¶meter); ``` -### ux_device_stack_class_unregister +## ux_device_stack_class_unregister Unregister a USB device class @@ -176,7 +197,7 @@ status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, u /* If status equals UX_SUCCESS, the operation was successful. */ ``` -### ux_device_stack_configuration_get +## ux_device_stack_configuration_get Get the current configuration @@ -209,7 +230,7 @@ status = ux_device_stack_configuration_get(); /* If status equals UX_SUCCESS, the operation was successful. */ ``` -### ux_device_stack_configuration_set +## ux_device_stack_configuration_set Set the current configuration @@ -245,7 +266,7 @@ status = ux_device_stack_configuration_set(configuration_value); /* If status equals UX_SUCCESS, the operation was successful. */ ``` -### ux_device_stack_descriptor_send +## ux_device_stack_descriptor_send Send a descriptor to the host @@ -334,7 +355,7 @@ Request endpoint Stall condition ### Prototype ```c -UINT ux_device_stack_endpoint_stall(UX_SLAVE_ENDPOINT*endpoint); +UINT ux_device_stack_endpoint_stall(UX_SLAVE_ENDPOINT *endpoint); ``` ### Description @@ -363,7 +384,7 @@ status = ux_device_stack_endpoint_stall(endpoint); /* If status equals UX_SUCCESS, the operation was successful. */ ``` -### ux_device_stack_host_wakeup +## ux_device_stack_host_wakeup Wake up the host @@ -400,7 +421,7 @@ status = ux_device_stack_host_wakeup(); /* If status equals UX_SUCCESS, the operation was successful. */ ``` -### ux_device_stack_initialize +## ux_device_stack_initialize Initialize USB device stack @@ -415,8 +436,8 @@ UINT ux_device_stack_initialize( UCHAR *string_framework, ULONG string_framework_length, UCHAR *language_id_framework, - ULONG language_id_framework_length), - UINT (*ux_system_slave_change_function)(ULONG))); + ULONG language_id_framework_length, + UINT (*ux_system_slave_change_function)(ULONG)); ``` ### Description @@ -541,23 +562,23 @@ UINT status; /* The code below is required for installing the device portion of USBX. There is no call back for device status change in this example. */ -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); +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); /* If status equals UX_SUCCESS, initialization was successful. */ ``` -### ux_device_stack_interface_delete +## ux_device_stack_interface_delete Delete a stack interface ### Prototype ```c -UINT ux_device_stack_interface_delete(UX_SLAVE_INTERFACE*interface); +UINT ux_device_stack_interface_delete(UX_SLAVE_INTERFACE *ux_interface); ``` ### Description @@ -566,7 +587,7 @@ This function is called when an interface should be removed. An interface is eit ### Input Parameter -- *interface*: Pointer to the interface to remove. +- *ux_interface*: Pointer to the interface to remove. ### Return Value @@ -583,7 +604,7 @@ status = ux_device_stack_interface_delete(interface); /* If status equals UX_SUCCESS, the operation was successful. */ ``` -### ux_device_stack_interface_get +## ux_device_stack_interface_get Get the current interface value @@ -621,7 +642,7 @@ status = ux_device_stack_interface_get(interface_value); /* If status equals UX_SUCCESS, the operation was successful. */ ``` -### ux_device_stack_interface_set +## ux_device_stack_interface_set Change the alternate setting of the interface @@ -654,26 +675,25 @@ This function starts status stage of the control transfer in background, and ret ### Example ```c -UCHAR * device_framework +UCHAR *device_framework ULONG device_framework_length; ULONG alternate_setting_value; -UINT status; +UINT status; /* The following example illustrates this service. */ -status = ux_device_stack_interface_set(device_framework, - device_framework_length, alternate_setting_value); +status = ux_device_stack_interface_set(device_framework, device_framework_length, alternate_setting_value); /* If status equals UX_SUCCESS, the operation was successful. */ ``` -### ux_device_stack_interface_start +## ux_device_stack_interface_start Start search for a class to own an interface instance ### Prototype ```c -UINT ux_device_stack_interface_start(UX_SLAVE_INTERFACE*interface); +UINT ux_device_stack_interface_start(UX_SLAVE_INTERFACE *ux_interface); ``` ### Description @@ -686,7 +706,7 @@ This function is not blocking and returns immediately. ### Input Parameter -- *interface*: Pointer to the interface created. +- *ux_interface*: Pointer to the interface created. ### Return Values @@ -704,7 +724,7 @@ status = ux_device_stack_interface_start(interface); /* If status equals UX_SUCCESS, the operation was successful. */ ``` -### ux_device_stack_transfer_request +## ux_device_stack_transfer_request Request to transfer data to the host @@ -766,7 +786,7 @@ while(total_length) { } ``` -### ux_device_stack_transfer_abort +## ux_device_stack_transfer_abort Cancel a transfer request @@ -803,9 +823,9 @@ status = ux_device_stack_transfer_abort(transfer_request, UX_TRANSFER_BUS_RESET) /* If status equals UX_SUCCESS, the operation was successful. */ ``` -### ux_device_stack_uninitialize +## ux_device_stack_uninitialize -Unitialize stack +Uninitialize stack ### Prototype @@ -815,7 +835,7 @@ 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, and return immediately. This should be called after all classes have been unregistered via ux_device_stack_class_unregister. +This function is called when an application needs to uninitialize the USBX device stack – all device stack resources are freed, and return immediately. This should be called after all classes have been unregistered via ux_device_stack_class_unregister. ### Parameters @@ -824,3 +844,154 @@ None ### Return Value **UX_SUCCESS** (0x00) This operation was successful. + +## ux_device_stack_microsoft_extension_register + +Registers the Microsoft extensions + +### Prototype + +```c +UINT ux_device_stack_microsoft_extension_register( + ULONG vendor_request, + UINT (*vendor_request_function)(ULONG, ULONG, ULONG, ULONG, UCHAR *, ULONG *)) +``` + +### Description + +This function registers the Microsoft extensions to support vendor commands before the device is configured. + +### Parameters + +- *vendor_request*: Vendor Command. +- *vendor_request_function*: Vendor Command application Callback. + +### Return Value + +**UX_SUCCESS** (0x00) This operation was successful. + +### Example + +```c +#define UX_DEMO_VENDOR_REQUEST 0x54 + +/* MS extensions. */ +status = _ux_device_stack_microsoft_extension_register(UX_DEMO_VENDOR_REQUEST, pima_device_vendor_request); + + +UINT pima_device_vendor_request(ULONG request, ULONG request_value, ULONG request_index, ULONG request_length, + UCHAR *transfer_request_buffer, + ULONG *transfer_request_length) +{ +UINT status; +ULONG length; + + /* Do some sanity check. The request must be our vendor request. */ + if (request != UX_TEST_VENDOR_REQUEST) + + /* Do not proceed. */ + return(UX_ERROR); + + /* Check the wIndex value. Values can be : + 0x0001 : Genre + 0x0004 : Extended compatible ID + 0x0005 : Extended properties */ + switch (request_index) + { + + case 0x0001 : + + /* Not sure what this is for. Windows does not seem to request this. Drop it. */ + status = UX_ERROR; + break; + + case 0x0004 : + case 0x0005 : + + /* Length to return. */ + length = UX_MIN(0x28, request_length); + + /* Length check. */ + UX_ASSERT(*transfer_request_length >= length); + + /* At least length should be returned. */ + if (length < 4) + { + status = UX_ERROR; + break; + } + status = UX_SUCCESS; + + /* Return the length. */ + *transfer_request_length = length; + + /* Reset returned bytes. */ + ux_utility_memory_set(transfer_request_buffer, 0, length); + + /* Build the descriptor to be returned. This is not a composite descriptor. Single MTP. + First dword is length of the descriptor. */ + ux_utility_long_put(transfer_request_buffer, 0x0028); + length -= 4; + + /* Then the version. fixed to 0x0100. */ + if (length < 2) + break; + ux_utility_short_put(transfer_request_buffer + 4, 0x0100); + length -= 2; + + /* Then the descriptor ID. Fixed to 0x0004. */ + if (length < 2) + break; + ux_utility_short_put(transfer_request_buffer + 6, 0x0004); + length -= 2; + + /* Then the bcount field. Fixed to 0x0001. */ + if (length < 1) + break; + *(transfer_request_buffer + 8) = 0x01; + length -= 1; + + /* Reset the next 7 bytes. */ + if (length < 7) + break; + ux_utility_memory_set(transfer_request_buffer + 9, 0x00, 7); + length -= 7; + + /* Last byte of header is the interface number, here 0. */ + if (length < 1) + break; + *(transfer_request_buffer + 16) = 0x00; + length -= 1; + + /* First byte of descriptor is set to 1. */ + if (length < 1) + break; + *(transfer_request_buffer + 17) = 0x01; + length -= 1; + + /* Reset the next 8 + 8 + 6 bytes. */ + if (length < (8+8+6)) + break; + ux_utility_memory_set(transfer_request_buffer + 18, 0x00, (8 + 8 + 6)); + length -= 8+8+6; + + /* Set the compatible ID to MTP. */ + if (length < 3) + break; + ux_utility_memory_copy(transfer_request_buffer + 18, "MTP", 3); + length -= 3; + + /* We are done here. */ + status = UX_SUCCESS; + break; + + default : + status = UX_ERROR; + break; + + } + /* Return status to device stack. */ + return(status); +} + +``` diff --git a/rtos-docs/usbx/usbx-device-stack-5.md b/rtos-docs/usbx/usbx-device-stack-5.md index 8dfec88..29ad1cd 100644 --- a/rtos-docs/usbx/usbx-device-stack-5.md +++ b/rtos-docs/usbx/usbx-device-stack-5.md @@ -4,29 +4,32 @@ description: Learn about the USBX Device Class considerations. --- # Chapter 5 - USBX Device Class Considerations -## Device Class registration +- [Device Class Registration](#device_class_registration) +- [General Considerations For Bulk Transfer](#general_considerations_for_bulk_transfer) + +USB Device Classes : +- [USB Device Storage Class](#usb_device_storage_class) +- [USB Device CDC-ACM Class](#usb_device_cdc_acm_class) +- [USB Device CDC-ECM Class](#usb_device_cdc_ecm_class) +- [USB Device HID Class](#usb_device_hid_class) + +# 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. ```c /* Set the parameters for callback when insertion/extraction of a HID device. */ - -hid_parameter.ux_slave_class_hid_instance_activate = tx_demo_hid_instance_activate; - -hid_parameter.ux_slave_class_hid_instance_deactivate = tx_demo_hid_instance_deactivate; +hid_parameter.ux_slave_class_hid_instance_activate = demo_hid_instance_activate; +hid_parameter.ux_slave_class_hid_instance_deactivate = demo_hid_instance_deactivate; /* Initialize the hid class parameters for the device. */ hid_parameter.ux_device_class_hid_parameter_report_address = hid_device_report; - hid_parameter.ux_device_class_hid_parameter_report_length = HID_DEVICE_REPORT_LENGTH; - hid_parameter.ux_device_class_hid_parameter_report_id = UX_TRUE; -hid_parameter.ux_device_class_hid_parameter_callback = demo_thread_hid_callback; +hid_parameter.ux_device_class_hid_parameter_callback = demo_hid_callback; /* Initialize 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); +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 a instance of the class gets activated. The callback is then called by the device stack to inform the application that an instance was created. @@ -34,13 +37,13 @@ Each class can register, optionally, a callback function when a instance of the The application would have in its body the 2 functions for activation and deactivation, as shown in the following example. ```c -VOID tx_demo_hid_instance_activate(VOID *hid_instance) +VOID demo_hid_instance_activate(VOID *hid_instance) { /* Save the HID instance. */ hid_slave = (UX_SLAVE_CLASS_HID *) hid_instance; } -VOID tx_demo_hid_instance_deactivate(VOID *hid_instance) +VOID demo_hid_instance_deactivate(VOID *hid_instance) { /* Reset the HID instance. */ hid_slave = UX_NULL; @@ -49,7 +52,7 @@ VOID tx_demo_hid_instance_deactivate(VOID *hid_instance) It is not recommended to do anything within these functions but to memorize the instance of the class and synchronize with the rest of the application. -## General Considerations for Bulk Transfer +# general_considerations_for_bulk_transfer As per the USB 2.0 specification, an endpoint must always transmit data payloads with a data field less than or equal to the endpoint's reported wMaxPacketSize value. The size of a data packet is limited to bMaxPacketSize. Transfer can be completed with the following cases @@ -58,65 +61,58 @@ reported wMaxPacketSize value. The size of a data packet is limited to bMaxPacke Short packets and Zero Length Packets signify the end of a bulk data transfer. The above considerations apply to raw bulk data transfer APIs, e.g., ux_device_class_cdc_acm_read(). -## USB Device Storage Class +# 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. +- [Storage Class Initialize](#storage_class_initialize) +- [Storage Class Configuration Options](#storage_class_configuration_options) +- [Storage Class Multiple SCSI LUN](#storage_class_multiple_scsi_lun) +- [Storage Class Write Caching SCSI LUN](#storage_class_write_caching_scsi_lun) + 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. +## storage_class_initialize + 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. ```c -/* Initialize the storage class parameters to customize vendor strings. */ - -storage_parameter.ux_slave_class_storage_parameter_vendor_id - = demo_ux_system_slave_class_storage_vendor_id; +UX_SLAVE_CLASS_STORAGE_PARAMETER storage_parameter; -storage_parameter.ux_slave_class_storage_parameter_product_id - = demo_ux_system_slave_class_storage_product_id; +UCHAR demo_storage_vendor_id[] = "USBX VID"; +UCHAR demo_storage_product_id[] = "USBX Storage "; +UCHAR demo_storage_product_rev[] = "1010"; +UCHAR demo_storage_product_serial[] = "01234567890123456789"; -storage_parameter.ux_slave_class_storage_parameter_product_rev - = demo_ux_system_slave_class_storage_product_rev; +/* Initialize callbacks. */ +storage_parameter.ux_slave_class_storage_instance_activate = demo_storage_instance_activate; +storage_parameter.ux_slave_class_storage_instance_deactivate = demo_storage_instance_deactivate; -storage_parameter.ux_slave_class_storage_parameter_product_serial - = demo_ux_system_slave_class_storage_product_serial; +/* Initialize the storage class parameters to customize vendor strings. */ +storage_parameter.ux_slave_class_storage_parameter_vendor_id = demo_storage_vendor_id; +storage_parameter.ux_slave_class_storage_parameter_product_id = demo_storage_product_id; +storage_parameter.ux_slave_class_storage_parameter_product_rev = demo_storage_product_rev; +storage_parameter.ux_slave_class_storage_parameter_product_serial = demo_storage_product_serial; /* 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_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].ux_slave_class_storage_media_status - = tx_demo_thread_flash_media_status; - -/* A simple write caching support. - If this callback is assigned, host gets notification from caching page - that write caching is supported, and can send SYNCHRONIZE_CACHE to - flush cache. But caching options are not allowed to be changed. */ -storage_parameter.ux_slave_class_storage_parameter_lun[0]. -ux_slave_class_storage_media_flush = - tx_demo_thread_flash_media_flush; +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 = demo_storage_flash_media_read; +storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_storage_flash_media_write; +storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_storage_flash_media_status; +storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_storage_flash_media_flush; /* 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); +status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, 1, 0, (VOID *)&storage_parameter); + +if (status != UX_SUCCESS) + return; ``` 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 ThreadX string is used. @@ -234,10 +230,10 @@ UINT ux_slave_class_storage_media_notification( Where: -- *storage* is the instance of the storage class. -- *media_id* is not currently used. notification_class specifies the class of notification. -- *media_notification* should be set by the application to the buffer containing the response for the notification. -- *media_notification_length* should be set by the application to contain the length of the response buffer. +- *storage*: is the instance of the storage class. +- *media_id*: is not currently used. notification_class specifies the class of notification. +- *media_notification*: should be set by the application to the buffer containing the response for the notification. +- *media_notification_length*: should be set by the application to contain the length of the response buffer. The return value indicates whether or not the command succeeded – should be either **UX_SUCCESS** or **UX_ERROR**. @@ -258,58 +254,63 @@ UINT ux_slave_class_storage_media_flush( Where: -- *storage* is the instance of the storage class. -- *lun* parameter specifies which LUN the command is directed to. -- *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. +- *storage*: is the instance of the storage class. +- *lun*: parameter specifies which LUN the command is directed to. +- *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**. -### Multiple SCSI LUN +## storage_class_configuration_options + +There are several configuration options for building USB Device Storage Class. All options are located in the ***ux_user.h***. + +The list below details each configuration option. + +| Configuration Option | Description | +| ----------------------------------------------- | ----------- | +| **UX_MAX_SLAVE_LUN** | This value represents the current number of SCSI logical units represented in the device storage class driver. | +| **UX_SLAVE_CLASS_STORAGE_INCLUDE_MMC** | This value includes code to handle storage Multi-Media Commands (MMC). E.g., DVD-ROM. | + +## storage_class_multiple_scsi_lun The USBX device storage class supports multiple LUNs. It is therefore possible to create a storage device that acts as a CD-ROM and a Flash disk at the same time. In such a case, the initialization would be slightly different. Here is an example for a Flash Disk and CD-ROM: ```c +UX_SLAVE_CLASS_STORAGE_PARAMETER storage_parameter; + /* Store the number of LUN in this device storage instance. */ storage_parameter.ux_slave_class_storage_parameter_number_lun = 2; /* 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 = 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[0].ux_slave_class_storage_media_read = demo_storage_flash_media_read; +storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_storage_flash_media_write; +storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_storage_flash_media_status; /* Initialize the storage class LUN parameters for reading/writing to the CD-ROM. */ - 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].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 = demo_storage_cdrom_media_read; +storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_storage_cdrom_media_write; +storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_storage_cdrom_media_status; -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, 1, 0, (VOID *)&storage_parameter); -/* 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); +if (status != UX_SUCCESS) + return; ``` -### Write Caching SCSI LUN +> **Note:** In case multiple LUNs *UX_MAX_SLAVE_LUN* should be defined in *ux_user.h* with numbers of supported lun. + +## storage_class_write_caching_scsi_lun The USBX device storage class supports write caching on LUNs. @@ -318,17 +319,23 @@ The application needs to pass a callback function pointer to allow the storage c The flush callback function has the following prototype: ```c -UINT media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); +UINT media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); ``` The calling parameter *number_blocks* and *lba* specifies the area on LUN that needs flush. -Note that when the callback is not assigned, host is not notified for write caching support, so there is no option for it. When the callback is assigned, host is notified for write caching enabled, but not allowed to change this setting. +> **Note:** when the callback is not assigned, host is not notified for write caching support, so there is no option for it. When the callback is assigned, host is notified for write caching enabled, but not allowed to change this setting. -## USB Device CDC-ACM Class +# 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. +- [CDC-ACM Class Initialize](#cdc_acm_class_initialize) +- [CDC-ACM Class Configuration Options](#cdc_acm_class_configuration_options) +- [CDC-ACM Class APIs](#cdc_acm_class_apis) + +## cdc_acm_class_initialize + A CDC-ACM compliant device framework needs to be declared by the device stack. An example is found here below. ```c @@ -394,17 +401,18 @@ The CDC-ACM class also uses a union functional descriptor which performs the sam The initialization of the CDC-ACM class expects the following parameters. ```c -/* Set the parameters for callback when insertion/extraction of a CDC device. */ +UX_SLAVE_CLASS_CDC_ACM_PARAMETER cdc_acm_parameter; -parameter.ux_slave_class_cdc_acm_instance_activate = tx_demo_cdc_instance_activate; - -parameter.ux_slave_class_cdc_acm_instance_deactivate = tx_demo_cdc_instance_deactivate; - -parameter.ux_slave_class_cdc_acm_parameter_change = tx_demo_cdc_instance_parameter_change; +/* Set the parameters for callback when insertion/extraction of a CDC device. */ +cdc_acm_parameter.ux_slave_class_cdc_acm_instance_activate = demo_cdc_instance_activate; +cdc_acm_parameter.ux_slave_class_cdc_acm_instance_deactivate = demo_cdc_instance_deactivate; +cdc_acm_parameter.ux_slave_class_cdc_acm_parameter_change = demo_cdc_instance_parameter_change; /* 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); +status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, 1, 0, (VOID *)&cdc_acm_parameter); + +if (status != UX_SUCCESS) + return; ``` The 2 parameters defined are callback pointers into the user applications that will be called when the stack activates or deactivate this class. @@ -425,8 +433,27 @@ In the device framework of the CDC-ACM device, the PID/VID are stored in the dev 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. +## cdc_acm_class_configuration_options + +There are several configuration options for building USB Device CDC-ACM Class. All options are located in the ***ux_user.h***. + +| Configuration Option | Description | +| ------------------------------------------------- | ----------- | +| **UX_DEVICE_CLASS_CDC_ACM_TRANSMISSION_DISABLE** | This macro disables CDC ACM non-blocking transmission support. | +| **UX_DEVICE_CLASS_CDC_ACM_WRITE_AUTO_ZLP** | class _write is pending ZLP automatically (complete transfer) after buffer is sent. | +| **UX_DEVICE_CLASS_CDC_ACM_ZERO_COPY** | This macro enables device CDC ACM zero copy for bulk in/out endpoints (write/read). Enabled, the endpoint buffer is not allocated in class, application must provide the buffer for read/write, and the buffer must meet device controller driver (DCD) buffer requirements (e.g., aligned and cache safe). It only works if *UX_DEVICE_ENDPOINT_BUFFER_OWNER* is 1 (endpoint buffer managed by class). | + +## cdc_acm_class_apis + The CDC-ACM class API functions are defined below. +- [ux_device_class_cdc_acm_ioctl](#ux_device_class_cdc_acm_ioctl) +- [ux_device_class_cdc_acm_read](#ux_device_class_cdc_acm_read) +- [ux_device_class_cdc_acm_read_run](#ux_device_class_cdc_acm_read_run) +- [ux_device_class_cdc_acm_write](#ux_device_class_cdc_acm_write) +- [ux_device_class_cdc_acm_write_run](#ux_device_class_cdc_acm_write_run) +- [ux_device_class_cdc_acm_write_with_callback](#ux_device_class_cdc_acm_write_with_callback) + ### ux_device_class_cdc_acm_ioctl Perform IOCTL on the CDC-ACM interface @@ -434,7 +461,7 @@ Perform IOCTL on the CDC-ACM interface ### Prototype ```c -UINT ux_device_class_cdc_acm_ioctl ( +UINT ux_device_class_cdc_acm_ioctl( UX_SLAVE_CLASS_CDC_ACM *cdc_acm, ULONG ioctl_function, VOID *parameter); @@ -459,9 +486,7 @@ This function is called when an application needs to perform various ioctl calls ```c /* Start cdc acm callback transmission. */ - -status = _ux_device_class_cdc_acm_ioctl(cdc_acm_slave, - UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START, &callback); +status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START, &callback); if(status != UX_SUCCESS) return; @@ -478,6 +503,8 @@ if(status != UX_SUCCESS) | 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 | +| UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_READ_TIMEOUT | 8 | +| UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_WRITE_TIMEOUT | 9 | ### ux_device_class_cdc_acm_ioctl: UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_CODING @@ -486,15 +513,15 @@ Perform IOCTL Set Line Coding on the CDC-ACM interface ### Prototype ```c -UINT ux_device_class_cdc_acm_ioctl ( - UX_SLAVE_CLASS_CDC_ACM*cdc_acm, +UINT ux_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 Set the Line Coding parameters. +This function is called when an application needs to set the line coding parameters. ### Parameters @@ -519,19 +546,15 @@ typedef struct UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_PARAMETER_STRUCT ### Example ```c -/* Change the line coding values. */ - -line_coding.ux_slave_class_cdc_acm_line_coding_dter = 9600; -line_coding.ux_slave_class_cdc_acm_line_coding_stop_bit = - UX_HOST_CLASS_CDC_ACM_LINE_CODING_STOP_BIT_15; +UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_PARAMETER cdc_acm_slave_line_coding; -line_coding.ux_slave_class_cdc_acm_line_coding_parity = - UX_HOST_CLASS_CDC_ACM_LINE_CODING_PARITY_EVEN; - -line_coding.ux_slave_class_cdc_acm_line_coding_data_bits = 5; +/* Change the line coding values. */ +cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_baudrate = UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_RATE; +cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_line_coding_stop_bit = UX_HOST_CLASS_CDC_ACM_LINE_CODING_STOP_BIT_15; +cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_line_coding_parity = UX_HOST_CLASS_CDC_ACM_LINE_CODING_PARITY_EVEN; +cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_line_coding_data_bits = UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_RATE; -status = _ux_slave_class_cdc_acm_ioctl(cdc_acm, - UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_CODING, &line_coding); +status = ux_device_class_cdc_acm_ioctl(cdc_acm, UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_CODING, &cdc_acm_slave_line_coding); if (status != UX_SUCCESS) break; @@ -544,7 +567,7 @@ Perform IOCTL Get Line Coding on the CDC-ACM interface ### Prototype ```c -device_class_cdc_acm_ioctl ( +device_class_cdc_acm_ioctl( UX_SLAVE_CLASS_CDC_ACM *cdc_acm, ULONG ioctl_function, VOID *parameter); @@ -552,7 +575,7 @@ device_class_cdc_acm_ioctl ( ### Description -This function is called when an application needs to Get the Line Coding parameters. +This function is called when an application needs to get the line coding parameters. ### Parameters @@ -577,31 +600,31 @@ typedef struct UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_PARAMETER_STRUCT ### Example ```c -/* This is to retrieve BAUD rate. */ +UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_PARAMETER cdc_acm_slave_line_coding; -status = _ux_device_class_cdc_acm_ioctl(cdc_acm_slave, - UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING, &line_coding); +/* 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, &cdc_acm_slave_line_coding); /* Any error ? */ if (status == UX_SUCCESS) { /* Decode BAUD rate. */ - switch (line_coding.ux_slave_class_cdc_acm_parameter_baudrate) + switch (cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_baudrate) { case 1200 : - status = tx_demo_thread_slave_cdc_acm_response("1200", 4); + status = demo_cdc_acm_response("1200", 4); break; case 2400 : - status = tx_demo_thread_slave_cdc_acm_response("2400", 4); + status = demo_cdc_acm_response("2400", 4); break; case 4800 : - status = tx_demo_thread_slave_cdc_acm_response("4800", 4); + status = demo_cdc_acm_response("4800", 4); break; case 9600 : - status = tx_demo_thread_slave_cdc_acm_response("9600", 4); + status = demo_cdc_acm_response("9600", 4); break; case 115200 : - status = tx_demo_thread_slave_cdc_acm_response("115200", 6); + status = demo_cdc_acm_response("115200", 6); break; } } @@ -614,15 +637,15 @@ Perform IOCTL Get Line State on the CDC-ACM interface ### Prototype ```c -UINT ux_device_class_cdc_acm_ioctl ( - UX_SLAVE_CLASS_CDC_ACM*cdc_acm, +UINT ux_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 State parameters. +This function is called when an application needs to get the line state parameters. ### Parameters @@ -645,20 +668,21 @@ typedef struct UX_SLAVE_CLASS_CDC_ACM_LINE_STATE_PARAMETER_STRUCT ### Example ```c +UX_SLAVE_CLASS_CDC_ACM_LINE_STATE_PARAMETER cdc_acm_slave_line_state; + /* This is to retrieve RTS state. */ -status = _ux_device_class_cdc_acm_ioctl(cdc_acm_slave, - UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_STATE, &line_state); +status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_STATE, &cdc_acm_slave_line_state); /* Any error ? */ if (status == UX_SUCCESS) { -/* Check state. */ - if (line_state.ux_slave_class_cdc_acm_parameter_rts == UX_TRUE) + /* Check state. */ + if (cdc_acm_slave_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); + status = demo_cdc_acm_response("RTS ON", 6); else /* State is OFF. */ - status = tx_demo_thread_slave_cdc_acm_response("RTS OFF", 7); + status = demo_cdc_acm_response("RTS OFF", 7); } ``` @@ -669,7 +693,7 @@ Perform IOCTL Set Line State on the CDC-ACM interface ### Prototype ```c -UINT ux_device_class_cdc_acm_ioctl ( +UINT ux_device_class_cdc_acm_ioctl( UX_SLAVE_CLASS_CDC_ACM *cdc_acm, ULONG ioctl_function, VOID *parameter); @@ -677,7 +701,7 @@ UINT ux_device_class_cdc_acm_ioctl ( ### Description -This function is called when an application needs to Get the Line State parameters +This function is called when an application needs to set the line state parameters ### Parameters @@ -700,13 +724,16 @@ typedef struct UX_SLAVE_CLASS_CDC_ACM_LINE_STATE_PARAMETER_STRUCT ### Example ```c +UX_SLAVE_CLASS_CDC_ACM_LINE_STATE_PARAMETER cdc_acm_slave_line_state; + /* This is to set RTS state. */ +cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_rts = UX_TRUE; -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); +status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_STATE, &cdc_acm_slave_line_state); /* If status is UX_SUCCESS, the operation was successful. */ +if (status != UX_SUCCESS) + return; ``` ### ux_device_class_cdc_acm_ioctl: UX_SLAVE_CLASS_CDC_ACM_IOCTL_ABORT_PIPE @@ -716,7 +743,7 @@ Perform IOCTL ABORT PIPE on the CDC-ACM interface ### Prototype ```c -UINT ux_device_class_cdc_acm_ioctl ( +UINT ux_device_class_cdc_acm_ioctl( UX_SLAVE_CLASS_CDC_ACM *cdc_acm, ULONG ioctl_function, VOID *parameter); @@ -733,9 +760,8 @@ This function is called when an application needs to abort a pipe. For example, - **parameter**: The pipe direction: ```c -UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_XMIT 1 - -UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_RCV 2 +UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_XMIT 1 +UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_RCV 2 ``` ### Return Value @@ -748,11 +774,11 @@ UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_RCV 2 ```c /* 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); +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); /* If status is UX_SUCCESS, the operation was successful. */ +if (status != UX_SUCCESS) + return; ``` ### ux_device_class_cdc_acm_ioctl: UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START @@ -781,10 +807,8 @@ This function is called when an application wants to use transmission with callb ```c typedef struct UX_SLAVE_CLASS_CDC_ACM_CALLBACK_PARAMETER_STRUCT { - UINT (*ux_device_class_cdc_acm_parameter_write_callback)(struct UX_SLAVE_CLASS_CDC_ACM_STRUCT *cdc_acm, - UINT status, ULONG length); - 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); + UINT (*ux_device_class_cdc_acm_parameter_write_callback)(struct UX_SLAVE_CLASS_CDC_ACM_STRUCT *cdc_acm, UINT status, ULONG length); + 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; ``` @@ -797,19 +821,18 @@ typedef struct UX_SLAVE_CLASS_CDC_ACM_CALLBACK_PARAMETER_STRUCT ### Example ```c -/* Set the callback parameter. */ +UX_SLAVE_CLASS_CDC_ACM_CALLBACK_PARAMETER cdc_acm_slave_callback; -callback.ux_device_class_cdc_acm_parameter_write_callback - = tx_demo_thread_slave_write_callback; - -callback.ux_device_class_cdc_acm_parameter_read_callback - = tx_demo_thread_slave_read_callback; +/* Set the callback parameter. */ +cdc_acm_slave_callback.ux_device_class_cdc_acm_parameter_write_callback = demo_cdc_acm_write_callback; +cdc_acm_slave_callback.ux_device_class_cdc_acm_parameter_read_callback = demo_cdc_acm_read_callback; /* Program the start of transmission. */ -status = _ux_device_class_cdc_acm_ioctl(cdc_acm_slave, - UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START, &callback); +status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START, &cdc_acm_slave_callback); /* If status is UX_SUCCESS, the operation was successful. */ +if (status != UX_SUCCESS) + return; ``` ### ux_device_class_cdc_acm_ioctl: UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_STOP @@ -845,18 +868,95 @@ This function is called when an application wants to stop using transmission wit ```c /* Program the stop of transmission. */ -status = _ux_device_class_cdc_acm_ioctl(cdc_acm_slave, - UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_STOP, UX_NULL); +status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_STOP, UX_NULL); /* If status is UX_SUCCESS, the operation was successful. */ +if (status != UX_SUCCESS) + return; ``` -### ux_device_class_cdc_acm_read +### ux_device_class_cdc_acm_ioctl: UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_READ_TIMEOUT -Read from CDC-ACM pipe +Perform IOCTL set read timeout on the CDC-ACM interface ### Prototype +```c +UINT ux_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 Set read timeout parameters. + +### Parameters + +- **cdc_acm**: Pointer to the cdc class instance. +- **ioctl_function**: ux_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START +- **parameter**: Pointer to the Start Transmission parameter structure: + +### Return Value + +- **UX_SUCCESS** (0x00) This operation was successful. +- **UX_ERROR** (0xFF) Transmission already started. +- **UX_MEMORY_INSUFFICIENT** (0x12) A memory allocation failed. + +### Example + +```c +status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_READ_TIMEOUT, (VOID *)10); + +/* If status is UX_SUCCESS, the operation was successful. */ +if (status != UX_SUCCESS) + return; +``` + +### ux_device_class_cdc_acm_ioctl: UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_WRITE_TIMEOUT + +Perform IOCTL set write timeout on the CDC-ACM interface + +### Prototype + +```c +UINT ux_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 set write timeout parameters. +### Parameters + +- **cdc_acm**: Pointer to the cdc class instance. +- **ioctl_function**: ux_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START +- **parameter**: Pointer to the Start Transmission parameter structure: + +### Return Value + +- **UX_SUCCESS** (0x00) This operation was successful. +- **UX_ERROR** (0xFF) Transmission already started. +- **UX_MEMORY_INSUFFICIENT** (0x12) A memory allocation failed. + +### Example + +```c +status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_WRITE_TIMEOUT, (VOID *)10); + +/* If status is UX_SUCCESS, the operation was successful. */ +if (status != UX_SUCCESS) + return; +``` + +### ux_device_class_cdc_acm_read + +Read from CDC-ACM pipe, This function is for RTOS mode. +### Prototype + ```c UINT ux_device_class_cdc_acm_read( UX_SLAVE_CLASS_CDC_ACM *cdc_acm, @@ -869,7 +969,7 @@ UINT ux_device_class_cdc_acm_read( 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. -> **Note:** This functions reads raw bulk data from host, so it keeps pending until buffer is full or host terminates the transfer by a short packet (including Zero Length Packet). For more details, please refer to section [**General Considerations for Bulk Transfer**](#general-considerations-for-bulk-transfer). +> **Note:** This functions reads raw bulk data from host, so it keeps pending until buffer is full or host terminates the transfer by a short packet (including Zero Length Packet). For more details, please refer to section [**General Considerations for Bulk Transfer**](#general_considerations_for_bulk_transfer). > The function reads bytes from the host packet by packet. If the prepared buffer size is smaller than a packet and the host sends more data than expected (in other words, the prepared buffer size is not a multiple of the USB endpoint's max packet size), then buffer overflow will occur. To avoid this issue, the recommended way to read is to allocate a buffer exactly one packet size (USB endpoint max packet size). This way if there is more data, the next read can get it and no buffer overflow will occur. If there is less data, the current read can get a short packet instead of generating an error. ### Parameters @@ -889,15 +989,90 @@ This function is called when an application needs to read from the OUT data pipe ```c /* Read from the CDC class. */ - status = ux_device_class_cdc_acm_read(cdc, buffer, UX_DEMO_BUFFER_SIZE, &actual_length); -if(status != UX_SUCCESS) return; +if (status != UX_SUCCESS) + return; +``` + +### ux_device_class_cdc_acm_read_run + +Read from CDC-ACM pipe, it's for standalone mode. + +### Prototype + +```c +UINT ux_device_class_cdc_acm_read_run( + UX_SLAVE_CLASS_CDC_ACM *cdc_acm, + UCHAR *buffer, + ULONG requested_length, + ULONG *actual_length); +``` + +### 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. + +> **Note:** This functions reads raw bulk data from host, so it keeps pending until buffer is full or host terminates the transfer by a short packet (including Zero Length Packet). For more details, please refer to section [**General Considerations for Bulk Transfer**](#general_considerations_for_bulk_transfer). +> The function reads bytes from the host packet by packet. If the prepared buffer size is smaller than a packet and the host sends more data than expected (in other words, the prepared buffer size is not a multiple of the USB endpoint's max packet size), then buffer overflow will occur. To avoid this issue, the recommended way to read is to allocate a buffer exactly one packet size (USB endpoint max packet size). This way if there is more data, the next read can get it and no buffer overflow will occur. If there is less data, the current read can get a short packet instead of generating an error. + +> **Note:** This API works only in standalone mode, *UX_STANDALONE* should be defined in 'ux_user.h' + +### Parameters + +- **cdc_acm**: Pointer to the cdc class instance. +- **buffer**: Buffer address where data will be stored. +- **requested_length**: The maximum length we expect. +- **actual_length**: The length returned into the buffer. + +### Return Value + +- **UX_STATE_NEXT** (0x04) Transfer done, to next state. +- **UX_STATE_EXIT** (0x01) Abnormal, to reset state. +- **UX_STATE_ERROR** (0x03) Error occurred. + +### Example + +```c +#define CDC_ACM_DEVICE_STATE_READ UX_STATE_STEP +#define CDC_ACM_DEVICE_STATE_WRITE UX_STATE_STEP + 1 +#define CDC_ACM_DEVICE_STATE_ZLP UX_STATE_STEP + 2 + +UINT cdc_acm_device_state = UX_STATE_RESET; +ULONG actual_length; +ULONG device_read_length = UX_SLAVE_REQUEST_DATA_MAX_LENGTH; +UCHAR device_buffer[UX_SLAVE_REQUEST_DATA_MAX_LENGTH * 2]; + +if (cdc_acm_slave == UX_NULL) +{ + cdc_acm_device_state = UX_STATE_RESET; + break; +} + +status = ux_device_class_cdc_acm_read_run(cdc_acm_slave, device_buffer, device_read_length, &actual_length); + +if (status < UX_STATE_NEXT) +{ + return; +} + +if (status == UX_STATE_NEXT) +{ + write_length = actual_length; + + if ((actual_length < device_read_length) && + ((actual_length & 63) == 0)) + { + write_zlp = UX_TRUE; + } + + cdc_acm_device_state = CDC_ACM_DEVICE_STATE_WRITE; +} ``` ### ux_device_class_cdc_acm_write -Write to a CDC-ACM pipe +Write to a CDC-ACM pipe, This function is for RTOS mode. ### Prototype @@ -929,13 +1104,68 @@ This function is called when an application needs to write to the IN data pipe ( ```c /* Write to the CDC class bulk in pipe. */ - status = ux_device_class_cdc_acm_write(cdc, buffer, UX_DEMO_BUFFER_SIZE, &actual_length); if(status != UX_SUCCESS) return; ``` +### ux_device_class_cdc_acm_write_run + +Write to a CDC-ACM pipe, it's for standalone mode. + +### Prototype + +```c +UINT ux_device_class_cdc_acm_write_run( + UX_SLAVE_CLASS_CDC_ACM *cdc_acm, + UCHAR *buffer, + ULONG requested_length, + ULONG *actual_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). It is blocking. + +> **Note:** This API works only in standalone mode, *UX_STANDALONE* should be defined in 'ux_user.h' + +### Parameters + +- **cdc_acm**: Pointer to the cdc class instance. +- **buffer**: Buffer address where data is stored. +- **requested_length**: The length of the buffer to write. +- **actual_length**: The length returned into the buffer after write is performed. + +### Return Value +- **UX_STATE_NEXT** (0x04) Transfer done, to next state. +- **UX_STATE_EXIT** (0x01) Abnormal, to reset state. +- **UX_STATE_ERROR** (0x03) Error occurred. + +### Example + +```c +UCHAR device_buffer[UX_SLAVE_REQUEST_DATA_MAX_LENGTH * 2]; + +status = ux_device_class_cdc_acm_write_run(cdc_acm_slave, device_buffer, write_length, &actual_length); + +if (status < UX_STATE_NEXT) +{ + return; +} + +if (status == UX_STATE_NEXT) +{ + if (write_zlp && ((write_length % 64) == 0)) + { + cdc_acm_device_state = CDC_ACM_DEVICE_STATE_ZLP; + break; + } + cdc_acm_device_state = CDC_ACM_DEVICE_STATE_READ; + break; +} +``` + ### ux_device_class_cdc_acm_write_with_callback Writing to a CDC-ACM pipe with callback @@ -969,6 +1199,8 @@ This function is called when an application needs to write to the IN data pipe ( ### Example ```c +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) + /* Write to the CDC class bulk in pipe non blocking mode. */ status = ux_device_class_cdc_acm_write_with_callback(cdc, buffer, UX_DEMO_BUFFER_SIZE); @@ -976,10 +1208,15 @@ if(status != UX_SUCCESS) return; ``` -### USB Device CDC-ECM Class +# 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. +- [CDC-ECM Class Initialize](#cdc_ecm_class_initialize) +- [CDC-ECM Class Configuration Options](#cdc_ecm_class_configuration_options) + +## cdc_ecm_class_initialize + A CDC-ECM compliant device framework needs to be declared by the device stack. An example is found here below. ```c @@ -1046,7 +1283,7 @@ unsigned char string_framework[] = { 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x20, 0x4c, 0x6f, 0x67, 0x69, 0x63, - /* Product string descriptor: Index 2 - "EL CDCECM Device" */ + /* Product string descriptor: Index 2 - "EL CDC-ECM Device" */ 0x09, 0x04, 0x02, 0x10, 0x45, 0x4c, 0x20, 0x43, 0x44, 0x43, 0x45, 0x43, 0x4d, 0x20, 0x44, 0x65, 0x76, 0x69, 0x63, 0x64, @@ -1068,9 +1305,11 @@ The MAC address string descriptor is used by the CDC-ECM class to reply to the h The initialization of the CDC-ECM class is as follows. ```c -/* Set the parameters for callback when insertion/extraction of a CDC device. Set to NULL.*/ -cdc_ecm_parameter.ux_slave_class_cdc_ecm_instance_activate = UX_NULL; -cdc_ecm_parameter.ux_slave_class_cdc_ecm_instance_deactivate = UX_NULL; +UX_SLAVE_CLASS_CDC_ECM_PARAMETER cdc_ecm_parameter; + +/* Set the parameters for callback when insertion/extraction of a CDC device. */ +cdc_ecm_parameter.ux_slave_class_cdc_ecm_instance_activate = demo_cdc_ecm_instance_activate; +cdc_ecm_parameter.ux_slave_class_cdc_ecm_instance_deactivate = demo_cdc_ecm_instance_deactivate; /* Define a NODE ID. */ cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_local_node_id[0] = 0x00; @@ -1089,8 +1328,10 @@ cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_remote_node_id[4] = 0xb8; cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_remote_node_id[5] = 0x79; /* Initialize the device cdc_ecm class. */ -status = ux_device_stack_class_register(_ux_system_slave_class_cdc_ecm_name, - ux_device_class_cdc_ecm_entry, 1,0,&cdc_ecm_parameter); +status = ux_device_stack_class_register(_ux_system_slave_class_cdc_ecm_name, ux_device_class_cdc_ecm_entry, 1, 0, (VOID *)&cdc_ecm_parameter); + +if(status != UX_SUCCESS) + return; ``` 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. @@ -1109,16 +1350,32 @@ nx_system_initialize(); ux_network_driver_init(); ``` -The USB network stack needs to be activated only once and is not specific to CDCECM but is required by any USB class that requires NetX services. +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 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. -## USB Device HID Class +## cdc_ecm_class_configuration_options + +There are several configuration options for building USB Device CDC-ECM Class. All options are located in the ***ux_user.h***. + +| Configuration Option | Description | +| ------------------------------------------------- | ----------- | +| **UX_DEVICE_CLASS_CDC_ECM_NX_PKPOOL_ENTRIES** | This value represents the number of packets in the CDC_ECM device class. The default is 16. | +| **UX_DEVICE_CLASS_CDC_ECM_PACKET_POOL_WAIT** | This value represents the number of milliseconds to wait for packet allocation until invoking the application's error callback and retrying. | +| **UX_DEVICE_CLASS_CDC_ECM_ZERO_COPY** | This marco enables device CDC_ECM zero copy support (works if CDC_ECM owns endpoint buffer). Enabled, it requires that the NX IP default packet pool is in cache safe area, and buffer max size is larger than UX_DEVICE_CLASS_CDC_ECM_ETHERNET_PACKET_SIZE (1536). | + +# 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. +- [HID Class Initialize](#hid_class_initialize) +- [HID Class Configuration Options](#hid_class_configuration_options) +- [HID Class APIs](#hid_class_apis) + +## hid_class_initialize + Any HID client requires first to define a HID device framework as the example below. ```c @@ -1148,17 +1405,26 @@ The HID framework contains an interface descriptor that describes the HID class The initialization of the HID class is as follow, using a USB keyboard as an example. ```c -/* Initialize the hid class parameters for a keyboard. */ +UX_SLAVE_CLASS_HID_PARAMETER hid_parameter; + +/* Initialize the hid class parameters. */ +hid_parameter.ux_slave_class_hid_instance_activate = demo_hid_instance_activate; +hid_parameter.ux_slave_class_hid_instance_deactivate = demo_hid_instance_deactivate; hid_parameter.ux_device_class_hid_parameter_report_address = hid_keyboard_report; hid_parameter.ux_device_class_hid_parameter_report_length = HID_KEYBOARD_REPORT_LENGTH; -hid_parameter.ux_device_class_hid_parameter_callback = tx_demo_thread_hid_callback; -hid_parameter.ux_device_class_hid_parameter_get_callback = tx_demo_thread_hid_get_callback; +hid_parameter.ux_device_class_hid_parameter_callback = demo_hid_callback; +hid_parameter.ux_device_class_hid_parameter_get_callback = demo_hid_get_callback; hid_parameter.ux_device_class_hid_parameter_report_id = 0; +#if defined(UX_DEVICE_CLASS_HID_INTERRUPT_OUT_SUPPORT) +hid_parameter.ux_device_class_hid_parameter_receiver_initialize = ux_device_class_hid_receiver_initialize; +hid_parameter.ux_device_class_hid_parameter_receiver_event_max_length = 32; +hid_parameter.ux_device_class_hid_parameter_receiver_event_max_number = 3; +hid_parameter.ux_device_class_hid_parameter_receiver_event_callback = demo_hid_receiver_event_callback; +#endif /* Initialize 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); -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; ``` @@ -1182,9 +1448,31 @@ The Get and Set report are the most commonly used commands by HID to transfer da The HID class can send data back to the host on the interrupt endpoint by using the ux_device_class_hid_event_set function. +## hid_class_configuration_options + +There are several configuration options for building USB Device HID Class. All options are located in the ***ux_user.h***. + +| Configuration Option | Description | +| ------------------------------------------------- | ----------- | +| **UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH** | This value represents the the maximum length of HID reports on the device. | +| **UX_DEVICE_CLASS_HID_MAX_EVENTS_QUEUE** | This value represents the the maximum number of HID events/reports that can be queued at once. | +| **UX_DEVICE_CLASS_HID_INTERRUPT_OUT_SUPPORT** | This macro enables device HID interrupt OUT transfer is supported. | +| **UX_DEVICE_CLASS_HID_ZERO_COPY** | This macro enables device HID zero copy and flexible queue support (works if HID owns endpoint buffer). Enabled, the internal queue buffer is directly used for transfer, the APIs are kept to keep backword compatibility, to AVOID KEEPING BUFFERS IN APPLICATION. Flexible queue introduces initialization parameter _event_max_number and _event_max_length, so each HID function could have different queue settings. _event_max_number could be 2 ~ *UX_DEVICE_CLASS_HID_MAX_EVENTS_QUEUE*. Max of _event_max_length could be *UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH*. If the initialization parameters are invalid (are 0s or exceed upper mentioned definition), *UX_DEVICE_CLASS_HID_MAX_EVENTS_QUEUE* and *UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH* are used to calculate and allocate the queue. | + +## hid_class_apis + +The HID class API functions are defined below. + +- [ux_device_class_hid_event_set](#ux_device_class_hid_event_set) +- [ux_device_class_hid_event_get](#ux_device_class_hid_event_get) +- [ux_device_class_hid_read](#ux_device_class_hid_read) +- [ux_device_class_hid_read_run](#ux_device_class_hid_read_run) +- [_ux_device_class_hid_receiver_event_get](#_ux_device_class_hid_receiver_event_get) +- [ux_device_class_hid_receiver_event_free](#ux_device_class_hid_receiver_event_free) + ### ux_device_class_hid_event_set -Setting an event to the HID class +Setting an event to the HID class. ### Prototype @@ -1210,21 +1498,267 @@ This function is called when an application needs to send a HID event back to th ### Example +the example below show how to set hid mouse event. + ```c -/* Insert a key into the keyboard event. Length is fixed to 8. */ +UX_SLAVE_CLASS_HID *hid; +UX_SLAVE_CLASS_HID_EVENT device_hid_event; + +/* Initialize mouse event. */ +device_hid_event.ux_device_class_hid_event_length = 4; +device_hid_event.ux_device_class_hid_event_buffer[0] = 0; /* ...M|R|L */ +device_hid_event.ux_device_class_hid_event_buffer[1] = 0; /* X */ +device_hid_event.ux_device_class_hid_event_buffer[2] = 0; /* Y */ +device_hid_event.ux_device_class_hid_event_buffer[3] = 0; / + +/* Set L click. */ +device_hid_event.ux_device_class_hid_event_buffer[0] = 1; /* ...M|R|L */ +ux_device_class_hid_event_set(hid, &device_hid_event); + +/* Set R click. */ +device_hid_event.ux_device_class_hid_event_buffer[0] = 3; /* ...M|R|L */ +ux_device_class_hid_event_set(hid, &device_hid_event); + +/* Move X. */ +device_hid_event.ux_device_class_hid_event_buffer[1] = -1; /* X */ +ux_device_class_hid_event_set(hid, &device_hid_event); + +/* Move Y. */ +device_hid_event.ux_device_class_hid_event_buffer[2] = +8; /* Y */ +ux_device_class_hid_event_set(hid, &device_hid_event); + +/* Move Wheel. */ +device_hid_event.ux_device_class_hid_event_buffer[1] = -2; /* X */ +device_hid_event.ux_device_class_hid_event_buffer[2] = -5; /* Y */ +device_hid_event.ux_device_class_hid_event_buffer[3] = +10; /* Wheel */ +ux_device_class_hid_event_set(hid, &device_hid_event); + +``` + +the example below show how to initialize hid keyboard event. + +```c +UX_SLAVE_CLASS_HID *hid; +UX_SLAVE_CLASS_HID_EVENT hid_event; + +/* Then insert a key into the keyboard event. Length is fixed to 8. */ hid_event.ux_device_class_hid_event_length = 8; -/* First byte is a modifier byte. */ +/* First byte is a modifier byte. */ hid_event.ux_device_class_hid_event_buffer[0] = 0; /* Second byte is reserved. */ hid_event.ux_device_class_hid_event_buffer[1] = 0; -/* The 6 next bytes are keys. We only have one key here. */ +/* The 6 next bytes are keys. We only have one key here. */ hid_event.ux_device_class_hid_event_buffer[2] = key; -/* Set the keyboard event. */ +/* Set the keyboard event. */ ux_device_class_hid_event_set(hid, &hid_event); + +/* Next event has the key depressed. */ +hid_event.ux_device_class_hid_event_buffer[2] = 0; + +/* Length is fixed to 8. */ +hid_event.ux_device_class_hid_event_length = 8; + +/* Set the keyboard event. */ +ux_device_class_hid_event_set(hid, &hid_event); + +/* Are we at the end of alphabet ? */ +if (key != (0x04 + 26)) + key++; +else + key = 0x04; +``` + +### ux_device_class_hid_event_get + +This function checks if there is an event from the application. + +### Prototype + +```c +UINT ux_device_class_hid_event_get( + UX_SLAVE_CLASS_HID *hid, + UX_SLAVE_CLASS_HID_EVENT *hid_event); +``` + +### Description + +This function is called when an application needs to checks if there is an event from the application. + +### Parameters + +- **hid**: Pointer to the hid class instance. +- **hid_event**: Pointer to structure of the hid event. + +### Return Value + +- **UX_SUCCESS** (0x00) This operation was successful. +- **UX_ERROR** (0xFF) Error no space available in circular queue. + +### Example + +```c +status = ux_device_class_hid_event_get(hid, &hid_event); +``` + +### ux_device_class_hid_read + +This function reads from the HID class. +This function is for RTOS mode. + +### Prototype + +```c +UINT ux_device_class_hid_read( + UX_SLAVE_CLASS_HID *hid, + UCHAR *buffer, + ULONG requested_length, + ULONG *actual_length) +``` + +### Description + +This function is called when an application needs to reads from the HID class application. +This function must not be used with receiver related functions. + +### Parameters + +- **hid**: Pointer to the hid class instance. +- **buffer**: Pointer to buffer to save received data. +- **requested_length**: Length of bytes to read. +- **actual_length**: Pointer to save number of bytes read. + +### Return Value + +- **UX_SUCCESS** (0x00) This operation was successful. +- **UX_ERROR** (0xFF) Error no space available in circular queue. + +### Example + +```c +#define DEVICE_BUFFER_LENGTH 32 /* 4*8 */ + 1 + +UCHAR device_buffer[DEVICE_BUFFER_LENGTH]; +ULONG device_read_request_length; +ULONG device_read_actual_length; + +status = ux_device_class_hid_read(hid, device_buffer, device_read_request_length, &device_read_actual_length); +``` + +### ux_device_class_hid_read_run + +This function reads from the HID class. +This function is for standalone mode. + +### Prototype + +```c +UINT ux_device_class_hid_read_run( + UX_SLAVE_CLASS_HID *hid, + UCHAR *buffer, + ULONG requested_length, + ULONG *actual_length) +``` + +### Description + +This function is called when an application needs to reads from the HID class application. +This function must not be used with receiver related functions. + +### Parameters + +- **hid**: Pointer to the hid class instance. +- **buffer**: Pointer to buffer to save received data. +- **requested_length**: Length of bytes to read. +- **actual_length**: Pointer to save number of bytes read. + +### Return Value + +- **UX_STATE_WAIT** (0x03) waiting. +- **UX_STATE_EXIT** (0x01) Abnormal, to reset state. +- **UX_STATE_ERROR** (0x03) Error occurred. + +### Example + +```c +#define DEVICE_BUFFER_LENGTH 32 /* 4*8 */ + 1 + +UCHAR device_buffer[DEVICE_BUFFER_LENGTH]; +ULONG device_read_request_length; +ULONG device_read_actual_length; + +status = ux_device_class_hid_read_run(hid, device_buffer, device_read_request_length, &device_read_actual_length); +``` + +### ux_device_class_hid_receiver_event_get + +This function checks if there was an event from the interrupt OUT. + +### Prototype + +```c +UINT ux_device_class_hid_receiver_event_get( + UX_SLAVE_CLASS_HID *hid, + UX_DEVICE_CLASS_HID_RECEIVED_EVENT *event) +``` + +### Description + +This function checks if there was an event from the interrupt OUT, if so return first received event length and it's buffer entry pointer. + +> **Note:** This API works only in standalone mode, *UX_DEVICE_CLASS_HID_INTERRUPT_OUT_SUPPORT* should be defined in 'ux_user.h' + +### Parameters + +- **hid**: Pointer to the hid class instance. +- **event**: Pointer of the HID event. + +### Return Value + +- **UX_SUCCESS** (0x00) This operation was successful. +- **UX_ERROR** (0xFF) Error no space available in circular queue. + +### Example + +```c +UX_DEVICE_CLASS_HID_RECEIVED_EVENT received_event; + +status = ux_device_class_hid_receiver_event_get(hid, &received_event); +``` + +### ux_device_class_hid_receiver_event_free + +This function free event buffer for new incoming interrupt OUT. + +### Prototype + +```c +UINT ux_device_class_hid_receiver_event_free ( + UX_SLAVE_CLASS_HID *hid) +``` + +### Description + +This function free event buffer for new incoming interrupt OUT and advance the current reading position. + +> **Note:** This API works only in standalone mode, *UX_DEVICE_CLASS_HID_INTERRUPT_OUT_SUPPORT* should be defined in 'ux_user.h' + +### Parameters + +- **hid**: Pointer to the hid class instance. + +### Return Value + +- **UX_SUCCESS** (0x00) This operation was successful. +- **UX_ERROR** (0xFF) Error no space available in circular queue. + +### Example + +```c +status = ux_device_class_hid_receiver_event_free(hid); ``` 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. @@ -1255,7 +1789,7 @@ This function is called when the host sends a HID SET_REPORT to the application. The following example shows how to interpret an event for a HID keyboard: ```c -UINT tx_demo_thread_hid_callback(UX_SLAVE_CLASS_HID *hid, UX_SLAVE_CLASS_HID_EVENT *hid_event +UINT demo_hid_callback(UX_SLAVE_CLASS_HID *hid, UX_SLAVE_CLASS_HID_EVENT *hid_event) { /* There was an event. Analyze it. Is it NUM LOCK ? */ if (hid_event -> ux_device_class_hid_event_buffer[0] & HID_NUM_LOCK_MASK) @@ -1277,7 +1811,7 @@ UINT tx_demo_thread_hid_callback(UX_SLAVE_CLASS_HID *hid, UX_SLAVE_CLASS_HID_EVE ### hid_get_callback -Notify that a host is requesting event through control GET_REPORT request +Notify that a host is requesting event through control GET_REPORT request. ### Prototype @@ -1289,9 +1823,7 @@ UINT hid_get_callback( ### Description -This function is invoked when host is requesting event through control GET_REPORT -request, application must fill event structure in the callback, the data size must -not exceed the event length and the max event buffer size. +This function is invoked when host is requesting event through control GET_REPORT request, application must fill event structure in the callback, the data size must not exceed the event length and the max event buffer size. ### Parameters @@ -1303,7 +1835,7 @@ not exceed the event length and the max event buffer size. The following example shows how to prepare an event: ```c -UINT tx_demo_thread_hid_get_callback(UX_SLAVE_CLASS_HID *hid, UX_SLAVE_CLASS_HID_EVENT *hid_event) +UINT demo_hid_get_callback(UX_SLAVE_CLASS_HID *hid, UX_SLAVE_CLASS_HID_EVENT *hid_event) { /* Host is asking input for GET_REPORT, prepare event data here. */ @@ -1321,14 +1853,14 @@ UINT tx_demo_thread_hid_get_callback(UX_SLAVE_CLASS_HID *hid, UX_SLAVE_CLASS_HID demo_hid_event_length += 1; event->ux_device_class_hid_event_length = demo_hid_event_length; *(event->ux_device_class_hid_event_buffer) = (UCHAR)event->ux_device_class_hid_event_report_id; - _ux_utility_memory_copy(event->ux_device_class_hid_event_buffer + 1, - demo_hid_event_buffer, - event->ux_device_class_hid_event_length - 1); + ux_utility_memory_copy(event->ux_device_class_hid_event_buffer + 1, + demo_hid_event_buffer, + event->ux_device_class_hid_event_length - 1); } else /* A prepared event can be copied here. Note if copying data to event buffer, * keep the total size inside UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH. */ - _ux_utility_memory_copy(event, my_event, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + ux_utility_memory_copy(event, my_event, sizeof(UX_SLAVE_CLASS_HID_EVENT)); } ``` diff --git a/rtos-docs/usbx/usbx-device-stack-about.md b/rtos-docs/usbx/usbx-device-stack-about.md index 5cb2659..db7bec3 100644 --- a/rtos-docs/usbx/usbx-device-stack-about.md +++ b/rtos-docs/usbx/usbx-device-stack-about.md @@ -9,19 +9,15 @@ This guide provides comprehensive information about USBX, the high performance U 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 https://www.USB.org/developers. +For technical information related to USB, see the USB specification and USB Class specifications that can be downloaded at https://www.usb.org/developers. ## Organization -- [**Chapter 1**](usbx-device-stack-1.md) - contains an introduction to USBX - -- [**Chapter 2**](usbx-device-stack-2.md) - gives the basic steps to install and use USBX with your ThreadX application - -- [**Chapter 3**](usbx-device-stack-3.md) - describes the functional components of the USBX device stack - -- [**Chapter 4**](usbx-device-stack-4.md) - describes the USBX device stack services - -- [**Chapter 5**](usbx-device-stack-5.md) - describes each USBX device class including their APIs +- [**Chapter 1**](usbx-device-stack-1.md) - contains an introduction to USBX. +- [**Chapter 2**](usbx-device-stack-2.md) - gives the basic steps to install and use USBX. +- [**Chapter 3**](usbx-device-stack-3.md) - describes the functional components of the USBX device stack. +- [**Chapter 4**](usbx-device-stack-4.md) - describes the USBX device stack services. +- [**Chapter 5**](usbx-device-stack-5.md) - describes each USBX device class including their APIs. ## Troubleshooting diff --git a/rtos-docs/usbx/usbx-device-stack-supplemental-1.md b/rtos-docs/usbx/usbx-device-stack-supplemental-1.md index 95c6e14..05b9794 100644 --- a/rtos-docs/usbx/usbx-device-stack-supplemental-1.md +++ b/rtos-docs/usbx/usbx-device-stack-supplemental-1.md @@ -9,8 +9,10 @@ This document is a supplement to the USBX Device Stack User Guide. It contains d ## Organization -- **Chapter 1** contains an introduction to USBX -- [**Chapter 2**](usbx-device-stack-supplemental-2.md) USBX Host Classes API -- [**Chapter 3**](usbx-device-stack-supplemental-3.md) USBX DPUMP Class Considerations -- [**Chapter 4**](usbx-device-stack-supplemental-4.md) USBX Pictbridge implementation -- [**Chapter 5**](usbx-device-stack-supplemental-5.md) USBX OTG +- [**Chapter 1**](usbx-device-stack-supplemental-1.md) contains an introduction to USBX. +- [**Chapter 2**](usbx-device-stack-supplemental-2.md) USBX Device Classes APIs. +- [**Chapter 3**](usbx-device-stack-supplemental-3.md) USBX DPUMP Class Considerations. +- [**Chapter 4**](usbx-device-stack-supplemental-4.md) USBX Pictbridge implementation. +- [**Chapter 5**](usbx-device-stack-supplemental-5.md) USBX OTG. +- [**Chapter 7**](usbx-device-stack-supplemental-6.md) USBX Implement controller driver (DCD). +- [**Chapter 8**](usbx-device-stack-supplemental-7.md) USBX Implement device class modules. diff --git a/rtos-docs/usbx/usbx-device-stack-supplemental-2.md b/rtos-docs/usbx/usbx-device-stack-supplemental-2.md index 073fb1d..376cfac 100644 --- a/rtos-docs/usbx/usbx-device-stack-supplemental-2.md +++ b/rtos-docs/usbx/usbx-device-stack-supplemental-2.md @@ -5,10 +5,22 @@ description: The USB device RNDIS class allows for a USB host system to communic # Chapter 2 - USBX Device Class Considerations -## USB Device RNDIS Class +USB Device Classes : +- [USB Device RNDIS Class](#usb_device_rndis_class) +- [USB Device DFU Class](#usb_device_dfu_class) +- [USB Device PIMA Class](#usb_device_pima_class) +- [USB Device AUDIO Class](#usb_device_audio_class) +- [USB Device PRINTER Class](#usb_device_printer_class) + +# usb_device_rndis_class The USB device RNDIS class allows for a USB host system to communicate with the device as a ethernet device. This class is based on the Microsoft implementation and is specific to Windows platforms. +- [RNDIS Class Initialize](#rndis_class_initialize) +- [RNDIS Class Configuration Options](#rndis_class_configuration_options) + +## rndis_class_initialize + A RNDIS compliant device framework needs to be declared by the device stack. An example is found below. ```C @@ -106,39 +118,35 @@ The RNDIS class uses a very similar device descriptor approach to the CDC-ACM an The activation of the RNDIS class is as follows. ```C -/* Set the parameters for callback when insertion/extraction of a CDC device. Set to NULL.*/ - -parameter.ux_slave_class_rndis_instance_activate = UX_NULL; -parameter.ux_slave_class_rndis_instance_deactivate = UX_NULL; - -/* Define a local NODE ID. */ - -parameter.ux_slave_class_rndis_parameter_local_node_id[0] = 0x00; -parameter.ux_slave_class_rndis_parameter_local_node_id[1] = 0x1e; -parameter.ux_slave_class_rndis_parameter_local_node_id[2] = 0x58; -parameter.ux_slave_class_rndis_parameter_local_node_id[3] = 0x41; -parameter.ux_slave_class_rndis_parameter_local_node_id[4] = 0xb8; -parameter.ux_slave_class_rndis_parameter_local_node_id[5] = 0x78; - -/* Define a remote NODE ID. */ - -parameter.ux_slave_class_rndis_parameter_remote_node_id[0] = 0x00; -parameter.ux_slave_class_rndis_parameter_remote_node_id[1] = 0x1e; -parameter.ux_slave_class_rndis_parameter_remote_node_id[2] = 0x58; -parameter.ux_slave_class_rndis_parameter_remote_node_id[3] = 0x41; -parameter.ux_slave_class_rndis_parameter_remote_node_id[4] = 0xb8; -parameter.ux_slave_class_rndis_parameter_remote_node_id[5] = 0x79; - -/* Set extra parameters used by the RNDIS query command with certain OIDs. */ - -parameter.ux_slave_class_rndis_parameter_vendor_id = 0x04b4 ; -parameter.ux_slave_class_rndis_parameter_driver_version = 0x1127; -ux_utility_memory_copy(parameter.ux_slave_class_rndis_parameter_vendor_description, - "ELOGIC RNDIS", 12); +UX_SLAVE_CLASS_RNDIS_PARAMETER rndis_parameter; + +/* Set the parameters for callback when insertion/extraction of a CDC device. */ +rndis_parameter.ux_slave_class_rndis_instance_activate = demo_rndis_instance_activate; +rndis_parameter.ux_slave_class_rndis_instance_deactivate = demo_rndis_instance_deactivate; + +/* Define a local NODE ID. */ +rndis_parameter.ux_slave_class_rndis_parameter_local_node_id[0] = 0x00; +rndis_parameter.ux_slave_class_rndis_parameter_local_node_id[1] = 0x1e; +rndis_parameter.ux_slave_class_rndis_parameter_local_node_id[2] = 0x58; +rndis_parameter.ux_slave_class_rndis_parameter_local_node_id[3] = 0x41; +rndis_parameter.ux_slave_class_rndis_parameter_local_node_id[4] = 0xb8; +rndis_parameter.ux_slave_class_rndis_parameter_local_node_id[5] = 0x78; + +/* Define a remote NODE ID. */ +rndis_parameter.ux_slave_class_rndis_parameter_remote_node_id[0] = 0x00; +rndis_parameter.ux_slave_class_rndis_parameter_remote_node_id[1] = 0x1e; +rndis_parameter.ux_slave_class_rndis_parameter_remote_node_id[2] = 0x58; +rndis_parameter.ux_slave_class_rndis_parameter_remote_node_id[3] = 0x41; +rndis_parameter.ux_slave_class_rndis_parameter_remote_node_id[4] = 0xb8; +rndis_parameter.ux_slave_class_rndis_parameter_remote_node_id[5] = 0x79; + +/* Set extra parameters used by the RNDIS query command with certain OIDs. */ +rndis_parameter.ux_slave_class_rndis_parameter_vendor_id = 0x04b4 ; +rndis_parameter.ux_slave_class_rndis_parameter_driver_version = 0x1127; +ux_utility_memory_copy(rndis_parameter.ux_slave_class_rndis_parameter_vendor_description, "ELOGIC RNDIS", 12); /* Initialize the device rndis class. This class owns both interfaces. */ -status = ux_device_stack_class_register(_ux_system_slave_class_rndis_name, - ux_device_class_rndis_entry, 1,0, ¶meter); +status = ux_device_stack_class_register(_ux_system_slave_class_rndis_name, ux_device_class_rndis_entry, 1,0, ¶meter); ``` As for the CDC-ECM, the RNDIS class requires 2 nodes, one local and one remote but there is no requirement to have a string descriptor describing the remote node. @@ -174,7 +182,15 @@ In the device framework of the RNDIS device, the PID/VID are stored in the devic When a USB host systems discovers the USB RNDIS device, it will mount a network interface and the device can be used with network protocol stack. See the host Operating System for reference. -## USB Device DFU Class +## rndis_class_configuration_options + +There are several configuration options for building USB Device RNDIS Class. All options are located in the ***ux_user.h***. + +| Configuration Option | Description | +| ------------------------------------------------- | ----------- | +| **UX_DEVICE_CLASS_RNDIS_ZERO_COPY** | This macro enables device RNDIS zero copy support (works if RNDIS owns endpoint buffer). Enabled, it requires that the NX IP default packet pool is in cache safe area, and buffer max size is larger than UX_DEVICE_CLASS_RNDIS_MAX_PACKET_TRANSFER_SIZE (1600). | + +## usb_device_dfu_class The USB device DFU class allows for a USB host system to update the device firmware based on a host application. The DFU class is a USB-IF standard class. @@ -182,6 +198,11 @@ USBX DFU class is relatively simple. It device descriptor does not require anyth The DFU class works in 3 steps. First the device mounts as normal using the class exported. An application on the host (Windows or Linux) will exercise the DFU class and send a request to reset the device into DFU mode. The device will disappear from the bus for a short time (enough for the host and the device to detect a RESET sequence) and upon restarting, the device will be exclusively in DFU mode, waiting for the host application to send a firmware upgrade. When the firmware upgrade has been completed, the host application resets the device and upon re-enumeration the device will revert to its normal operation with the new firmware. +- [DFU Class Initialize](#dfu_class_initialize) +- [DFU Class Configuration Options](#dfu_class_configuration_options) + +## dfu_class_initialize + A DFU device framework will look like this. ```C @@ -210,48 +231,35 @@ In this example, the DFU descriptor is not associated with any other classes. It The description of the DFU capabilities are as follows. -| Name | Offset | Size | type | Description | +| Name | Offset | Size | type | Description | |------------------|----------|------|-----------|------------| -| bmAttributes | 2 | 1 | Bit field | Bit 3: device will perform a bus detach-attach sequence when it receives a DFU_DETACH request. The host must not issue a USB Reset. (bitWillDetach) 0 = no 1 = yes Bit 2: device is able to communicate via USB after Manifestation phase. (bitManifestationTolerant) 0 = no, must see bus reset 1 = yes Bit 1: upload capable (bitCanUpload) 0 = no 1 = yes Bit 0: download capable (bitCanDnload) 0 = no 1 = yes | -| wDetachTimeOut | 3 | 2 | number | Time, in milliseconds, that the device will wait after receipt of the DFU_DETACH request. If this time elapses without a USB reset, then the device will terminate the Reconfiguration phase and revert back to normal operation. This represents the maximum time that the device can wait (depending on its timers, etc.). USBX sets this value to 1000 ms. | -| wTransferSize | 5 | 2 | number | Maximum number of bytes that the device can accept per control\-write operation. USBX sets this value to 64 bytes. | +| bmAttributes | 2 | 1 | Bit field | Bit 3: device will perform a bus detach-attach sequence when it receives a DFU_DETACH request. The host must not issue a USB Reset. (bitWillDetach) 0 = no 1 = yes Bit 2: device is able to communicate via USB after Manifestation phase. (bitManifestationTolerant) 0 = no, must see bus reset 1 = yes Bit 1: upload capable (bitCanUpload) 0 = no 1 = yes Bit 0: download capable (bitCanDnload) 0 = no 1 = yes | +| wDetachTimeOut | 3 | 2 | number | Time, in milliseconds, that the device will wait after receipt of the DFU_DETACH request. If this time elapses without a USB reset, then the device will terminate the Reconfiguration phase and revert back to normal operation. This represents the maximum time that the device can wait (depending on its timers, etc.). USBX sets this value to 1000 ms. | +| wTransferSize | 5 | 2 | number | Maximum number of bytes that the device can accept per control\-write operation. USBX sets this value to 64 bytes. | The declaration of the DFU class is as follows: ```C -/* Store the DFU parameters. */ - -dfu_parameter.ux_slave_class_dfu_parameter_instance_activate = - tx_demo_thread_dfu_activate; - -dfu_parameter.ux_slave_class_dfu_parameter_instance_deactivate = - tx_demo_thread_dfu_deactivate; - -dfu_parameter.ux_slave_class_dfu_parameter_read = - tx_demo_thread_dfu_read; - -dfu_parameter.ux_slave_class_dfu_parameter_write = - tx_demo_thread_dfu_write; - -dfu_parameter.ux_slave_class_dfu_parameter_get_status = - tx_demo_thread_dfu_get_status; - -dfu_parameter.ux_slave_class_dfu_parameter_notify = - tx_demo_thread_dfu_notify; - -dfu_parameter.ux_slave_class_dfu_parameter_framework = - device_framework_dfu; - -dfu_parameter.ux_slave_class_dfu_parameter_framework_length = - DEVICE_FRAMEWORK_LENGTH_DFU; - -/* Initialize the device dfu class. The class is connected with interface -1 on configuration 1. */ -status = ux_device_stack_class_register(_ux_system_slave_class_dfu_name, - ux_device_class_dfu_entry, 1, 0, - (VOID *)&dfu_parameter); - -if (status!=UX_SUCCESS) return; +UX_SLAVE_CLASS_DFU_PARAMETER dfu_parameter; + +/* Store the DFU parameters. */ +dfu_parameter.ux_slave_class_dfu_parameter_instance_activate = demo_dfu_activate; +dfu_parameter.ux_slave_class_dfu_parameter_instance_deactivate = demo_dfu_deactivate; +dfu_parameter.ux_slave_class_dfu_parameter_read = demo_dfu_read; +dfu_parameter.ux_slave_class_dfu_parameter_write = demo_dfu_write; +dfu_parameter.ux_slave_class_dfu_parameter_get_status = demo_dfu_get_status; +dfu_parameter.ux_slave_class_dfu_parameter_notify = demo_dfu_notify; +#ifdef UX_DEVICE_CLASS_DFU_CUSTOM_REQUEST_ENABLE +dfu_parameter.ux_device_class_dfu_parameter_custom_request = demo_dfu_custom_request; +#endif +dfu_parameter.ux_slave_class_dfu_parameter_framework = device_framework_dfu; +dfu_parameter.ux_slave_class_dfu_parameter_framework_length = DEVICE_FRAMEWORK_LENGTH_DFU; + +/* Initialize the device dfu class. The class is connected with interface 1 on configuration 1. */ +status = ux_device_stack_class_register(_ux_system_slave_class_dfu_name, ux_device_class_dfu_entry, 1, 0, (VOID *)&dfu_parameter); + +if (status != UX_SUCCESS) + return; ``` The DFU class needs to work with a device firmware application specific to the target. Therefore it defines several call back to read and write blocks of firmware and to get status from the firmware update application. The DFU class also has a notify callback function to inform the application when a begin and end of transfer of the firmware occur. @@ -297,12 +305,29 @@ dfu-util –R –t 64 -D file_to_download.hex The dfu-util should display the file download process until the firmware has been completely downloaded. -## USB Device PIMA Class (PTP Responder) +## dfu_class_configuration_options + +There are several configuration options for building USB Device DFU Class. All options are located in the ***ux_user.h***. + +| Configuration Option | Description | +| ------------------------------------------------- | ----------- | +| **UX_DEVICE_CLASS_DFU_UPLOAD_DISABLE** | This macro will disable DFU_UPLOAD support. | +| **UX_DEVICE_CLASS_DFU_ERROR_GET_ENABLE** | This macro will enable DFU_GETSTATUS and DFU_GETSTATE in dfuERROR. | +| **UX_DEVICE_CLASS_DFU_STATUS_MODE** | This macro will change status mode. 0 - simple mode, status is queried from application in dfuDNLOAD-SYNC and dfuMANIFEST-SYNC state, no bwPollTimeout. 1 - status is queried from application once requested, b0-3 : media status, b4-7 : bStatus, b8-31: bwPollTimeout, bwPollTimeout supported | +| **UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT** | This value represents the default DFU status bwPollTimeout. The value is 3 bytes long (max 0xFFFFFFu). By default the bwPollTimeout is 1 (means 1ms). | +| **UX_DEVICE_CLASS_DFU_CUSTOM_REQUEST_ENABLE** | This macro will enable custom request process callback. | + +# usb_device_pima_class The USB device PIMA class allows for a USB host system (Initiator) to connect to a +- [PIMA Class Initialize](#pima_class_initialize) +- [PIMA Class Configuration Options](#pima_class_configuration_options) +- [PIMA Class APIs](#pima_class_apis) + PIMA device (Responder) to transfer media files. USBX Pima Class is conforming to the USB-IF PIMA 15740 class also known as PTP class (for Picture Transfer Protocol). +# pima_class_initialize USBX device side PIMA class supports the following operations. | Operation code | Value | Description | @@ -402,22 +427,15 @@ object_info -> ux_device_class_pima_object_format = UX_DEVICE_CLASS_PIMA_OFC_SCR object_info -> ux_device_class_pima_object_storage_id = 1; object_info -> ux_device_class_pima_object_handle_id = 2; -ux_utility_string_to_unicode(_ux_pictbridge_ddiscovery_name, - object_info -> ux_device_class_pima_object_filename); +ux_utility_string_to_unicode(_ux_pictbridge_ddiscovery_name, object_info -> ux_device_class_pima_object_filename); /* Initialize the head and tail of the notification round robin buffers. At first, the head and tail are pointing to the beginning of the array. */ -pictbridge -> ux_pictbridge_event_array_head = - pictbridge -> ux_pictbridge_event_array; - -pictbridge -> ux_pictbridge_event_array_tail = - pictbridge -> ux_pictbridge_event_array; - -pictbridge -> ux_pictbridge_event_array_end = - pictbridge -> ux_pictbridge_event_array + - UX_PICTBRIDGE_MAX_EVENT_NUMBER; +pictbridge -> ux_pictbridge_event_array_head = pictbridge -> ux_pictbridge_event_array; +pictbridge -> ux_pictbridge_event_array_tail = pictbridge -> ux_pictbridge_event_array; +pictbridge -> ux_pictbridge_event_array_end = pictbridge -> ux_pictbridge_event_array + UX_PICTBRIDGE_MAX_EVENT_NUMBER; /* Initialize the pima device parameter. */ pictbridge -> ux_pictbridge_pima_parameter.ux_device_class_pima_parameter_manufacturer = @@ -485,13 +503,98 @@ pictbridge -> ux_pictbridge_pima_parameter.ux_device_class_pima_parameter_applic /* Initialize the device pima class. The class is connected with interface 0 */ -status = ux_device_stack_class_register(_ux_system_slave_class_pima_name, - ux_device_class_pima_entry, 1, 0, (VOID *)&pictbridge -> ux_pictbridge_pima_parameter); +status = ux_device_stack_class_register(_ux_system_slave_class_pima_name, ux_device_class_pima_entry, 1, 0, (VOID *)&pictbridge -> ux_pictbridge_pima_parameter); /* Check status. */ if (status != UX_SUCCESS) +{ + return; +} +``` + +The following example shows how to initialize the client side of PIMA. This example uses PIMA. + +```C +UX_SLAVE_CLASS_PIMA_PARAMETER pima_device_parameter; + +/* Set the parameters for PIMA device. */ +pima_device_parameter.ux_device_class_pima_instance_activate = test_pima_instance_activate; +pima_device_parameter.ux_device_class_pima_instance_deactivate = test_pima_instance_deactivate; + +/* Initialize the pima device parameter. */ +pima_device_parameter.ux_device_class_pima_parameter_manufacturer = pima_device_info_vendor_name; +pima_device_parameter.ux_device_class_pima_parameter_model = pima_device_info_product_name; +pima_device_parameter.ux_device_class_pima_parameter_device_version = pima_device_info_version; +pima_device_parameter.ux_device_class_pima_parameter_serial_number = pima_device_info_serial_no; +pima_device_parameter.ux_device_class_pima_parameter_storage_id = UX_TEST_PIMA_STORAGE_ID; +pima_device_parameter.ux_device_class_pima_parameter_storage_type = UX_DEVICE_CLASS_PIMA_STC_FIXED_RAM; +pima_device_parameter.ux_device_class_pima_parameter_storage_file_system_type = UX_DEVICE_CLASS_PIMA_FSTC_GENERIC_FLAT; +pima_device_parameter.ux_device_class_pima_parameter_storage_access_capability = UX_DEVICE_CLASS_PIMA_AC_READ_WRITE; +pima_device_parameter.ux_device_class_pima_parameter_storage_max_capacity_low = ram_disk.fx_media_total_clusters * ram_disk.fx_media_sectors_per_cluster * ram_disk.fx_media_bytes_per_sector; +pima_device_parameter.ux_device_class_pima_parameter_storage_max_capacity_high = 0; +pima_device_parameter.ux_device_class_pima_parameter_storage_free_space_low = ram_disk.fx_media_available_clusters * ram_disk.fx_media_sectors_per_cluster * ram_disk.fx_media_bytes_per_sector; +pima_device_parameter.ux_device_class_pima_parameter_storage_free_space_high = 0; +pima_device_parameter.ux_device_class_pima_parameter_storage_free_space_image = 0xFFFFFFFF; +pima_device_parameter.ux_device_class_pima_parameter_storage_description = pima_parameter_volume_description; +pima_device_parameter.ux_device_class_pima_parameter_storage_volume_label = pima_parameter_volume_label; +pima_device_parameter.ux_device_class_pima_parameter_device_properties_list = pima_device_prop_supported; +pima_device_parameter.ux_device_class_pima_parameter_supported_capture_formats_list= pima_device_supported_capture_formats; +pima_device_parameter.ux_device_class_pima_parameter_supported_image_formats_list = pima_device_supported_image_formats; +pima_device_parameter.ux_device_class_pima_parameter_object_properties_list = pima_device_object_prop_supported; + +/* Define the callbacks. */ +pima_device_parameter.ux_device_class_pima_parameter_device_reset = pima_device_device_reset; +pima_device_parameter.ux_device_class_pima_parameter_device_prop_desc_get = pima_device_device_prop_desc_get; +pima_device_parameter.ux_device_class_pima_parameter_device_prop_value_get = pima_device_device_prop_value_get; +pima_device_parameter.ux_device_class_pima_parameter_device_prop_value_set = pima_device_device_prop_value_set; +pima_device_parameter.ux_device_class_pima_parameter_storage_format = pima_device_storage_format; +pima_device_parameter.ux_device_class_pima_parameter_storage_info_get = pima_device_storage_info_get; +pima_device_parameter.ux_device_class_pima_parameter_object_number_get = pima_device_object_number_get; +pima_device_parameter.ux_device_class_pima_parameter_object_handles_get = pima_device_object_handles_get; +pima_device_parameter.ux_device_class_pima_parameter_object_info_get = pima_device_object_info_get; +pima_device_parameter.ux_device_class_pima_parameter_object_data_get = pima_device_object_data_get; +pima_device_parameter.ux_device_class_pima_parameter_object_info_send = pima_device_object_info_send; +pima_device_parameter.ux_device_class_pima_parameter_object_data_send = pima_device_object_data_send; +pima_device_parameter.ux_device_class_pima_parameter_object_delete = pima_device_object_delete; +pima_device_parameter.ux_device_class_pima_parameter_object_prop_desc_get = pima_device_object_prop_desc_get; +pima_device_parameter.ux_device_class_pima_parameter_object_prop_value_get = pima_device_object_prop_value_get; +pima_device_parameter.ux_device_class_pima_parameter_object_prop_value_set = pima_device_object_prop_value_set; +pima_device_parameter.ux_device_class_pima_parameter_object_references_get = pima_device_object_references_get; +pima_device_parameter.ux_device_class_pima_parameter_object_references_set = pima_device_object_references_set; + +/* Store the instance owner. */ +pima_device_parameter.ux_device_class_pima_parameter_application = (VOID *) 0; + +/* Initialize the device PIMA class. */ +status = ux_device_stack_class_register(_ux_system_slave_class_pima_name, ux_device_class_pima_entry, 1, 0, &pima_device_parameter); + +if (status != UX_SUCCESS) +{ + return; +} ``` +## pima_class_configuration_options + +There are several configuration options for building USB Device PIMA Class. All options are located in the ***ux_user.h***. + +| Configuration Option | Description | +| ------------------------------------------------- | ----------- | +| **UX_PIMA_WITH_MTP_SUPPORT** | This macro enables device/host PIMA MTP support. | + +## pima_class_apis + +The PIMA class API functions are defined below. + +- [ux_device_class_pima_object_add](#ux_device_class_pima_object_add) +- [ux_device_class_pima_object_number_get](#ux_device_class_pima_object_number_get) +- [ux_device_class_pima_object_handles_get](#ux_device_class_pima_object_handles_get) +- [ux_device_class_pima_object_info_get](#ux_device_class_pima_object_info_get) +- [ux_device_class_pima_object_data_get](#ux_device_class_pima_object_data_get) +- [ux_device_class_pima_object_info_send](#ux_device_class_pima_object_info_send) +- [ux_device_class_pima_object_data_send](#ux_device_class_pima_object_data_send) +- [ux_device_class_pima_object_delete](#ux_device_class_pima_object_delete) + ## ux_device_class_pima_object_add Adding an object and sending the event to the host @@ -517,7 +620,6 @@ This function is called when the PIMA class needs to add an object and inform th ```C /* Send the notification to the host that an object has been added. */ - status = ux_device_class_pima_object_add(pima, UX_PICTBRIDGE_OBJECT_HANDLE_CLIENT_REQUEST); ``` @@ -1020,10 +1122,14 @@ UINT ux_pictbridge_dpsclient_object_delete(UX_SLAVE_CLASS_PIMA *pima, } ``` -## USB Device Audio Class +## usb_device_audio_class The USB device Audio class allows for a USB host system to communicate with the device as an audio device. This class is based on the USB standard and USB Audio Class 1.0 or 2.0 standard. +- [AUDIO Class Initialize](#audio_class_initialize) +- [AUDIO Class Configuration Options](#audio_class_configuration_options) +- [AUDIO Class APIs](#audio_class_apis) + A USB audio compliant device framework needs to be declared by the device stack. An example of an Audio 2.0 speaker follows: ```C @@ -1163,79 +1269,107 @@ The initialization of the Audio class expects the following parts. 1. Audio class expects the following streaming parameters: - ```C - /* Set the parameters for Audio streams. */ - /* Set the application-defined callback that is invoked when the - host requests a change to the alternate setting. */ - audio_stream_parameter[0].ux_device_class_audio_stream_parameter_callbacks - .ux_device_class_audio_stream_change = demo_audio_read_change; - - /* Set the application-defined callback that is invoked whenever - a USB packet (audio frame) is sent to or received from the host. */ - audio_stream_parameter[0].ux_device_class_audio_stream_parameter_callbacks - .ux_device_class_audio_stream_frame_done = demo_audio_read_done; - - /* Set the number of audio frame buffers in the FIFO. */ - audio_stream_parameter[0].ux_device_class_audio_stream_parameter_max_frame _buffer_nb = UX_DEMO_FRAME_BUFFER_NB; - - /* Set the maximum size of each audio frame buffer in the FIFO. */ - audio_stream_parameter[0].ux_device_class_audio_stream_parameter_max_frame _buffer_size = UX_DEMO_MAX_FRAME_SIZE; +```C +UX_DEVICE_CLASS_AUDIO_STREAM_PARAMETER audio_stream_parameter[2]; + +#if !defined(UX_DEVICE_STANDALONE) +audio_stream_parameter[0].ux_device_class_audio_stream_parameter_thread_entry = ux_device_class_audio_write_thread_entry; +#else +audio_stream_parameter[0].ux_device_class_audio_stream_parameter_task_function = _ux_device_class_audio_write_task_function; +#endif +audio_stream_parameter[0].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_change = slave_audio_tx_stream_change; +audio_stream_parameter[0].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_frame_done = slave_audio_tx_done; +audio_stream_parameter[0].ux_device_class_audio_stream_parameter_max_frame_buffer_size = 256; +audio_stream_parameter[0].ux_device_class_audio_stream_parameter_max_frame_buffer_nb = 8; + +#if defined(UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT) +#if !defined(UX_DEVICE_STANDALONE) + audio_stream_parameter[0].ux_device_class_audio_stream_parameter_feedback_thread_entry = ux_device_class_audio_feedback_thread_entry; +#else + audio_stream_parameter[0].ux_device_class_audio_stream_parameter_feedback_task_function = _ux_device_class_audio_feedback_task_function; +#endif +#endif + +#if !defined(UX_DEVICE_STANDALONE) +audio_stream_parameter[1].ux_device_class_audio_stream_parameter_thread_entry = ux_device_class_audio_read_thread_entry; +#else +audio_stream_parameter[1].ux_device_class_audio_stream_parameter_task_function = _ux_device_class_audio_read_task_function; +#endif +audio_stream_parameter[1].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_change = slave_audio_rx_stream_change; +audio_stream_parameter[1].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_frame_done = slave_audio_rx_done; +audio_stream_parameter[1].ux_device_class_audio_stream_parameter_max_frame_buffer_size = 256; +audio_stream_parameter[1].ux_device_class_audio_stream_parameter_max_frame_buffer_nb = 8; - /* Set the internally-defined audio processing thread entry pointer. If the application wishes to receive audio from the host - (which is the case in this example), ux_device_class_audio_read_thread_entry should be used; - if the application wishes to send data to the host, ux_device_class_audio_write_thread_entry should be used. */ - audio_stream_parameter[0].ux_device_class_audio_stream_parameter_thread_entry = ux_device_class_audio_read_thread_entry; - ``` +``` 2. Audio class expects the following function parameters. - ```C - /* Set the parameters for Audio device. */ +```C +UX_DEVICE_CLASS_AUDIO_PARAMETER audio_parameter; - /* Set the number of streams. */ - audio_parameter.ux_device_class_audio_parameter_streams_nb = 1; +audio_parameter.ux_device_class_audio_parameter_callbacks.ux_slave_class_audio_instance_activate = audio_activate; +audio_parameter.ux_device_class_audio_parameter_callbacks.ux_slave_class_audio_instance_deactivate = audio_deactivate; +audio_parameter.ux_device_class_audio_parameter_streams = audio_stream_parameter; +audio_parameter.ux_device_class_audio_parameter_streams_nb = 2; +audio_parameter.ux_device_class_audio_parameter_callbacks.ux_device_class_audio_control_process = audio_control_process; +audio_parameter.ux_device_class_audio_parameter_callbacks.ux_device_class_audio_arg = UX_NULL; - /* Set the pointer to the first audio stream parameter. - Note that we initialized this parameter in the previous section. - Also note that for more than one streams, this should be an array. */ - audio_parameter.ux_device_class_audio_parameter_streams = audio_stream_parameter; +#if defined(UX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT) +audio_parameter.ux_device_class_audio_parameter_status_queue_size = 2; +audio_parameter.ux_device_class_audio_parameter_status_size = 6; +#endif - /* Set the application-defined callback that is invoked when the audio class - is activated i.e. device is connected to host. */ - audio_parameter.ux_device_class_audio_parameter_callbacks - .ux_slave_class_audio_instance_activate = demo_audio_instance_activate; +/* Initialize the device Audio class. This class owns interfaces starting with 0, 1, 2. */ +status = ux_device_stack_class_register(_ux_system_slave_class_audio_name, ux_device_class_audio_entry, 1, 0, &audio_parameter); - /* Set the application-defined callback that is invoked when the audio class - is deactivated i.e. device is disconnected from host. */ +if(status!=UX_SUCCESS) + return; +``` - audio_parameter.ux_device_class_audio_parameter_callbacks - .ux_slave_class_audio_instance_deactivate = demo_audio_instance_deactivate; +The application-defined control request callback (***ux_device_class_audio_control_process***; set in the previous example) is invoked when the stack receives a control request from the host. If the request is accepted and handled (acknowledged or stalled) the callback must return success, otherwise error should be returned. - /* Set the application-defined callback that is invoked when the stack receives a control request from the host. - See below for more details. - */ - audio_parameter.ux_device_class_audio_parameter_callbacks - .ux_device_class_audio_control_process = demo_audio20_request_process; +The class-specific control request process is defined as an application-defined callback because the control requests are very different between USB Audio versions and a large part of the request process relates to the device framework. The application should handle requests correctly to make the device functional. - /* Initialize the device Audio class. This class owns interfaces starting with 0. */ - status = ux_device_stack_class_register(_ux_system_slave_class_audio_name, - ux_device_class_audio_entry, 1, 0, &audio_parameter); - if(status!=UX_SUCCESS) - return; - ``` +Since for an audio device, volume, mute and sampling frequency are common control requests, simple, internally-defined callbacks for different USB audio versions are introduced in later sections for applications to use. Refer to ***ux_device_class_audio10_control_process*** and ***ux_device_class_audio_control_request*** for more details. + +In the device framework of the Audio device, the PID/VID are stored in the device descriptor (see the device descriptor declared above). - The application-defined control request callback (***ux_device_class_audio_control_process***; set in the previous example) is invoked when the stack receives a control request from the host. If the request is accepted and handled (acknowledged or stalled) the callback must return success, otherwise error should be returned. +When a USB host system discovers the USB Audio device and mounts the audio class, the device can be used with any audio player or recorder (depending on the framework). See the host Operating System for reference. - The class-specific control request process is defined as an application-defined callback because the control requests are very different between USB Audio versions and a large part of the request process relates to the device framework. The application should handle requests correctly to make the device functional. +## audio_class_configuration_options - Since for an audio device, volume, mute and sampling frequency are common control requests, simple, internally-defined callbacks for different USB audio versions are introduced in later sections for applications to use. Refer to ***ux_device_class_audio10_control_process*** and ***ux_device_class_audio_control_request*** for more details. +There are several configuration options for building USB Device AUDIO Class. All options are located in the ***ux_user.h***. -In the device framework of the Audio device, the PID/VID are stored in the device descriptor (see the device descriptor declared above). +| Configuration Option | Description | +| --------------------------------------------------------- | ----------- | +| **UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT** | This macro enables device audio feedback endpoint support | +| **UX_DEVICE_CLASS_AUDIO_FEEDBACK_ENDPOINT_BUFFER_SIZE** | Works if UX_DEVICE_ENDPOINT_BUFFER_OWNER is 1. Defined, it represents feedback endpoint buffer size. It should be larger than feedback endpoint max packet size in framework. | +| **UX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT** | This macro enables device audio interrupt endpoint support. | -When a USB host system discovers the USB Audio device and mounts the audio class, the device can be used with any audio player or recorder (depending on the framework). See the host Operating System for reference. +## audio_class_apis The Audio class APIs are defined below. +- [ux_device_class_audio_read_thread_entry](#ux_device_class_audio_read_thread_entry) +- [ux_device_class_audio_write_thread_entry](#ux_device_class_audio_write_thread_entry) +- [ux_device_class_audio_stream_get](#ux_device_class_audio_stream_get) +- [ux_device_class_audio_reception_start](#ux_device_class_audio_reception_start) +- [ux_device_class_audio_sample_read8](#ux_device_class_audio_sample_read8) +- [ux_device_class_audio_sample_read16](#ux_device_class_audio_sample_read16) +- [ux_device_class_audio_sample_read24](#ux_device_class_audio_sample_read24) +- [ux_device_class_audio_sample_read32](#ux_device_class_audio_sample_read32) +- [ux_device_class_audio_read_frame_get](#ux_device_class_audio_read_frame_get) +- [ux_device_class_audio_read_frame_free](#ux_device_class_audio_read_frame_free) +- [ux_device_class_audio_transmission_start](#ux_device_class_audio_transmission_start) +- [ux_device_class_audio_frame_write](#ux_device_class_audio_frame_write) +- [ux_device_class_audio_write_frame_get](#ux_device_class_audio_write_frame_get) +- [ux_device_class_audio_write_frame_commit](#ux_device_class_audio_write_frame_commit) +- [ux_device_class_audio10_control_process](#ux_device_class_audio10_control_process) +- [ux_device_class_audio20_control_process](#ux_device_class_audio20_control_process) +- [ux_device_class_audio_feedback_set](#ux_device_class_audio_feedback_set) +- [ux_device_class_audio_feedback_get](#ux_device_class_audio_feedback_get) +- [ux_device_class_audio_interrupt_send](#ux_device_class_audio_interrupt_send) + ## ux_device_class_audio_read_thread_entry Thread entry for reading data for the Audio function. @@ -1258,8 +1392,7 @@ This function is passed to the audio stream initialization parameter if reading ```C /* Set parameter to initialize a stream for reading. */ -audio_stream_parameter[0].ux_device_class_audio_stream_parameter_thread_entry - = ux_device_class_audio_read_thread_entry; +audio_stream_parameter[0].ux_device_class_audio_stream_parameter_thread_entry = ux_device_class_audio_read_thread_entry; ``` ## ux_device_class_audio_write_thread_entry @@ -1284,8 +1417,7 @@ This function is passed to the audio stream initialization parameter if writing ```C /* Set parameter to initialize as stream for writing. */ -audio_stream_parameter[0].ux_device_class_audio_stream_parameter_thread_en - try = ux_device_class_audio_write_thread_entry; +audio_stream_parameter[0].ux_device_class_audio_stream_parameter_thread_entry = ux_device_class_audio_write_thread_entry; ``` ## ux_device_class_audio_stream_get @@ -1813,7 +1945,8 @@ if (status == UX_SUCCESS) { case UX_DEVICE_CLASS_AUDIO10_CONTROL_MUTE_CHANGED: case UX_DEVICE_CLASS_AUDIO10_CONTROL_VOLUME_CHANGED: - default: break; + default: + break; } } ``` @@ -1884,10 +2017,123 @@ if (status == UX_SUCCESS) } ``` -## USB Device printer Class +## ux_device_class_audio_feedback_set + +Set encoded feedback from the Audio Stream. + +### Prototype +```C +UINT ux_device_class_audio_feedback_set( + UX_DEVICE_CLASS_AUDIO_STREAM *stream, + UCHAR *encoded_feedback) +``` + +### Description + +his function set encoded feedback of the Audio Stream. *UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT* should be defined in *ux_user.h* + +### Parameters + +- **audio**: Address of audio class instance. +- **encoded_feedback**: Feedback data (3 or 4 bytes). + +### Return Value + +- **UX_SUCCESS** (0x00) This operation was successful. +- **UX_ERROR** (0xFF) Error from function + +### Example + +```C +ULONG temp; + +audio_rx_stream->ux_device_class_audio_stream_feedback->ux_slave_endpoint_transfer_request.ux_slave_transfer_request_requested_length = 4; + +temp = 0x1234567; + +ux_device_class_audio_feedback_set(audio_rx_stream, (UCHAR *)&temp); +``` + +## ux_device_class_audio_feedback_get + +Obtain encoded feedback from the Audio Stream. + +### Prototype +```C +UINT ux_device_class_audio_feedback_get( + UX_DEVICE_CLASS_AUDIO_STREAM *stream, + UCHAR *encoded_feedback) +``` + +### Description + +This function obtain encoded feedback from the Audio Stream. *UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT* should be defined in *ux_user.h* + +### Parameters + +- **audio**: Address of audio class instance. +- **encoded_feedback**: Feedback data (3 or 4 bytes). + +### Return Value + +- **UX_SUCCESS** (0x00) This operation was successful. +- **UX_ERROR** (0xFF) Error from function + +### Example + +```C +ULONG temp; + +status = ux_device_class_audio_feedback_get(audio, (UCHAR *)&temp); +``` + +## ux_device_class_audio_interrupt_send + +Set queues audio interrupt data. + +### Prototype +```C +UINT ux_device_class_audio_interrupt_send( + UX_DEVICE_CLASS_AUDIO_STREAM *stream, + UCHAR *int_data) +``` + +### Description + +This function queues audio interrupt data. *UX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT* should be defined in *ux_user.h* +- for Audio 1.0 interrupt status word is 2 bytes. +- for Audio 2.0 interrupt data message is 6 bytes. + +### Parameters + +- **audio**: Address of audio class instance. +- **int_data**: Interrupt data (2 or 6 bytes). + +### Return Value + +- **UX_SUCCESS** (0x00) This operation was successful. +- **UX_ERROR** (0xFF) Error from function + +### Example + +```C + /* Fill one duplicate status, success. */ + status_word[0] = 0; + status_word[1] = 0; + + status = ux_device_class_audio_interrupt_send(audio, status_word); +``` + +## usb_device_printer_class The USB device printer class allows for a USB host system to communicate with the device as a printer. This class is based on the USB standard. +- [PRINTER Class Initialize](#printer_class_initialize) +- [PRINTER Class Configuration Options](#printer_class_configuration_options) +- [PRINTER Class APIs](#printer_class_apis) + +## printer_class_initialize + A printer compliant device framework needs to be declared by the device stack. An example is found here below. ```c @@ -1948,12 +2194,14 @@ The initialization of the printer class is as follows. ```c /* Set the parameters for callback when insertion/extraction of a printer device. */ -_ux_utility_memory_set(&device_printer_parameter, 0, sizeof(device_printer_parameter)); -_ux_utility_short_put_big_endian(printer_device_id, sizeof(printer_device_id)); -device_printer_parameter.ux_device_class_printer_device_id = printer_device_id; -device_printer_parameter.ux_device_class_printer_instance_activate = test_printer_instance_activate; -device_printer_parameter.ux_device_class_printer_instance_deactivate = test_printer_instance_deactivate; -device_printer_parameter.ux_device_class_printer_soft_reset = test_printer_soft_reset; +ux_utility_memory_set(&device_printer_parameter, 0, sizeof(device_printer_parameter)); +ux_utility_short_put_big_endian(printer_device_id, sizeof(printer_device_id)); + +device_printer_parameter.ux_device_class_printer_device_id = printer_device_id; +device_printer_parameter.ux_device_class_printer_instance_activate = demo_printer_instance_activate; +device_printer_parameter.ux_device_class_printer_instance_deactivate = demo_printer_instance_deactivate; +device_printer_parameter.ux_device_class_printer_soft_reset = demo_printer_soft_reset; + /* Initialize the device printer class. This class owns both interfaces starting with 0. */ status = ux_device_stack_class_register(_ux_system_device_class_printer_name, ux_device_class_printer_entry, @@ -1981,13 +2229,13 @@ In above example, The Generic/Text driver is selected, then RAW text will be tra The application would have in its body the 2 functions for activation and deactivation, as shown in the following example. ```c -static VOID test_printer_instance_activate(VOID *dummy_instance) +static VOID demo_printer_instance_activate(VOID *dummy_instance) { if (device_printer == UX_NULL) device_printer = (UX_DEVICE_CLASS_PRINTER *)dummy_instance; } -static VOID test_printer_instance_deactivate(VOID *dummy_instance) +static VOID demo_printer_instance_deactivate(VOID *dummy_instance) { if ((VOID*)device_printer == dummy_instance) device_printer = UX_NULL; @@ -2006,8 +2254,25 @@ The USBX printer class supports the following standard printer commands from the | GET_PORT_STATUS | 0x01 | Get the printer port status, the port status can be set by UX_DEVICE_CLASS_PRINTER_IOCTL_PORT_STATUS_SET | | SOFT_RESET | 0x02 | Request to execute soft reset, the reset callback function is assigned by initialization parameter | +## printer_class_configuration_options + +There are several configuration options for building USB Device PRINTER Class. All options are located in the ***ux_user.h***. + +| Configuration Option | Description | +| ------------------------------------------------- | ----------- | +| **UX_DEVICE_CLASS_PRINTER_ZERO_COPY** | This macro enables zero copy support (works if PRINTER owns endpoint buffer). Defined, it enables zero copy for bulk in/out endpoints (write/read). In this case, the endpoint buffer is not allocated in class, application must provide the buffer for read/write, and the buffer must meet device controller driver (DCD) buffer requirements (e.g., aligned and cache safe if buffer is for DMA). | +| **UX_DEVICE_CLASS_PRINTER_WRITE_AUTO_ZLP** | class _write is pending ZLP automatically (complete transfer) after buffer is sent. | + +## printer_class_apis + The printer class API functions are defined below. +- [ux_device_class_printer_read](#ux_device_class_printer_read) +- [ux_device_class_printer_read_run](#ux_device_class_printer_read_run) +- [ux_device_class_printer_write](#ux_device_class_printer_write) +- [_ux_device_class_printer_write_run](#_ux_device_class_printer_write_run) +- [ux_device_class_printer_ioctl](#ux_device_class_printer_ioctl) + ### ux_device_class_printer_read Read from printer pipe @@ -2015,7 +2280,7 @@ Read from printer pipe ### Prototype ```c -UINT _ux_device_class_printer_read( +UINT ux_device_class_printer_read( UX_DEVICE_CLASS_PRINTER *printer, UCHAR *buffer, ULONG requested_length, @@ -2052,6 +2317,61 @@ if (status != UX_SUCCESS) return; ``` +### ux_device_class_printer_read_run + +Read from printer pipe, It's for standalone mode. + +### Prototype + +```c +UINT ux_device_class_printer_read_run( + UX_DEVICE_CLASS_PRINTER *printer, + UCHAR *buffer, + ULONG requested_length, + ULONG *actual_length); +``` + +### 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. + +> **Note:** This functions reads raw bulk data from device, so it keeps pending until buffer is full or device terminates the transfer by a short packet (including Zero Length Packet). For more details, please refer to [**General Considerations for Bulk Transfer**](usbx-device-stack-5.md#general-considerations-for-bulk-transfer). + +### Parameters + +- **printer**: Pointer to the printer class instance. +- **buffer**: Buffer address where data will be stored. +- **requested_length**: The maximum length we expect. +- **actual_length**: The length returned into the buffer. + +### Return Value +- **UX_STATE_NEXT** Transfer done, to next state. +- **UX_STATE_EXIT** Abnormal, to reset state. +- **(others)** Keep running, waiting. + +### Example + +```c +/* Write to the printer class bulk in pipe. */ +status = ux_device_class_printer_read_run(device_printer, device_buffer, sizeof(device_buffer), &actual_length); + +if (status < UX_STATE_NEXT) + return; + +if (status == UX_STATE_NEXT) +{ + if (actual_length == 0) + { + printer_device_state = UX_STATE_RESET; + break; + } + write_length = actual_length; + printer_device_state = PRINTER_DEVICE_STATE_WRITE; + device_buffer_length = actual_length; +} + +``` + ### ux_device_class_printer_write Write to a printer pipe @@ -2059,7 +2379,7 @@ Write to a printer pipe ### Prototype ```c -UINT _ux_device_class_printer_write( +UINT ux_device_class_printer_write( UX_DEVICE_CLASS_PRINTER *printer, UCHAR *buffer, ULONG requested_length, @@ -2094,6 +2414,56 @@ if (status != UX_SUCCESS) return; ``` +### ux_device_class_printer_write_run + +Write to a printer pipe, It's for standalone mode. + +### Prototype + +```c +UINT ux_device_class_printer_write_run( + UX_DEVICE_CLASS_PRINTER *printer, + UCHAR *buffer, + ULONG requested_length, + ULONG *actual_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). It is blocking. + +> **Note:** This function writes bulk data to host. The host keeps waiting until buffer is full or there is short packet. So if transfer size is multiple of max packet size of the IN endpoint, it's better to add another call with transfer size 0 to send ZLP, to tell host that all data is done. For more details, please refer to [**General Considerations for Bulk Transfer**](usbx-device-stack-5.md#general-considerations-for-bulk-transfer). + +### Parameters + +- **printer**: Pointer to the printer class instance. +- **buffer**: Buffer address where data is stored. +- **requested_length**: The length of the buffer to write. +- **actual_length**: The length returned into the buffer after write is performed. + +### Return Value +- **UX_STATE_NEXT** Transfer done, to next state. +- **UX_STATE_EXIT** Abnormal, to reset state. +- **(others)** Keep running, waiting. + +### Example + +```c + +status = ux_device_class_printer_write_run(device_printer, device_buffer, write_length, &actual_length); + +if (status < UX_STATE_NEXT) +{ + return; +} +if (status == UX_STATE_NEXT) +{ + printer_device_state = PRINTER_DEVICE_STATE_READ; + break; +} + +``` + ### ux_device_class_printer_ioctl Perform IOCTL on the printer interface diff --git a/rtos-docs/usbx/usbx-device-stack-supplemental-4.md b/rtos-docs/usbx/usbx-device-stack-supplemental-4.md index 766f27f..d59f00f 100644 --- a/rtos-docs/usbx/usbx-device-stack-supplemental-4.md +++ b/rtos-docs/usbx/usbx-device-stack-supplemental-4.md @@ -51,20 +51,10 @@ Unlike other USBX device implementations, the Pictbridge application does not ne ```C /* Initialize the Pictbridge string components. */ -ux_utility_memory_copy - (pictbridge.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_vendor_name, - "ExpressLogic",13); - -ux_utility_memory_copy - (pictbridge.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_product_name, - "EL_Pictbridge_Camera",21); - -ux_utility_memory_copy - (pictbridge.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_serial_no, "ABC_123",7); - -ux_utility_memory_copy - (pictbridge.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dpsversions, - "1.0 1.1",7); +ux_utility_memory_copy(pictbridge.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_vendor_name, "ExpressLogic",13); +ux_utility_memory_copy(pictbridge.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_product_name, "EL_Pictbridge_Camera",21); +ux_utility_memory_copy(pictbridge.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_serial_no, "ABC_123",7); +ux_utility_memory_copy(pictbridge.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dpsversions, "1.0 1.1",7); pictbridge.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_vendor_specific_version = 0x0100; @@ -78,16 +68,11 @@ if(status != UX_SUCCESS) The parameters passed to the pictbridge client are as follows. ```C -pictbridge.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_vendor_name - : String of Vendor name -pictbridge.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_product_name - : String of product name -pictbridge.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_serial_no - : String of serial number -pictbridge.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dpsversions - : String of version -pictbridge.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_vendor_specific_version - : Value set to 0x0100; +pictbridge.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_vendor_name : String of Vendor name +pictbridge.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_product_name : String of product name +pictbridge.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_serial_no : String of serial number +pictbridge.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dpsversions : String of version +pictbridge.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_vendor_specific_version : Value set to 0x0100; ``` The next step is for the device and the host to synchronize and be ready to exchange information. @@ -97,8 +82,8 @@ This is done by waiting on an event flag as follows. ```C /* We should wait for the host and the client to discover one another. */ status = ux_utility_event_flags_get(&pictbridge.ux_pictbridge_event_flags_group, - UX_PICTBRIDGE_EVENT_FLAG_DISCOVERY,TX_AND_CLEAR, - &actual_flags, UX_PICTBRIDGE_EVENT_TIMEOUT); + UX_PICTBRIDGE_EVENT_FLAG_DISCOVERY,TX_AND_CLEAR, + &actual_flags, UX_PICTBRIDGE_EVENT_TIMEOUT); ``` If the state machine is in the **DISCOVERY_COMPLETE** state, the camera side (the DPS client) will gather information regarding the printer and its capabilities. @@ -107,8 +92,7 @@ If the DPS client is ready to accept a print job, its status will be set to **UX ```C /* Check if the printer is ready for a print job. */ -if (pictbridge.ux_pictbridge_dpsclient.ux_pictbridge_devinfo_newjobok == - UX_PICTBRIDGE_NEW_JOB_TRUE) +if (pictbridge.ux_pictbridge_dpsclient.ux_pictbridge_devinfo_newjobok == UX_PICTBRIDGE_NEW_JOB_TRUE) /* We can print something … */ ``` @@ -122,54 +106,37 @@ jobinfo = &pictbridge.ux_pictbridge_jobinfo; jobinfo -> ux_pictbridge_jobinfo_printinfo_start = &printinfo; /* Set the default values for print job. */ -jobinfo -> ux_pictbridge_jobinfo_quality = - UX_PICTBRIDGE_QUALITIES_DEFAULT; -jobinfo -> ux_pictbridge_jobinfo_papersize = - UX_PICTBRIDGE_PAPER_SIZES_DEFAULT; -jobinfo -> ux_pictbridge_jobinfo_papertype = - UX_PICTBRIDGE_PAPER_TYPES_DEFAULT; -jobinfo -> ux_pictbridge_jobinfo_filetype = - UX_PICTBRIDGE_FILE_TYPES_DEFAULT; -jobinfo -> ux_pictbridge_jobinfo_dateprint = - UX_PICTBRIDGE_DATE_PRINTS_DEFAULT; -jobinfo -> ux_pictbridge_jobinfo_filenameprint = - UX_PICTBRIDGE_FILE_NAME_PRINTS_DEFAULT; -jobinfo -> ux_pictbridge_jobinfo_imageoptimize = - UX_PICTBRIDGE_IMAGE_OPTIMIZES_OFF; -jobinfo -> ux_pictbridge_jobinfo_layout = - UX_PICTBRIDGE_LAYOUTS_DEFAULT; -jobinfo -> ux_pictbridge_jobinfo_fixedsize = - UX_PICTBRIDGE_FIXED_SIZE_DEFAULT; -jobinfo -> ux_pictbridge_jobinfo_cropping = - UX_PICTBRIDGE_CROPPINGS_DEFAULT; +jobinfo -> ux_pictbridge_jobinfo_quality = UX_PICTBRIDGE_QUALITIES_DEFAULT; +jobinfo -> ux_pictbridge_jobinfo_papersize = UX_PICTBRIDGE_PAPER_SIZES_DEFAULT; +jobinfo -> ux_pictbridge_jobinfo_papertype = UX_PICTBRIDGE_PAPER_TYPES_DEFAULT; +jobinfo -> ux_pictbridge_jobinfo_filetype = UX_PICTBRIDGE_FILE_TYPES_DEFAULT; +jobinfo -> ux_pictbridge_jobinfo_dateprint = UX_PICTBRIDGE_DATE_PRINTS_DEFAULT; +jobinfo -> ux_pictbridge_jobinfo_filenameprint = UX_PICTBRIDGE_FILE_NAME_PRINTS_DEFAULT; +jobinfo -> ux_pictbridge_jobinfo_imageoptimize = UX_PICTBRIDGE_IMAGE_OPTIMIZES_OFF; +jobinfo -> ux_pictbridge_jobinfo_layout = UX_PICTBRIDGE_LAYOUTS_DEFAULT; +jobinfo -> ux_pictbridge_jobinfo_fixedsize = UX_PICTBRIDGE_FIXED_SIZE_DEFAULT; +jobinfo -> ux_pictbridge_jobinfo_cropping = UX_PICTBRIDGE_CROPPINGS_DEFAULT; /* Program the callback function for reading the object data. */ -jobinfo -> ux_pictbridge_jobinfo_object_data_read = - ux_demo_object_data_copy; +jobinfo -> ux_pictbridge_jobinfo_object_data_read = ux_demo_object_data_copy; /* This is a demo, the fileID is hardwired (1 and 2 for scripts, 3 for photo to be printed. */ -printinfo.ux_pictbridge_printinfo_fileid = - UX_PICTBRIDGE_OBJECT_HANDLE_PRINT; -ux_utility_memory_copy(printinfo.ux_pictbridge_printinfo_filename, - "Pictbridge demo file", 20); -ux_utility_memory_copy(printinfo.ux_pictbridge_printinfo_date, "01/01/2008", - 10); +printinfo.ux_pictbridge_printinfo_fileid = UX_PICTBRIDGE_OBJECT_HANDLE_PRINT; +ux_utility_memory_copy(printinfo.ux_pictbridge_printinfo_filename, "Pictbridge demo file", 20); +ux_utility_memory_copy(printinfo.ux_pictbridge_printinfo_date, "01/01/2008", 10); /* Fill in the object info to be printed. First get the pointer to the object container in the job info structure. */ -object = (UX_SLAVE_CLASS_PIMA_OBJECT *) jobinfo -> - ux_pictbridge_jobinfo_object; +object = (UX_SLAVE_CLASS_PIMA_OBJECT *) jobinfo -> ux_pictbridge_jobinfo_object; /* Store the object format: JPEG picture. */ object -> ux_device_class_pima_object_format = UX_DEVICE_CLASS_PIMA_OFC_EXIF_JPEG; object -> ux_device_class_pima_object_compressed_size = IMAGE_LEN; object -> ux_device_class_pima_object_offset = 0; -object -> ux_device_class_pima_object_handle_id = - UX_PICTBRIDGE_OBJECT_HANDLE_PRINT; +object -> ux_device_class_pima_object_handle_id = UX_PICTBRIDGE_OBJECT_HANDLE_PRINT; object -> ux_device_class_pima_object_length = IMAGE_LEN; /* File name is in Unicode. */ -ux_utility_string_to_unicode("JPEG Image", object -> - ux_device_class_pima_object_filename); +ux_utility_string_to_unicode("JPEG Image", object -> ux_device_class_pima_object_filename); /* And start the job. */ status =ux_pictbridge_dpsclient_api_start_job(&pictbridge); diff --git a/rtos-docs/usbx/usbx-device-stack-supplemental-5.md b/rtos-docs/usbx/usbx-device-stack-supplemental-5.md index 0f2b590..20b337e 100644 --- a/rtos-docs/usbx/usbx-device-stack-supplemental-5.md +++ b/rtos-docs/usbx/usbx-device-stack-supplemental-5.md @@ -12,20 +12,20 @@ The regular controller driver functions (host or device) can still be found in t There are four categories of functions for an OTG controller in addition to the usual host/device functions. -- VBUS specific functions -- Start and Stop of the controller -- USB role manager -- Interrupt handlers +- [VBUS specific functions](#vbus_specific_functions) +- [Start and Stop the controller](#start_and_Stop_the_controller) +- [USB role manager](#usb_role_manager) +- [Interrupt handlers](#interrupt_handlers) -## VBUS functions +## vbus_specific_functions Each controller needs to have a VBUS manager to change the state of VBUS based on power management requirements. Usually, this function only performs turning on or off VBUS. -## Start and Stop the controller +## start_and_Stop_the_controller Unlike a regular USB implementation, OTG requires the host and/or the device stack to be activated and deactivated when the role changes. -## USB role Manager +## usb_role_manager The USB role manager receives commands to change the state of the USB. There are several states that need transitions to and from: @@ -39,7 +39,7 @@ The USB role manager receives commands to change the state of the USB. There are | UX_OTG_SLAVE_TO_IDLE | 5 | Slave device is disconnected | | UX_OTG_SLAVE_TO_HOST | 6 | Role swap from Slave to Host | -## Interrupt handlers +## interrupt_handlers Both host and device controller drivers for OTG needs different interrupt handlers to monitor signals beyond traditional USB interrupts, in particular signals due to SRP and VBUS. @@ -47,8 +47,7 @@ How to initialize a USB OTG controller. We use the NXP LPC3131 as an example her ```C /* Initialize the LPC3131 OTG controller. */ -status = ux_otg_lpc3131_initialize(0x19000000, lpc3131_vbus_function, - tx_demo_change_mode_callback); +status = ux_otg_lpc3131_initialize(0x19000000, lpc3131_vbus_function, demo_change_mode_callback); ``` In this example, we initialize the LPC3131 in OTG mode by passing a VBUS function and a callback for mode change (from host to slave or vice versa). @@ -56,7 +55,8 @@ In this example, we initialize the LPC3131 in OTG mode by passing a VBUS functio The callback function should simply record the new mode and wake up a pending thread to act up the new state. ```C -void tx_demo_change_mode_callback(ULONG mode) { +void demo_change_mode_callback(ULONG mode) +{ /* Simply save the otg mode. */ otg_mode = mode; @@ -95,6 +95,5 @@ For a slave device, there is no command to issue but the slave device can set a ```C /* We are a B device, ask for role swap. The next GET_STATUS from the host will get the status change and do the HNP. */ -_ux_system_otg -> ux_system_otg_slave_role_swap_flag = - UX_OTG_HOST_REQUEST_FLAG; +_ux_system_otg -> ux_system_otg_slave_role_swap_flag = UX_OTG_HOST_REQUEST_FLAG; ``` diff --git a/rtos-docs/usbx/usbx-device-stack-supplemental-6.md b/rtos-docs/usbx/usbx-device-stack-supplemental-6.md new file mode 100644 index 0000000..dd7e9ad --- /dev/null +++ b/rtos-docs/usbx/usbx-device-stack-supplemental-6.md @@ -0,0 +1,459 @@ +--- +title: Chapter 6 - USBX Implement controller driver (DCD) +description: This guide is about how to implement device controller driver (DCD) of specific hardware for USBX. +--- +# Chapter 6 - USBX Implement controller driver (DCD) + +# Device Controller Driver (DCD) + +The device controller driver is a driver layer to provide a unique way to access different USB hardware peripherals. + +## DCD for USBX Device Stack + +The USBX device stack accesses device controller through a unique struct of device controller driver (DCD). +After USBX system initialization (`ux_system_initialize`), the USBX DCD struct (`UX_SLAVE_DCD`) is allocated and can be referenced by +`_ux_system_slave -> ux_system_slave_dcd`. + +## DCD for specific USB controller hardware + +For different USB controller hardware the DCD struct is initialized by specific initialize function, called in application. +The actual implements are then linked for USBX device stack to communicate, so that the USB flow can be performed on actual physical device. +There are three parts in such a interface: +* APIs for application +* APIs for USBX stack +* USB events (callbacks) to call USBX stack + +### APIs for application + +- [_ux_dcd_xxxxx_initialize](#_ux_dcd_xxxxx_initialize) +- [_ux_dcd_xxxx_uninitialize](#_ux_dcd_xxxx_uninitialize) + +#### _ux_dcd_xxxxx_initialize + +The initialize function for specific DCD is called by USBX application, after `ux_system_initialize`, `ux_device_stack_initialize` and `ux_device_stack_class_register`. +It allocates necessary resources for the driver. +Usually DCD operates directly on hardware, so the initialize function initialize hardware and connect USB. + +Implement example is as following: + +```c +/**************************************************************************/ +/* */ +/* DESCRIPTION */ +/* */ +/* This function initializes the USB device controller of the XXXXX */ +/* microcontroller in USBX device system. */ +/* */ +/* INPUT */ +/* */ +/* dcd_io Driver specific parameter 1 */ +/* parameter Driver specific parameter 2 */ +/* */ +/* OUTPUT */ +/* */ +/* Completion Status */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/**************************************************************************/ +UINT _ux_dcd_xxx_initialize(ULONG dcd_io, ULONG parameter) +{ + +UX_SLAVE_DCD *dcd; +UX_DCD_XXXXX *dcd_xxxxx; + + + UX_PARAMETER_NOT_USED(dcd_io); + + /* Get the pointer to the DCD. */ + dcd = &_ux_system_slave -> ux_system_slave_dcd; + + /* The controller initialized here is of XXXXX type. */ + dcd -> ux_slave_dcd_controller_type = UX_DCD_XXXXX_SLAVE_CONTROLLER; + + /* Allocate memory for this XXXXX DCD instance. */ + dcd_xxxxx = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_DCD_XXXXX)); + + /* Check if memory was properly allocated. */ + if(dcd_xxxxx == UX_NULL) + return(UX_MEMORY_INSUFFICIENT); + + /* Set the pointer to the XXXXX DCD. */ + dcd -> ux_slave_dcd_controller_hardware = (VOID *) dcd_xxxxx; + + /* Initialize the function collector for this DCD. */ + dcd -> ux_slave_dcd_function = _ux_dcd_xxxxx_function; + + /* Set the generic DCD owner for the XXXXX DCD. */ + dcd_xxxxx -> ux_dcd_xxxxx_dcd_owner = dcd; + + /* Initialize XXXXX DCD. */ + /* TODO: Initialize XXXXX DCD struct fields. */ + /* TODO: if not initialized in application (after invoking this function), + initialize controller hardware and attach to host. */ + + /* Set the state of the controller to OPERATIONAL now. */ + dcd -> ux_slave_dcd_status = UX_DCD_STATUS_OPERATIONAL; + + /* Return successful completion. */ + return(UX_SUCCESS); +} +``` + +#### _ux_dcd_xxxx_uninitialize (optional) + +The uninitialize function for specific DCD is optional, +since the USB device system is usually enabled and always ready to serve. +In some cases, it is called by USBX application, +if the application needs a way to disconnect USB, completely free resources and uninitialize hardware. +Code example is as following: + +```c +/**************************************************************************/ +/* */ +/* DESCRIPTION */ +/* */ +/* This function uninitializes the USB device controller in USBX */ +/* device system. */ +/* */ +/* INPUT */ +/* */ +/* dcd_io Driver specific parameter 1 */ +/* parameter Driver specific parameter 2 */ +/* */ +/* OUTPUT */ +/* */ +/* Completion Status */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/**************************************************************************/ +UINT _ux_dcd_xxxxx_uninitialize(ULONG dcd_io, ULONG parameter) +{ +UX_SLAVE_DCD *dcd; +UX_DCD_XXXXX *dcd_xxxxx; + UX_PARAMETER_NOT_USED(dcd_io); + UX_PARAMETER_NOT_USED(parameter); + /* Get the pointer to the DCD. */ + dcd = &_ux_system_slave -> ux_system_slave_dcd; + /* Set the state of the controller to HALTED now. */ + dcd -> ux_slave_dcd_status = UX_DCD_STATUS_HALTED; + /* Get controller driver. */ + dcd_xxxxx = (UX_DCD_XXXXX *)dcd -> ux_slave_dcd_controller_hardware; + /* Free XXXXX driver. */ + { + _ux_utility_memory_free(dcd_xxxxx); + dcd -> ux_slave_dcd_controller_hardware = UX_NULL; + } + /* TODO: If not uninitialized in application (after invoking this function), + detach from host and uninitialize the controller. */ + return(UX_SUCCESS); +} +``` + +### Stack APIs for USBX + +#### ux_dcd_xxxxx_function + +In USBX device stack, the commands sent to controller is in a single API call defined as: + +```c +UINT ux_dcd_xxxxx_function(UX_SLAVE_DCD *dcd, UINT cmd, VOID *param); +``` +The commands should be implemented as following: +| command | parameter | description | +| ------------------------------------------- | ------------------------------- | ------------------------------------------------- | +| UX_DCD_TRANSFER_REQUEST/UX_DCD_TRANSFER_RUN | UX_SLAVE_TRANSFER* | Issue a transfer/run transfer state machine | +| UX_DCD_TRANSFER_ABORT | UX_SLAVE_TRANSFER* | Abort on going transfer | +| UX_DCD_CREATE_ENDPOINT | UX_SLAVE_ENDPOINT* | Create a physical endpoint | +| UX_DCD_DESTROY_ENDPOINT | UX_SLAVE_ENDPOINT* | Destroy a physical endpoint | +| UX_DCD_RESET_ENDPOINT | UX_SLAVE_ENDPOINT* | Reset an endpoint | +| UX_DCD_STALL_ENDPOINT | UX_SLAVE_ENDPOINT* | Stall an endpoint | +| UX_DCD_ENDPOINT_STATUS | ULONG | Return status of endpoint (index/address) | +| UX_DCD_SET_DEVICE_ADDRESS | ULONG | Set the device address | +| UX_DCD_CHANGE_STATE | ULONG (UX_DEVICE_REMOTE_WAKEUP) | Change USB state (to remote wakeup) | +| UX_DCD_ISR_PENDING/UX_DCD_TASKS_RUN | - | For standalone, run background task state machine | +Note for command `UX_DCD_CHANGE_STATE`, parameter of `UX_DEVICE_REMOTE_WAKEUP` should be accepted and send remote wakeup signal to host. +Implement example is as following: +```c +/**************************************************************************/ +/* */ +/* DESCRIPTION */ +/* */ +/* This function dispatches the DCD function internally to the XXXXX */ +/* controller in USBX device system. */ +/* */ +/* Following commands are supported: */ +/* - UX_DCD_TRANSFER_REQUEST/UX_DCD_TRANSFER_RUN */ +/* - control transfer: mandatory for all devices; */ +/* - bulk/interrupt/isochronous transfer: optional if needed, e.g., */ +/* bulk is needed by CDC, Mass Storage classes, */ +/* interrupt is needed by HID class, */ +/* isochronous is needed by audio/video classes, etc. */ +/* - UX_DCD_TRANSFER_ABORT */ +/* - UX_DCD_CREATE_ENDPOINT */ +/* - UX_DCD_DESTROY_ENDPOINT */ +/* - UX_DCD_RESET_ENDPOINT */ +/* - UX_DCD_ENDPOINT_STATUS */ +/* - UX_DCD_SET_DEVICE_ADDRESS */ +/* - UX_DCD_CHANGE_STATE */ +/* - UX_DEVICE_REMOTE_WAKEUP: optional if remote wakeup is supported */ +/* - UX_DCD_ISR_PENDING/UX_DCD_TASKS_RUN */ +/* */ +/* INPUT */ +/* */ +/* dcd Pointer to device controller */ +/* function Function requested */ +/* parameter Pointer to function parameters*/ +/* */ +/* OUTPUT */ +/* */ +/* Completion Status */ +/* */ +/* CALLS */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* USBX Device Stack */ +/* */ +/**************************************************************************/ +UINT _ux_dcd_xxxxx_function(UX_SLAVE_DCD *dcd, UINT function, VOID *parameter) +{ +UINT status = UX_FUNCTION_NOT_SUPPORTED; +UX_DCD_XXXXX *dcd_xxxxx; + /* Check the status of the controller. */ + if (dcd -> ux_slave_dcd_status == UX_UNUSED) + { + /* Error trap. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_DCD, UX_CONTROLLER_UNKNOWN); + /* If trace is enabled, insert this event into the trace buffer. */ + UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_CONTROLLER_UNKNOWN, 0, 0, 0, UX_TRACE_ERRORS, 0, 0) + return(UX_CONTROLLER_UNKNOWN); + } + /* Get the pointer to the XXXXX DCD. */ + dcd_xxxxx = (UX_DCD_XXXXX *) dcd -> ux_slave_dcd_controller_hardware; + /* Look at the function and route it. */ + switch(function) + { + case UX_DCD_TRANSFER_REQUEST: + /* TODO: controller level transfer state machine/transfer request, parameter: UX_SLAVE_TRANSFER *transfer. */ + /* Transfer types to support: + Control: mandatory for all devices; + Bulk: optional, for functions that need bulk endpoint (like CDC-ACM, Mass Storage, etc.); + Interrupt: optional, for function that need interrupt endpoint (like HID, CDC-ACM, etc.); + Isochronous: optional, for function that need Isochronous endpoint (like audio, video, etc.). + */ +#if defined(UX_DEVICE_STANDALONE) + /* Must be non-blocking; + in start state: start background transfer and return UX_STATE_NEXT; + in pending state: return UX_STATE_WAIT; + in done state: confirm transfer fields including completion code are updated and return UX_STATE_NEXT. */ + /* ...... */ +#else + /* control request: start background transfer for data stage followed by status stage. + /* non-control: it's blocking, start background transfer and wait transfer->ux_slave_transfer_request_semaphore. */ + /* ...... */ +#endif + break; + case UX_DCD_TRANSFER_ABORT: + /* TODO: controller level transfer abort, parameter: UX_SLAVE_TRANSFER *transfer. */ + /* ...... */ + break; + case UX_DCD_CREATE_ENDPOINT: + /* TODO: controller level endpoint create, parameter: UX_SLAVE_ENDPOINT *endpoint. */ + /* ...... */ + break; + case UX_DCD_DESTROY_ENDPOINT: + /* TODO: controller level endpoint destroy, parameter: UX_SLAVE_ENDPOINT *endpoint. */ + /* ...... */ + break; + case UX_DCD_RESET_ENDPOINT: + /* TODO: controller level endpoint reset to clear halt and reset toggle, parameter: UX_SLAVE_ENDPOINT *endpoint. */ + /* ...... */ + break; + case UX_DCD_STALL_ENDPOINT: + /* TODO: controller level endpoint stall, parameter: UX_SLAVE_ENDPOINT *endpoint. */ + /* ...... */ + break; + case UX_DCD_SET_DEVICE_ADDRESS: + /* TODO: update hardware to set address of the device, parameter: ULONG address. */ + /* ...... */ + break; + case UX_DCD_CHANGE_STATE: + /* TODO: actively change USB state in controller level, parameter: ULONG state. It could be: + - UX_DEVICE_REMOTE_WAKEUP: send remote wakeup signal on USB bus (if device needs the feature). */ + /* ...... */ + break; + case UX_DCD_ENDPOINT_STATUS: + /* TODO: get endpoint status (stall).. */ + /* If UX_DEVICE_BIDIRECTIONAL_ENDPOINT_SUPPORT is defined parameter is ULONG endpoint_address, + which kept endpoint direction, in this case both 0x81 and 0x01 are accepted as different + endpoints addresses. + Otherwise, parameter is ULONG endpoint_index, which removes endpoint direction, in this case + address of 0x81 and 0x01 both pass index 0x01 as parameter, so the index must be unique. */ + /* ...... */ + break; +#if defined(UX_DEVICE_STANDALONE) + case UX_DCD_TASKS_RUN: + /* TODO: controller level background tasks running. */ + /* ...... */ + status = UX_SUCCESS; + break; +#endif + default: + /* Error trap. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_DCD, status); + /* If trace is enabled, insert this event into the trace buffer. */ + UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, status, 0, 0, 0, UX_TRACE_ERRORS, 0, 0) + break; + } + /* Return completion status. */ + return(status); +} +``` + +### Events CALLs to USBX + +Following USBX device stack function should be called in event handling: + +#### ux_device_stack_control_request_process(UX_SLAVE_TRANSFER *) + +* Control SETUP received and IN (device to host) data is expected +* Control SETUP received and there is no OUT (host to device) data +* Control SETUP received and OUT data also received + +E.g., for a DCD based on STM32 HAL, the code reference could be: + +```c +void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd) +{ + /* ...... */ + + /* Check if the transaction is IN. */ + if (*transfer_request -> ux_slave_transfer_request_setup & UX_REQUEST_IN) + { + + /* ...... */ + + /* Call the Control Transfer dispatcher. */ + _ux_device_stack_control_request_process(transfer_request); + + } + else + { + /* ....... */ + + /* We are in a OUT transaction. Check if there is a data payload. If so, wait for the payload + to be delivered. */ + if (*(transfer_request -> ux_slave_transfer_request_setup + 6) == 0 && + *(transfer_request -> ux_slave_transfer_request_setup + 7) == 0) + { + + /* Call the Control Transfer dispatcher. */ + _ux_device_stack_control_request_process(transfer_request); + + /* TODO: start background control request status phase. */ + /* ...... */ + } + else + { + /* TODO: start background control request data OUT transfer, + when transfer/partial transfer is done, HAL_PCD_DataOutStageCallback is triggered. */ + /* ...... */ + } + } +} +void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) +{ + /* Endpoint 0 is the control endpoint. */ + if (epnum == 0U) + { + /* Check if we have received something on control endpoint during data phase . */ + if (ed -> ux_dcd_stm32_ed_state == UX_DCD_STM32_ED_STATE_DATA_RX) + { + /* Are we done with this transfer ? */ + if ((transfer_request -> ux_slave_transfer_request_actual_length == + transfer_request -> ux_slave_transfer_request_requested_length) || + (transfer_length != endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize)) + { + /* ...... */ + + _ux_device_stack_control_request_process(transfer_request); + } + } + } + +} +``` +#### ux_device_stack_disconnect(void) + +* A USB bus reset happen in not reset states. +* A USB bus disconnect happen in not reset states +E.g., for a DCD based on STM32 HAL, the code reference could be: +```c +void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd) +{ + /* If the device is attached or configured, we need to disconnect it. */ + if (_ux_system_slave -> ux_system_slave_device.ux_slave_device_state != UX_DEVICE_RESET) + { + /* Disconnect the device. */ + _ux_device_stack_disconnect(); + } + /* Put the device in attached default state. */ + /* ...... */ +} +void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd) +{ + /* Check if the device is attached or configured. */ + if (_ux_system_slave -> ux_system_slave_device.ux_slave_device_state != UX_DEVICE_RESET) + { + /* Disconnect the device. */ + _ux_device_stack_disconnect(); + } +} +``` + +#### _ux_system_slave -> ux_system_slave_speed and _ux_system_slave -> ux_system_slave_device.ux_slave_device_state + +* Updated when USB bus reset is done + +E.g., for a DCD based on STM32 HAL, the code reference could be: +```c +void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd) +{ + + /* ...... */ + + /* Set USB Current Speed */ + switch(hpcd -> Init.speed) + { + case PCD_SPEED_HIGH: + + /* We are connected at high speed. */ + _ux_system_slave -> ux_system_slave_speed = UX_HIGH_SPEED_DEVICE; + break; + + case PCD_SPEED_FULL: + + /* We are connected at full speed. */ + _ux_system_slave -> ux_system_slave_speed = UX_FULL_SPEED_DEVICE; + break; + + default: + + /* We are connected at full speed. */ + _ux_system_slave -> ux_system_slave_speed = UX_FULL_SPEED_DEVICE; + break; + } + + /* ...... */ + + /* Mark the device as attached now. */ + _ux_system_slave -> ux_system_slave_device.ux_slave_device_state = UX_DEVICE_ATTACHED; +} +``` \ No newline at end of file diff --git a/rtos-docs/usbx/usbx-device-stack-supplemental-7.md b/rtos-docs/usbx/usbx-device-stack-supplemental-7.md new file mode 100644 index 0000000..52f1292 --- /dev/null +++ b/rtos-docs/usbx/usbx-device-stack-supplemental-7.md @@ -0,0 +1,303 @@ +--- +title: Chapter 6 - USBX Implement device class modules +description: This guide is about how to implement device class modules for specific device classes/functions in USBX. +--- +# Chapter 6 - USBX Implement device class modules + +# Device Class Layer (ux_device_class) + +The device class layer is the class layer above device stack layer. +It provides a unique way for different classes/functions to communicate with USBX device stack, +and provides class/function specific APIs for the application usages. + +## USBX Device Class + +The USBX device stack accesses device class/function modules through a unique struct of `UX_SLAVE_CLASS`. +It's the container for specific (local) class modules. It's allocated on USBX device stack initialization, and can be referenced as `_ux_system_slave -> ux_system_slave_class_array`. + +## USBX Device Class Module for specific class/function + +For different USB class/function the device class struct is linked to specific class entry function, called by USBX device stack. +The actual implements then handles the commands from USBX device stack, to: +* initialize/uninitialize the class/function; +* query if the class/function is supported; +* activate/deactivate the class/function; +* process class specific requests received; +* handle the interface alternate setting change. + +The device class module may also provide application APIs and/or callbacks to perform class specific data/control exchange with application. + +### USBX Device Class Entry for Device Stack + +The device class/function module must provide an entry function. It's a parameter for `ux_device_stack_class_register` to register the class module on device stack and do initialization. It dispatches commands from USBX device stack for standard and class specific host requests handling. + +The prototype for the function is: +```c +UINT _ux_device_class_xxxxx_entry(UX_SLAVE_CLASS_COMMAND *command); +``` +The command data is encapsulated in a struct of `UX_SLAVE_CLASS_COMMAND`, where `ux_slave_class_command_request` holds the device stack command to process and others are parameters for the command, the possible commands are: +| request | _interface | _class/_subclass/_protocol | _class_ptr | _parameter | Description | +| ---------------------------------------------- | --------------------- | -------------------------- | ----------------- | ------------ | ----------------------------------------------------------- | +| UX_SLAVE_CLASS_COMMAND_INITIALIZE | not used | not used | (UX_SLAVE_CLASS*) | (VOID*)param | Initialize class/function module instance | +| UX_SLAVE_CLASS_COMMAND_QUERY | (UX_SLAVE_INTERFACE*) | ULONG | (UX_SLAVE_CLASS*) | not used | Query if class/subclass/protocol is supported | +| UX_SLAVE_CLASS_COMMAND_ACTIVATE | (UX_SLAVE_INTERFACE*) | ULONG | (UX_SLAVE_CLASS*) | not used | Activate local class/function instance | +| UX_SLAVE_CLASS_COMMAND_DEACTIVATE | (UX_SLAVE_INTERFACE*) | not used | not used | not used | Deactivate notification | +| UX_SLAVE_CLASS_COMMAND_REQUEST (optional) | not used | not used | (UX_SLAVE_CLASS*) | not used | Handle class/vendor requests from host (if needed) | +| UX_SLAVE_CLASS_COMMAND_CHANGE (optional) | (UX_SLAVE_INTERFACE*) | not used | (UX_SLAVE_CLASS*) | not used | Interface alternate setting change notification (if needed) | +| UX_SLAVE_CLASS_COMMAND_UNINITIALIZE (optional) | not used | not used | (UX_SLAVE_CLASS*) | not used | Uninitialize class/function module instance | + +The function entry implement example is as following: + +```c +/**************************************************************************/ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the entry point of the xxxxx class. It */ +/* will be called by the device stack when the host has sent specific */ +/* request and the xxxxx class/function needs to be processed. */ +/* */ +/* INPUT */ +/* */ +/* command Pointer to class command */ +/* */ +/* OUTPUT */ +/* */ +/* Completion Status */ +/* */ +/* CALLS */ +/* */ +/* CALLED BY */ +/* */ +/* USBX Device Stack */ +/* */ +/**************************************************************************/ +UINT _ux_device_class_xxxxx_entry(UX_SLAVE_CLASS_COMMAND *command) +{ +UINT status; + /* The command request will tell us we need to do here, either a enumeration + query, an activation or a deactivation, etc. */ + switch (command -> ux_slave_class_command_request) + { + case UX_SLAVE_CLASS_COMMAND_INITIALIZE: + /* TODO: Initialize the device class/function instance. */ + /* Allocates instance memory and other related resources and initialize them. */ + /* Link the instance to container so it can be referenced. */ + /* ...... */ + return(status); + case UX_SLAVE_CLASS_COMMAND_UNINITIALIZE: + /* TODO: uninitialize the device class/function instance. */ + /* Uninitialize, free the resources and release instance memory. */ + /* ...... */ + return(status); + case UX_SLAVE_CLASS_COMMAND_QUERY: + /* TODO: check class and/or subclass and/or protocol to see if it's supported. */ + if (command -> ux_slave_class_command_class == UX_DEVICE_CLASS_XXXXX_CLASS) + return(UX_SUCCESS); + else + return(UX_NO_CLASS_MATCH); + case UX_SLAVE_CLASS_COMMAND_ACTIVATE: + /* TODO: activate the device class/function instance. */ + /* The activate command is used when the host has sent a SET_CONFIGURATION command and this interface has to be mounted. */ + /* Mandatory endpoints have to be mounted and the class thread needs to be activated if needed. */ + /* If instance activation is success and there is notification callback, notify application. */ + /* ...... */ + return(status); + case UX_SLAVE_CLASS_COMMAND_CHANGE: + /* TODO: notify that the interface alternate setting has been changed (optional). */ + /* The change command is used when the host has sent a SET_INTERFACE command + to go from Alternate Setting 0 to >0 or revert to the default mode (0). */ + /* ...... */ + return(status); + case UX_SLAVE_CLASS_COMMAND_DEACTIVATE: + /* TODO: deactivate the device class/function instance (optional). */ + /* The deactivate command is used when the device has been extracted. */ + /* The instance endpoints have to be dismounted and the class thread canceled. */ + /* If there is notification callback, notify application. */ + /* ...... */ + return(status); + case UX_SLAVE_CLASS_COMMAND_REQUEST: + /* TODO: handle host class/vendor requests (optional). */ + /* The request command is used when the host sends a command on the control endpoint. */ + /* ...... */ + return(status); + default: + /* If trace is enabled, insert this event into the trace buffer. */ + UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_FUNCTION_NOT_SUPPORTED, 0, 0, 0, UX_TRACE_ERRORS, 0, 0) + /* Return an error. */ + return(UX_FUNCTION_NOT_SUPPORTED); + } +} +``` + +#### UX_SLAVE_CLASS_COMMAND_INITIALIZE + +The initialize command implement example is as following: + +```c + /* ...... */ + + /* Get the pointer to the application parameters for the xxxxx class. */ + xxxxx_parameter = command -> ux_slave_class_command_parameter; + + /* Get the class container. */ + class_ptr = command -> ux_slave_class_command_class_ptr; + + /* Create an instance of the device xxxxx class. */ + xxxxx = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_SLAVE_CLASS_xxxxx)); + + /* Check for successful allocation. */ + if (xxxxx == UX_NULL) + return(UX_MEMORY_INSUFFICIENT); + + /* Save the address of the xxxxx instance inside the container. */ + class_ptr -> ux_slave_class_instance = (VOID *) xxxxx; + + /* TODO: class/function specific initialization. */ + /* ...... */ +``` + +#### UX_SLAVE_CLASS_COMMAND_QUERY + +The query command implement example is as following: + +```c + if (command -> ux_slave_class_command_class == UX_DEVICE_CLASS_XXXXX_CLASS && + command -> ux_slave_class_command_subclass == UX_DEVICE_CLASS_XXXXX_SUBCLASS && + command -> ux_slave_class_command_protocol == UX_DEVICE_CLASS_XXXXX_PROTOCOL) + return(UX_SUCCESS); + else + return(UX_NO_CLASS_MATCH); +``` + +#### UX_SLAVE_CLASS_COMMAND_ACTIVATE + +The activate command implement example is as following: + +```c + /* ...... */ + + /* Get the class container. */ + class_ptr = command -> ux_slave_class_command_class_ptr; + + /* Get the class instance in the container. */ + xxxxx = (UX_SLAVE_CLASS_xxxxx *) class_ptr -> ux_slave_class_instance; + + /* Get the interface that owns this instance. */ + interface_ptr = (UX_SLAVE_INTERFACE *) command -> ux_slave_class_command_interface; + + /* Store the class instance into the interface. */ + interface_ptr -> ux_slave_interface_class_instance = (VOID *)xxxxx; + + /* Now the opposite, store the interface in the class instance. */ + xxxxx -> ux_slave_class_xxxxx_interface = interface_ptr; + + /* TODO: class/function specific activations, such as: + * - Activate class and function specific threads. + * - Activate function specific endpoints. + * - Other class/function specific preparations, etc. + */ + /* ...... */ +``` + +#### UX_SLAVE_CLASS_COMMAND_DEACTIVATE + +The deactivate command implement example is as following: + +```c +UINT _ux_device_class_xxxxx_deactivate(UX_SLAVE_CLASS_COMMAND *command) +{ + /* ...... */ + + /* Get the class container. */ + class_ptr = command -> ux_slave_class_command_class_ptr; + + /* Get the class instance in the container. */ + xxxxx = (UX_DEVICE_CLASS_XXXXXX *) class_ptr -> ux_slave_class_instance; + + /* TODO: class/function specific deactivations, such as: + * - Cancel pending transfers; + * - Notify application; + * - etc. + */ + /* ...... */ +} +``` +#### UX_SLAVE_CLASS_COMMAND_REQUEST + +The request command is optional. +It is implemented if the class/function needs to process class/vendor requests from host, +implement example is as following: + +```c + /* ...... */ + /* Get the pointer to the device. */ + device = &_ux_system_slave -> ux_system_slave_device; + /* Get the pointer to the transfer request associated with the control endpoint. */ + transfer_request = &device -> ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request; + /* Get the class container. */ + class_ptr = command -> ux_slave_class_command_class_ptr; + + /* Get the storage instance from this class container. */ + xxxxx = (UX_DEVICE_CLASS_XXXXX *) class_ptr -> ux_slave_class_instance; + /* TODO: handle setup request from host. */ + /* ...... */ +``` + +#### UX_SLAVE_CLASS_COMMAND_CHANGE + +The change command is optional. +It is implemented if the class/function needs different interface alternate settings. +implement example is as following: + +```c + /* ...... */ + + /* Get the class container. */ + class_ptr = command -> ux_slave_class_command_class_ptr; + + /* Get the class instance in the container. */ + xxxxx = (UX_SLAVE_CLASS_XXXXX *) class_ptr -> ux_slave_class_instance; + + /* Get the interface that owns this instance. */ + interface_ptr = (UX_SLAVE_INTERFACE *) command -> ux_slave_class_command_interface; + + /* Check alternate settings. */ + if (interface_ptr -> ux_slave_interface_descriptor.bAlternateSetting != 0) + { + /* TODO: non-zero alternate setting. */ + } + else + { + /* TODO: zero alternate setting. */ + } + + /* ...... */ +``` +#### UX_SLAVE_CLASS_COMMAND_UNINITIALIZE + +The uninitialize command is optional. +It is implemented in purpose to free all resources for the class/function support. +implement example is as following: + +```c + /* ...... */ + /* Get the class container. */ + class_ptr = command -> ux_slave_class_command_class_ptr; + /* Get the class instance in the container. */ + hid = (UX_SLAVE_CLASS_HID *) class_ptr -> ux_slave_class_instance; + /* TODO: Free resources, like + * - Delete threads, semaphores, mutexes, etc. + * - Free memories allocated for instance and the instnace memory; + * - etc. + */ + /* ...... */ +``` + +## Other considerations + +### Memory management + +To avoid memory fragmentation, it's recommended to allocate as much as memories in initialize instead of in activation. + +Also if the system does not need USB system deinitialization, it's not necessary to process the command of uninitialize. \ No newline at end of file