From 232e89f35b3714d735e3d44c33c0cf419de74504 Mon Sep 17 00:00:00 2001 From: Tiejun Zhou Date: Wed, 26 Oct 2022 23:43:22 +0000 Subject: [PATCH] Release 6.2.0 --- README.md | 139 ++-- common/core/inc/ux_api.h | 26 +- common/core/inc/ux_user_sample.h | 25 +- ...host_stack_configuration_instance_create.c | 30 +- ...host_stack_configuration_instance_delete.c | 14 +- .../core/src/ux_host_stack_hcd_thread_entry.c | 0 .../core/src/ux_host_stack_hcd_unregister.c | 0 .../src/ux_host_stack_rh_change_process.c | 0 common/core/src/ux_host_stack_tasks_run.c | 39 +- .../ux_host_stack_transfer_request_abort.c | 11 +- common/core/src/ux_utility_delay_ms.c | 0 common/usbx_device_classes/CMakeLists.txt | 10 + .../inc/ux_device_class_audio.h | 49 +- .../inc/ux_device_class_cdc_ecm.h | 14 +- .../inc/ux_device_class_printer.h | 42 +- .../inc/ux_device_class_rndis.h | 18 +- .../inc/ux_device_class_video.h | 26 +- .../src/ux_device_class_audio_activate.c | 11 +- .../src/ux_device_class_audio_change.c | 21 +- ...evice_class_audio_feedback_task_function.c | 164 +++++ ...device_class_audio_feedback_thread_entry.c | 11 +- .../src/ux_device_class_audio_initialize.c | 58 +- .../ux_device_class_audio_interrupt_send.c | 11 +- ...vice_class_audio_interrupt_task_function.c | 198 +++++ ...ux_device_class_audio_read_task_function.c | 188 +++++ .../ux_device_class_audio_read_thread_entry.c | 7 +- .../ux_device_class_audio_reception_start.c | 13 +- .../src/ux_device_class_audio_tasks_run.c | 153 ++++ ...ux_device_class_audio_transmission_start.c | 13 +- ...x_device_class_audio_write_task_function.c | 210 ++++++ ...ux_device_class_audio_write_thread_entry.c | 11 +- .../src/ux_device_class_cdc_acm_read_run.c | 7 +- .../src/ux_device_class_cdc_acm_tasks_run.c | 15 +- .../src/ux_device_class_cdc_acm_write_run.c | 9 +- .../ux_device_class_cdc_ecm_bulkin_thread.c | 31 +- .../ux_device_class_cdc_ecm_bulkout_thread.c | 76 +- .../src/ux_device_class_cdc_ecm_initialize.c | 34 +- .../ux_device_class_cdc_ecm_uninitialize.c | 11 +- .../src/ux_device_class_hid_control_request.c | 0 .../src/ux_device_class_hid_initialize.c | 10 +- .../src/ux_device_class_printer_initialize.c | 17 +- .../src/ux_device_class_printer_read_run.c | 238 ++++++ .../src/ux_device_class_printer_soft_reset.c | 11 +- .../ux_device_class_printer_uninitialize.c | 9 +- .../src/ux_device_class_printer_write_run.c | 258 +++++++ .../src/ux_device_class_rndis_bulkin_thread.c | 46 +- .../ux_device_class_rndis_bulkout_thread.c | 119 +-- .../src/ux_device_class_rndis_initialize.c | 38 +- .../src/ux_device_class_storage_tasks_run.c | 24 +- .../src/ux_device_class_video_activate.c | 13 +- .../src/ux_device_class_video_change.c | 14 +- .../src/ux_device_class_video_initialize.c | 28 +- ...ux_device_class_video_read_task_function.c | 188 +++++ .../ux_device_class_video_read_thread_entry.c | 6 +- .../ux_device_class_video_reception_start.c | 19 +- .../src/ux_device_class_video_tasks_run.c | 113 +++ ...ux_device_class_video_transmission_start.c | 22 +- ...x_device_class_video_write_task_function.c | 209 ++++++ ...ux_device_class_video_write_thread_entry.c | 11 +- .../inc/ux_host_class_asix.h | 78 +- .../inc/ux_host_class_cdc_ecm.h | 19 +- .../inc/ux_host_class_hid_keyboard.h | 8 +- .../inc/ux_host_class_storage.h | 0 .../src/ux_host_class_asix_activate.c | 49 +- .../src/ux_host_class_asix_deactivate.c | 23 +- .../src/ux_host_class_asix_endpoints_get.c | 27 +- .../src/ux_host_class_asix_entry.c | 43 +- ...x_host_class_asix_interrupt_notification.c | 59 +- .../ux_host_class_asix_reception_callback.c | 10 +- .../src/ux_host_class_asix_thread.c | 695 +++++++++++------- ...ux_host_class_asix_transmission_callback.c | 54 +- .../src/ux_host_class_asix_write.c | 124 +++- .../src/ux_host_class_cdc_ecm_activate.c | 189 ++--- .../src/ux_host_class_cdc_ecm_deactivate.c | 19 +- .../ux_host_class_cdc_ecm_mac_address_get.c | 19 +- .../src/ux_host_class_cdc_ecm_thread.c | 113 ++- ...host_class_cdc_ecm_transmission_callback.c | 26 +- .../src/ux_host_class_cdc_ecm_write.c | 55 +- .../ux_host_class_hid_keyboard_tasks_run.c | 24 +- .../src/ux_host_class_hub_entry.c | 9 +- .../src/ux_host_class_hub_tasks_run.c | 36 +- .../src/ux_host_class_storage_entry.c | 0 .../src/ux_host_class_storage_media_open.c | 15 +- .../ux_host_class_storage_partition_read.c | 0 .../src/ux_host_class_storage_tasks_run.c | 56 +- .../src/ux_host_class_storage_transport_run.c | 13 +- .../src/ux_host_class_video_activate.c | 16 +- .../ux_host_class_video_frame_interval_get.c | 0 .../usbx_host_controllers/inc/ux_hcd_ehci.h | 0 .../usbx_host_controllers/inc/ux_hcd_ohci.h | 0 ...ux_hcd_ehci_asynchronous_endpoint_create.c | 0 .../src/ux_hcd_ehci_done_queue_process.c | 0 .../ux_hcd_ehci_hsisochronous_tds_process.c | 0 .../ux_hcd_ehci_interrupt_endpoint_create.c | 0 .../ux_hcd_ehci_interrupt_endpoint_destroy.c | 0 .../ux_hcd_ehci_isochronous_endpoint_create.c | 0 ...ux_hcd_ehci_isochronous_endpoint_destroy.c | 0 .../src/ux_hcd_ehci_least_traffic_list_get.c | 0 .../src/ux_hcd_ehci_periodic_tree_create.c | 0 .../src/ux_hcd_ehci_poll_rate_entry_get.c | 0 .../ux_hcd_ehci_request_control_transfer.c | 0 .../src/ux_hcd_ehci_transfer_abort.c | 0 .../src/ux_hcd_ohci_endpoint_error_clear.c | 0 .../src/ux_hcd_ohci_endpoint_reset.c | 0 .../ux_hcd_ohci_periodic_endpoint_destroy.c | 0 .../src/ux_hcd_ohci_port_resume.c | 0 .../src/ux_hcd_ohci_port_suspend.c | 0 .../src/ux_hcd_ohci_power_down_port.c | 0 .../src/ux_hcd_ohci_power_on_port.c | 0 .../src/ux_hcd_ohci_power_root_hubs.c | 0 .../ux_hcd_ohci_request_control_transfer.c | 0 .../src/ux_hcd_ohci_transfer_abort.c | 0 docs/usbx-features.png | Bin 0 -> 317752 bytes ports/arm9/gnu/inc/ux_port.h | 2 +- ports/arm9/iar/inc/ux_port.h | 2 +- ports/cortex_a15/gnu/inc/ux_port.h | 2 +- ports/cortex_a5/gnu/inc/ux_port.h | 2 +- ports/cortex_a5/iar/inc/ux_port.h | 2 +- ports/cortex_a5x/ac6/inc/ux_port.h | 2 +- ports/cortex_a7/gnu/inc/ux_port.h | 2 +- ports/cortex_a7/iar/inc/ux_port.h | 2 +- ports/cortex_a8/gnu/inc/ux_port.h | 2 +- ports/cortex_a8/iar/inc/ux_port.h | 2 +- ports/cortex_a9/gnu/inc/ux_port.h | 2 +- ports/cortex_a9/iar/inc/ux_port.h | 2 +- ports/cortex_m0/gnu/inc/ux_port.h | 2 +- ports/cortex_m0/iar/inc/ux_port.h | 2 +- ports/cortex_m3/gnu/inc/ux_port.h | 2 +- ports/cortex_m3/iar/inc/ux_port.h | 2 +- ports/cortex_m4/gnu/inc/ux_port.h | 2 +- ports/cortex_m4/iar/inc/ux_port.h | 2 +- ports/cortex_m7/gnu/inc/ux_port.h | 2 +- ports/cortex_m7/iar/inc/ux_port.h | 2 +- ports/cortex_r4/gnu/inc/ux_port.h | 2 +- ports/cortex_r4/iar/inc/ux_port.h | 2 +- ports/cortex_r5/gnu/inc/ux_port.h | 2 +- ports/cortex_r5/iar/inc/ux_port.h | 2 +- ports/generic/inc/ux_port.h | 2 +- ports/linux/gnu/inc/ux_port.h | 2 +- 139 files changed, 3942 insertions(+), 977 deletions(-) mode change 100755 => 100644 common/core/inc/ux_api.h mode change 100755 => 100644 common/core/src/ux_host_stack_hcd_thread_entry.c mode change 100755 => 100644 common/core/src/ux_host_stack_hcd_unregister.c mode change 100755 => 100644 common/core/src/ux_host_stack_rh_change_process.c mode change 100755 => 100644 common/core/src/ux_utility_delay_ms.c create mode 100644 common/usbx_device_classes/src/ux_device_class_audio_feedback_task_function.c create mode 100644 common/usbx_device_classes/src/ux_device_class_audio_interrupt_task_function.c create mode 100644 common/usbx_device_classes/src/ux_device_class_audio_read_task_function.c create mode 100644 common/usbx_device_classes/src/ux_device_class_audio_tasks_run.c create mode 100644 common/usbx_device_classes/src/ux_device_class_audio_write_task_function.c mode change 100755 => 100644 common/usbx_device_classes/src/ux_device_class_hid_control_request.c create mode 100644 common/usbx_device_classes/src/ux_device_class_printer_read_run.c create mode 100644 common/usbx_device_classes/src/ux_device_class_printer_write_run.c create mode 100644 common/usbx_device_classes/src/ux_device_class_video_read_task_function.c create mode 100644 common/usbx_device_classes/src/ux_device_class_video_tasks_run.c create mode 100644 common/usbx_device_classes/src/ux_device_class_video_write_task_function.c mode change 100755 => 100644 common/usbx_host_classes/inc/ux_host_class_storage.h mode change 100755 => 100644 common/usbx_host_classes/src/ux_host_class_storage_entry.c mode change 100755 => 100644 common/usbx_host_classes/src/ux_host_class_storage_partition_read.c mode change 100755 => 100644 common/usbx_host_classes/src/ux_host_class_video_frame_interval_get.c mode change 100755 => 100644 common/usbx_host_controllers/inc/ux_hcd_ehci.h mode change 100755 => 100644 common/usbx_host_controllers/inc/ux_hcd_ohci.h mode change 100755 => 100644 common/usbx_host_controllers/src/ux_hcd_ehci_asynchronous_endpoint_create.c mode change 100755 => 100644 common/usbx_host_controllers/src/ux_hcd_ehci_done_queue_process.c mode change 100755 => 100644 common/usbx_host_controllers/src/ux_hcd_ehci_hsisochronous_tds_process.c mode change 100755 => 100644 common/usbx_host_controllers/src/ux_hcd_ehci_interrupt_endpoint_create.c mode change 100755 => 100644 common/usbx_host_controllers/src/ux_hcd_ehci_interrupt_endpoint_destroy.c mode change 100755 => 100644 common/usbx_host_controllers/src/ux_hcd_ehci_isochronous_endpoint_create.c mode change 100755 => 100644 common/usbx_host_controllers/src/ux_hcd_ehci_isochronous_endpoint_destroy.c mode change 100755 => 100644 common/usbx_host_controllers/src/ux_hcd_ehci_least_traffic_list_get.c mode change 100755 => 100644 common/usbx_host_controllers/src/ux_hcd_ehci_periodic_tree_create.c mode change 100755 => 100644 common/usbx_host_controllers/src/ux_hcd_ehci_poll_rate_entry_get.c mode change 100755 => 100644 common/usbx_host_controllers/src/ux_hcd_ehci_request_control_transfer.c mode change 100755 => 100644 common/usbx_host_controllers/src/ux_hcd_ehci_transfer_abort.c mode change 100755 => 100644 common/usbx_host_controllers/src/ux_hcd_ohci_endpoint_error_clear.c mode change 100755 => 100644 common/usbx_host_controllers/src/ux_hcd_ohci_endpoint_reset.c mode change 100755 => 100644 common/usbx_host_controllers/src/ux_hcd_ohci_periodic_endpoint_destroy.c mode change 100755 => 100644 common/usbx_host_controllers/src/ux_hcd_ohci_port_resume.c mode change 100755 => 100644 common/usbx_host_controllers/src/ux_hcd_ohci_port_suspend.c mode change 100755 => 100644 common/usbx_host_controllers/src/ux_hcd_ohci_power_down_port.c mode change 100755 => 100644 common/usbx_host_controllers/src/ux_hcd_ohci_power_on_port.c mode change 100755 => 100644 common/usbx_host_controllers/src/ux_hcd_ohci_power_root_hubs.c mode change 100755 => 100644 common/usbx_host_controllers/src/ux_hcd_ohci_request_control_transfer.c mode change 100755 => 100644 common/usbx_host_controllers/src/ux_hcd_ohci_transfer_abort.c create mode 100644 docs/usbx-features.png diff --git a/README.md b/README.md index d0165cdb..edf9d047 100755 --- a/README.md +++ b/README.md @@ -2,106 +2,105 @@ A high-performance USB host, device, and on-the-go (OTG) embedded stack, Azure RTOS USBX is fully integrated with Azure RTOS ThreadX and available for all Azure RTOS ThreadX–supported processors. Like Azure RTOS ThreadX, Azure RTOS USBX is designed to have a small footprint and high performance, making it ideal for deeply embedded applications that require an interface with USB devices. -## Documentation +Here are the key features and modules of USBX: -Documentation for this library can be found here: http://docs.microsoft.com/azure/rtos/usbx +![USBX Key Features](./docs/usbx-features.png) -# Understanding inter-component dependencies +## Getting Started -The main components of Azure RTOS are each provided in their own repository, but there are dependencies between them--shown in the following graph--that are important to understand when setting up your builds. +Azure RTOS USBX as part of Azure RTOS has been integrated to the semiconductor's SDKs and development environment. You can develop using the tools of choice from [STMicroelectronics](https://www.st.com/content/st_com/en/campaigns/x-cube-azrtos-azure-rtos-stm32.html), [NXP](https://www.nxp.com/design/software/embedded-software/azure-rtos-for-nxp-microcontrollers:AZURE-RTOS), [Renesas](https://github.com/renesas/azure-rtos) and [Microchip](https://mu.microchip.com/get-started-simplifying-your-iot-design-with-azure-rtos). -![dependency graph](docs/deps.png) +We also provide [samples](https://github.com/azure-rtos/samples) using hero development boards from semiconductors you can build and test with. -# Building and using the library +See [Overview of Azure RTOS USBX](https://learn.microsoft.com/azure/rtos/usbx/overview-usbx) for the high-level overview, and all documentation and APIs can be found in: [Azure RTOS USBX documentation](https://learn.microsoft.com/azure/rtos/usbx/). -## Prerequisites +## Repository Structure and Usage -Install the following tools: +### Directory layout -* [CMake](https://cmake.org/download/) version 3.0 or later -* [GCC compilers for arm-none-eabi](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads) -* [Ninja](https://ninja-build.org/) + . + ├── cmake # CMakeList files for building the project + ├── common # Core USBX files + ├── ports # Architecture and compiler specific files + ├── samples # Sample codes + ├── support # Misc platform configurations file used by USBX + ├── LICENSE.txt # License terms + ├── LICENSE-HARDWARE.txt # Licensed hardware from semiconductors + ├── CONTRIBUTING.md # Contribution guidance + └── SECURITY.md # Microsoft repo security guidance -## Cloning the repo +### Branches & Releases -```bash -$ git clone https://github.com/azure-rtos/usbx.git -``` +The master branch has the most recent code with all new features and bug fixes. It does not represent the latest General Availability (GA) release of the library. Each official release (preview or GA) will be tagged to mark the commit and push it into the Github releases tab, e.g. `v6.2-rel`. -## Building as a static library +## Component dependencies -Each component of Azure RTOS comes with a composible CMake-based build system that supports many different MCUs and host systems. Integrating any of these components into your device app code is as simple as adding a git submodule and then including it in your build using the CMake command `add_subdirectory()`. +The main components of Azure RTOS are each provided in their own repository, but there are dependencies between them, as shown in the following graph. This is important to understand when setting up your builds. -While the typical usage pattern is to include threadx into your device code source tree to be built & linked with your code, you can compile this project as a standalone static library to confirm your build is set up correctly. +![dependency graph](docs/deps.png) -```bash -$ cmake -Bbuild -DCMAKE_TOOLCHAIN_FILE=cmake/cortex_m4.cmake -GNinja . +> You will have to take the dependency graph above into account when building anything other than ThreadX itself. -$ cmake --build ./build -``` +### Building and using the library -NOTE: You will have to take the dependency graph above into account when building anything other than threadx itself. +Instruction for building the USBX as static library using Arm GNU Toolchain and CMake. If you are using toolchain and IDE from semiconductor, you might follow its own instructions to use Azure RTOS components as explained in the [Getting Started](#getting-started) section. -# Repository Structure and Usage +1. Install the following tools: -## Branches & Releases + * [CMake](https://cmake.org/download/) version 3.0 or later + * [Arm GNU Toolchain for arm-none-eabi](https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads) + * [Ninja](https://ninja-build.org/) -The master branch has the most recent code with all new features and bug fixes. It does not represent the latest General Availability (GA) release of the library. +1. Build the [ThreadX library](https://github.com/azure-rtos/threadx#building-and-using-the-library) as the dependency. -## Releases +1. Cloning the repo. -Each official release (preview or GA) will be tagged to mark the commit and push it into the Github releases tab, e.g. `v6.0-rel`. + ```bash + $ git clone https://github.com/azure-rtos/usbx.git + ``` -## Directory layout +1. Define the features and addons you need in `ux_user.h` and build together with the component source code. You can refer to [`ux_user_sample.h`](https://github.com/azure-rtos/usbx/blob/master/common/core/inc/ux_user_sample.h) as an example. -``` -- cmake -- common - - inc - - src -- ports - - cortex_m0/gnu - - inc - - src - - cortex_m3/gnu - - inc - - src - - cortex_m4/gnu - - inc - - src - - cortex_m7/gnu - - inc - - src -- samples -``` +1. Building as a static library -# Security + Each component of Azure RTOS comes with a composable CMake-based build system that supports many different MCUs and host systems. Integrating any of these components into your device app code is as simple as adding a git submodule and then including it in your build using the CMake `add_subdirectory()`. -Azure RTOS provides OEMs with components to secure communication and to create code and data isolation using underlying MCU/MPU hardware protection mechanisms. It is ultimately the responsibility of the device builder to ensure the device fully meets the evolving security requirements associated with its specific use case. + While the typical usage pattern is to include USBX into your device code source tree to be built & linked with your code, you can compile this project as a standalone static library to confirm your build is set up correctly. + + An example of building the library for Cortex-M4: + + ```bash + $ cmake -Bbuild -GNinja -DCMAKE_TOOLCHAIN_FILE=cmake/cortex_m4.cmake . + + $ cmake --build ./build + ``` -# Licensing +## Professional support -License terms for using Azure RTOS are defined in the LICENSE.txt file of this repo. Please refer to this file for all definitive licensing information. No additional license fees are required for deploying Azure RTOS on hardware defined in the LICENSED-HARDWARE.txt file. If you are using hardware not defined in the LICENSED-HARDWARE.txt file or have licensing questions in general, please contact Microsoft directly at https://aka.ms/azrtos-license. +[Professional support plans](https://azure.microsoft.com/support/options/) are available from Microsoft. For community support and others, see the [Resources](#resources) section below. -# Contribution, feedback, issues, and professional support +## Licensing -If you encounter any bugs, have suggestions for new features, or if you would like to become an active contributor to this project, please follow the instructions provided in the contribution guideline for the corresponding repo. +License terms for using Azure RTOS are defined in the LICENSE.txt file of this repo. Please refer to this file for all definitive licensing information. No additional license fees are required for deploying Azure RTOS on hardware defined in the [LICENSED-HARDWARE.txt](./LICENSED-HARDWARE.txt) file. If you are using hardware not listed in the file or having licensing questions in general, please contact Microsoft directly at https://aka.ms/azrtos-license. -For basic support, click Issues in the command bar or post a question to [Stack Overflow](http://stackoverflow.com/questions/tagged/azure-rtos+threadx) using the `threadx` and `azure-rtos` tags. +## Resources -Professional support plans (https://azure.microsoft.com/en-us/support/options/) are available from Microsoft. +The following are references to additional Azure RTOS resources: + +- **Product introduction and white papers**: https://azure.com/rtos +- **General technical questions**: https://aka.ms/QnA/azure-rtos +- **Product issues and bugs, or feature requests**: https://github.com/azure-rtos/usbx/issues +- **Licensing and sales questions**: https://aka.ms/azrtos-license +- **Product roadmap and support policy**: https://aka.ms/azrtos/lts +- **Blogs and videos**: http://msiotblog.com and https://aka.ms/iotshow +- **Azure RTOS TraceX Installer**: https://aka.ms/azrtos-tracex-installer + +You can also check [previous questions](https://stackoverflow.com/questions/tagged/azure-rtos+usbx) or ask new ones on StackOverflow using the `azure-rtos` and `usbx` tags. + +## Security + +Azure RTOS provides OEMs with components to secure communication and to create code and data isolation using underlying MCU/MPU hardware protection mechanisms. It is ultimately the responsibility of the device builder to ensure the device fully meets the evolving security requirements associated with its specific use case. -# Additional Resources +## Contribution -The following are references to additional Azure RTOS and Azure IoT in general: -| Content | Link | -|---|---| -| TraceX Installer | https://aka.ms/azrtos-tracex-installer | -| Azure RTOS Documentation and Guides: | https://docs.microsoft.com/azure/rtos | -| Azure RTOS Website: | https://azure.microsoft.com/services/rtos/ | -| Azure RTOS Sales Questions: | https://aka.ms/azrtos-license | -| Azure RTOS Product Support Policy | https://aka.ms/azrtos/lts | -| Azure RTOS Functional Safety Artifacts | https://aka.ms/azrtos/tuv | -| For technical questions check out Microsoft Q/A for Azure IoT | https://aka.ms/QnA/azure-rtos | -| Internet of Things Show for latest announcements and online training | https://aka.ms/iotshow | -| IoT Tech Community | https://aka.ms/community/azure-rtos | +Please follow the instructions provided in the [CONTRIBUTING.md](./CONTRIBUTING.md) for the corresponding repository. diff --git a/common/core/inc/ux_api.h b/common/core/inc/ux_api.h old mode 100755 new mode 100644 index b8f0c6eb..cb83675c --- a/common/core/inc/ux_api.h +++ b/common/core/inc/ux_api.h @@ -26,7 +26,7 @@ /* APPLICATION INTERFACE DEFINITION RELEASE */ /* */ /* ux_api.h PORTABLE C */ -/* 6.1.12 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -122,6 +122,12 @@ /* added shared device config */ /* descriptor for enum scan, */ /* resulting in version 6.1.12 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* added some ETH error codes, */ +/* allowed align minimal def, */ +/* added interface instance */ +/* creation strategy control, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ @@ -288,8 +294,8 @@ typedef signed char SCHAR; /* Define basic constants for the USBX Stack. */ #define AZURE_RTOS_USBX #define USBX_MAJOR_VERSION 6 -#define USBX_MINOR_VERSION 1 -#define USBX_PATCH_VERSION 12 +#define USBX_MINOR_VERSION 2 +#define USBX_PATCH_VERSION 0 /* Macros for concatenating tokens, where UX_CONCATn concatenates n tokens. */ @@ -1102,7 +1108,6 @@ VOID _ux_trace_event_update(TX_TRACE_BUFFER_ENTRY *event, ULONG timestamp, UL #define UX_NO_ALIGN 0u #define UX_ALIGN_16 0x0fu -#define UX_ALIGN_MIN 0x0fu #define UX_ALIGN_32 0x1fu #define UX_ALIGN_64 0x3fu #define UX_ALIGN_128 0x7fu @@ -1113,6 +1118,9 @@ VOID _ux_trace_event_update(TX_TRACE_BUFFER_ENTRY *event, ULONG timestamp, UL #define UX_ALIGN_4096 0xfffu #define UX_SAFE_ALIGN 0xffffffffu #define UX_MAX_SCATTER_GATHER_ALIGNMENT 4096 +#ifndef UX_ALIGN_MIN +#define UX_ALIGN_MIN UX_ALIGN_16 +#endif #define UX_MAX_USB_DEVICES 127 @@ -1483,6 +1491,10 @@ VOID _ux_trace_event_update(TX_TRACE_BUFFER_ENTRY *event, ULONG timestamp, UL #define UX_HOST_CLASS_AUDIO_WRONG_FREQUENCY 0x82 #define UX_CLASS_CDC_ECM_LINK_STATE_DOWN_ERROR 0x90 +#define UX_CLASS_ETH_LINK_STATE_DOWN_ERROR 0x90 +#define UX_CLASS_ETH_PACKET_POOL_ERROR 0x91 +#define UX_CLASS_ETH_PACKET_ERROR 0x92 +#define UX_CLASS_ETH_SIZE_ERROR 0x93 /* Define USBX HCD API function constants. */ @@ -2049,6 +2061,12 @@ typedef struct UX_CONFIGURATION_STRUCT ULONG ux_configuration_iad_protocol; } UX_CONFIGURATION; +#define UX_HOST_STACK_CONFIGURATION_INSTANCE_CREATE_ALL 0 /* Default: all things created. */ +#define UX_HOST_STACK_CONFIGURATION_INSTANCE_CREATE_OWNED 1 /* Owned: class owned things created. */ +#ifndef UX_HOST_STACK_CONFIGURATION_INSTANCE_CREATE_CONTROL +#define UX_HOST_STACK_CONFIGURATION_INSTANCE_CREATE_CONTROL UX_HOST_STACK_CONFIGURATION_INSTANCE_CREATE_ALL +#endif + /* Define USBX Interface Descriptor structure. */ diff --git a/common/core/inc/ux_user_sample.h b/common/core/inc/ux_user_sample.h index 0df602e1..72a7e5e8 100644 --- a/common/core/inc/ux_user_sample.h +++ b/common/core/inc/ux_user_sample.h @@ -26,7 +26,7 @@ /* PORT SPECIFIC C INFORMATION RELEASE */ /* */ /* ux_user.h PORTABLE C */ -/* 6.1.12 */ +/* 6.2.0 */ /* */ /* AUTHOR */ /* */ @@ -83,6 +83,12 @@ /* added device CDC_ACM and */ /* printer write auto ZLP, */ /* resulting in version 6.1.12 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* deprecated ECM pool option, */ +/* added align minimal config, */ +/* added host stack instance */ +/* creation strategy control, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ @@ -116,6 +122,10 @@ /* Override various options with default values already assigned in ux_api.h or ux_port.h. Please also refer to ux_port.h for descriptions on each of these options. */ +/* Defined, this value represents minimal allocated memory alignment in number of bytes. + The default is UX_ALIGN_16 (0x0f) to align allocated memory to 16 bytes. */ +/* #define UX_ALIGN_MIN UX_ALIGN_16 */ + /* Defined, this value represents how many ticks per seconds for a specific hardware platform. The default is 1000 indicating 1 tick per millisecond. */ @@ -317,7 +327,9 @@ /* #define UX_HOST_CLASS_CDC_ECM_PACKET_POOL_INSTANCE_WAIT 10 */ -/* Defined, this enables CDC ECM class to use the packet pool from NetX instance. */ +/* Defined, this enables CDC ECM class to use the packet pool from NetX instance. + It's deprecated, packet pool from NetX instance is always used now. + */ /* #define UX_HOST_CLASS_CDC_ECM_USE_PACKET_POOL_FROM_NETX */ @@ -427,6 +439,15 @@ /* Defined, host audio optional interrupt endpoint is support. */ /* #define UX_HOST_CLASS_AUDIO_INTERRUPT_SUPPORT */ +/* Defined, this value controls host configuration instance creation, include all + interfaces and endpoints physical resources. + Possible settings: + UX_HOST_STACK_CONFIGURATION_INSTANCE_CREATE_ALL (0) - The default, create all inside configuration. + UX_HOST_STACK_CONFIGURATION_INSTANCE_CREATE_OWNED (1) - Create things owned by class driver. + Not defined, default setting is applied. + */ +/* #define UX_HOST_STACK_CONFIGURATION_INSTANCE_CREATE_CONTROL UX_HOST_STACK_CONFIGURATION_INSTANCE_CREATE_OWNED */ + /* Defined, this value will only enable the host side of usbx. */ /* #define UX_HOST_SIDE_ONLY */ diff --git a/common/core/src/ux_host_stack_configuration_instance_create.c b/common/core/src/ux_host_stack_configuration_instance_create.c index 678b5b5b..7d44c07c 100644 --- a/common/core/src/ux_host_stack_configuration_instance_create.c +++ b/common/core/src/ux_host_stack_configuration_instance_create.c @@ -34,7 +34,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_host_stack_configuration_instance_create PORTABLE C */ -/* 6.1.12 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -72,6 +72,10 @@ /* fixed parameter/variable */ /* names conflict C++ keyword, */ /* resulting in version 6.1.12 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* added interface instance */ +/* creation strategy control, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_host_stack_configuration_instance_create(UX_CONFIGURATION *configuration) @@ -93,15 +97,21 @@ UINT status; /* Check if we are dealing with the first alternate setting. */ if (interface_ptr -> ux_interface_descriptor.bAlternateSetting == 0) { - /* Create the interface. */ - status = _ux_host_stack_interface_instance_create(interface_ptr); - - /* Check status, the controller may have refused the endpoint creation. */ - if (status != UX_SUCCESS) - - /* An error occurred. The interface cannot be mounted. */ - return(status); - + +#if UX_HOST_STACK_CONFIGURATION_INSTANCE_CREATE_CONTROL == UX_HOST_STACK_CONFIGURATION_INSTANCE_CREATE_OWNED + + /* Create the interface, if it's usable. */ + if (interface_ptr -> ux_interface_class || configuration -> ux_configuration_device -> ux_device_class) +#endif + { + status = _ux_host_stack_interface_instance_create(interface_ptr); + + /* Check status, the controller may have refused the endpoint creation. */ + if (status != UX_SUCCESS) + + /* An error occurred. The interface cannot be mounted. */ + return(status); + } } /* Next interface. */ diff --git a/common/core/src/ux_host_stack_configuration_instance_delete.c b/common/core/src/ux_host_stack_configuration_instance_delete.c index 9413c697..5834e0d4 100644 --- a/common/core/src/ux_host_stack_configuration_instance_delete.c +++ b/common/core/src/ux_host_stack_configuration_instance_delete.c @@ -34,7 +34,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_host_stack_configuration_instance_delete PORTABLE C */ -/* 6.1.12 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -72,6 +72,10 @@ /* fixed parameter/variable */ /* names conflict C++ keyword, */ /* resulting in version 6.1.12 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* added interface instance */ +/* creation strategy control, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ VOID _ux_host_stack_configuration_instance_delete(UX_CONFIGURATION *configuration) @@ -102,7 +106,13 @@ ULONG current_alternate_setting; if (interface_ptr -> ux_interface_descriptor.bAlternateSetting == current_alternate_setting) { - _ux_host_stack_interface_instance_delete(interface_ptr); + +#if UX_HOST_STACK_CONFIGURATION_INSTANCE_CREATE_CONTROL == UX_HOST_STACK_CONFIGURATION_INSTANCE_CREATE_OWNED + + /* If interface is usable, remove physical creates. */ + if (interface_ptr -> ux_interface_class || configuration -> ux_configuration_device -> ux_device_class) +#endif + _ux_host_stack_interface_instance_delete(interface_ptr); } interface_ptr = interface_ptr -> ux_interface_next_interface; diff --git a/common/core/src/ux_host_stack_hcd_thread_entry.c b/common/core/src/ux_host_stack_hcd_thread_entry.c old mode 100755 new mode 100644 diff --git a/common/core/src/ux_host_stack_hcd_unregister.c b/common/core/src/ux_host_stack_hcd_unregister.c old mode 100755 new mode 100644 diff --git a/common/core/src/ux_host_stack_rh_change_process.c b/common/core/src/ux_host_stack_rh_change_process.c old mode 100755 new mode 100644 diff --git a/common/core/src/ux_host_stack_tasks_run.c b/common/core/src/ux_host_stack_tasks_run.c index a867411c..6363268b 100644 --- a/common/core/src/ux_host_stack_tasks_run.c +++ b/common/core/src/ux_host_stack_tasks_run.c @@ -44,7 +44,7 @@ static inline VOID _ux_host_stack_pending_transfers_run(VOID); /* FUNCTION RELEASE */ /* */ /* _ux_host_stack_tasks_run PORTABLE C */ -/* 6.1.12 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -105,6 +105,11 @@ static inline VOID _ux_host_stack_pending_transfers_run(VOID); /* used shared descriptor in */ /* device instance for enum, */ /* resulting in version 6.1.12 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* improved internal logic, */ +/* fixed activation issue on */ +/* no class linked interfaces, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_host_stack_tasks_run(VOID) @@ -376,7 +381,12 @@ UX_INTERFACE *interface_inst; device -> ux_device_class : device -> ux_device_enum_inst.interface -> ux_interface_class; command -> ux_host_class_command_request = UX_HOST_CLASS_COMMAND_ACTIVATE_WAIT; - status = command -> ux_host_class_command_class_ptr -> ux_host_class_entry_function(command); + + /* If there is no class linked, just next state. */ + if (command -> ux_host_class_command_class_ptr != UX_NULL) + status = command -> ux_host_class_command_class_ptr -> ux_host_class_entry_function(command); + else + status = UX_STATE_NEXT; /* No wait command or ready for next state. */ if (status == UX_FUNCTION_NOT_SUPPORTED || @@ -435,6 +445,7 @@ UX_TRANSFER *trans; UX_CONFIGURATION *configuration; UX_HOST_CLASS_COMMAND class_command; UCHAR *buffer; +INT immediate_state = UX_TRUE; /* Check if the device enumeration should be processed. */ if ((device -> ux_device_flags & UX_DEVICE_FLAG_ENUM) == 0) @@ -457,7 +468,7 @@ UCHAR *buffer; } UX_RESTORE - while (1) + while (immediate_state) { switch (device -> ux_device_enum_state) { @@ -911,12 +922,17 @@ UCHAR *buffer; class_command.ux_host_class_command_class_ptr = device -> ux_device_enum_inst.interface -> ux_interface_class; } - status = class_command.ux_host_class_command_class_ptr -> - ux_host_class_entry_function(&class_command); - if (status != UX_SUCCESS) + + /* If there class linked, start activation. */ + if (class_command.ux_host_class_command_class_ptr != UX_NULL) { - device -> ux_device_enum_state = UX_HOST_STACK_ENUM_RETRY; - continue; + status = class_command.ux_host_class_command_class_ptr -> + ux_host_class_entry_function(&class_command); + if (status != UX_SUCCESS) + { + device -> ux_device_enum_state = UX_HOST_STACK_ENUM_RETRY; + continue; + } } /* Class activate execute wait. */ @@ -1078,8 +1094,11 @@ UCHAR *buffer; device -> ux_device_enum_state = UX_STATE_RESET; } - /* Run once anyway. */ - break; + /* Invalid unhandled state. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HOST_STACK, UX_INVALID_STATE); + + /* Break the immediate state loop. */ + immediate_state = UX_FALSE; } } diff --git a/common/core/src/ux_host_stack_transfer_request_abort.c b/common/core/src/ux_host_stack_transfer_request_abort.c index 58591e96..ad1c5f76 100644 --- a/common/core/src/ux_host_stack_transfer_request_abort.c +++ b/common/core/src/ux_host_stack_transfer_request_abort.c @@ -34,7 +34,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_host_stack_transfer_request_abort PORTABLE C */ -/* 6.1.10 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -83,6 +83,8 @@ /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */ /* added standalone support, */ /* resulting in version 6.1.10 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_host_stack_transfer_request_abort(UX_TRANSFER *transfer_request) @@ -104,14 +106,17 @@ ULONG completion_code; /* Check pending transaction. */ if (transfer_request -> ux_transfer_request_completion_code == UX_TRANSFER_STATUS_PENDING) { - + /* Send the abort command to the controller. */ hcd -> ux_hcd_entry_function(hcd, UX_HCD_TRANSFER_ABORT, transfer_request); /* Save the completion code since we're about to set it to ABORT. The reason we can't just assume its value is PENDING is that in between the completion code check and this line, it's possible that the transfer - completed, which would've changed the completion code to SUCCESS. + completed (by HCD function call below, or ISR), which would've + changed the completion code to SUCCESS and put the semaphore. + Even it's recommended to keep completion code untouched to let things + changed later here. Such a case is valid, and we want to make sure we don't put() the transfer request's semaphore again. */ completion_code = transfer_request -> ux_transfer_request_completion_code; diff --git a/common/core/src/ux_utility_delay_ms.c b/common/core/src/ux_utility_delay_ms.c old mode 100755 new mode 100644 diff --git a/common/usbx_device_classes/CMakeLists.txt b/common/usbx_device_classes/CMakeLists.txt index f3c38671..5291d4ba 100644 --- a/common/usbx_device_classes/CMakeLists.txt +++ b/common/usbx_device_classes/CMakeLists.txt @@ -10,14 +10,17 @@ target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_audio_feedback_get.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_audio_feedback_set.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_audio_feedback_thread_entry.c + ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_audio_feedback_task_function.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_audio_frame_write.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_audio_initialize.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_audio_interrupt_send.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_audio_interrupt_thread_entry.c + ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_audio_interrupt_task_function.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_audio_ioctl.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_audio_read_frame_free.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_audio_read_frame_get.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_audio_read_thread_entry.c + ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_audio_read_task_function.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_audio_reception_start.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_audio_sample_read16.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_audio_sample_read24.c @@ -30,6 +33,8 @@ target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_audio_write_frame_commit.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_audio_write_frame_get.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_audio_write_thread_entry.c + ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_audio_write_task_function.c + ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_audio_tasks_run.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_ccid_activate.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_ccid_auto_seq_done.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_ccid_auto_seq_start.c @@ -144,9 +149,11 @@ target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_printer_initialize.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_printer_ioctl.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_printer_read.c + ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_printer_read_run.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_printer_soft_reset.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_printer_uninitialize.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_printer_write.c + ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_printer_write_run.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_rndis_activate.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_rndis_bulkin_thread.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_rndis_bulkout_thread.c @@ -201,13 +208,16 @@ target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_video_max_payload_get.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_video_read_payload_free.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_video_read_payload_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_video_read_task_function.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_video_read_thread_entry.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_video_reception_start.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_video_stream_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_video_tasks_run.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_video_transmission_start.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_video_uninitialize.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_video_write_payload_commit.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_video_write_payload_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_video_write_task_function.c ${CMAKE_CURRENT_LIST_DIR}/src/ux_device_class_video_write_thread_entry.c # {{END_TARGET_SOURCES}} diff --git a/common/usbx_device_classes/inc/ux_device_class_audio.h b/common/usbx_device_classes/inc/ux_device_class_audio.h index 8ce47fa0..4cc5be3a 100644 --- a/common/usbx_device_classes/inc/ux_device_class_audio.h +++ b/common/usbx_device_classes/inc/ux_device_class_audio.h @@ -26,7 +26,7 @@ /* COMPONENT DEFINITION RELEASE */ /* */ /* ux_device_class_audio.h PORTABLE C */ -/* 6.1.12 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -59,6 +59,9 @@ /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */ /* added interrupt support, */ /* resulting in version 6.1.12 */ +/* 10-31-2022 Yajun Xia Modified comment(s), */ +/* added standalone support, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ @@ -310,6 +313,17 @@ extern "C" { #define UX_DEVICE_CLASS_AUDIO_IOCTL_GET_ARG 1 +/* Define Audio Class Task states. */ +#define UX_DEVICE_CLASS_AUDIO_INTERRUPT_STOP (UX_STATE_RESET) +#define UX_DEVICE_CLASS_AUDIO_INTERRUPT_START (UX_STATE_STEP + 1) +#define UX_DEVICE_CLASS_AUDIO_INTERRUPT_WAIT (UX_STATE_STEP + 2) + +#define UX_DEVICE_CLASS_AUDIO_STREAM_RW_STOP (UX_STATE_RESET) +#define UX_DEVICE_CLASS_AUDIO_STREAM_RW_START (UX_STATE_STEP + 1) +#define UX_DEVICE_CLASS_AUDIO_STREAM_RW_WAIT (UX_STATE_STEP + 2) + +#define UX_DEVICE_CLASS_AUDIO_STREAM_FEEDBACK_RW_STOP (UX_STATE_RESET) +#define UX_DEVICE_CLASS_AUDIO_STREAM_FEEDBACK_RW_WAIT (UX_STATE_STEP + 1) /* Define Audio Class callback structure. */ @@ -336,11 +350,20 @@ typedef struct UX_DEVICE_CLASS_AUDIO_STREAM_CALLBACKS_STRUCT typedef struct UX_DEVICE_CLASS_AUDIO_STREAM_PARAMETER_STRUCT { +#if !defined(UX_DEVICE_STANDALONE) ULONG ux_device_class_audio_stream_parameter_thread_stack_size; VOID (*ux_device_class_audio_stream_parameter_thread_entry)(ULONG id); +#else + UINT (*ux_device_class_audio_stream_parameter_task_function)(struct UX_DEVICE_CLASS_AUDIO_STREAM_STRUCT*); +#endif + #if defined(UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT) +#if !defined(UX_DEVICE_STANDALONE) ULONG ux_device_class_audio_stream_parameter_feedback_thread_stack_size; VOID (*ux_device_class_audio_stream_parameter_feedback_thread_entry)(ULONG id); +#else + UINT (*ux_device_class_audio_stream_parameter_feedback_task_function)(struct UX_DEVICE_CLASS_AUDIO_STREAM_STRUCT*); +#endif #endif UX_DEVICE_CLASS_AUDIO_STREAM_CALLBACKS ux_device_class_audio_stream_parameter_callbacks; @@ -386,6 +409,10 @@ typedef struct UX_DEVICE_CLASS_AUDIO_STREAM_STRUCT #if !defined(UX_DEVICE_STANDALONE) UCHAR *ux_device_class_audio_stream_feedback_thread_stack; UX_THREAD ux_device_class_audio_stream_feedback_thread; +#else + UINT (*ux_device_class_audio_stream_feedback_task_function)(struct UX_DEVICE_CLASS_AUDIO_STREAM_STRUCT*); + UINT ux_device_class_audio_stream_feedback_task_state; + UINT ux_device_class_audio_stream_feedback_task_status; #endif #endif @@ -394,11 +421,16 @@ typedef struct UX_DEVICE_CLASS_AUDIO_STREAM_STRUCT #if !defined(UX_DEVICE_STANDALONE) UCHAR *ux_device_class_audio_stream_thread_stack; UX_THREAD ux_device_class_audio_stream_thread; +#else + UINT (*ux_device_class_audio_stream_task_function)(struct UX_DEVICE_CLASS_AUDIO_STREAM_STRUCT*); + UINT ux_device_class_audio_stream_task_state; + UINT ux_device_class_audio_stream_task_status; #endif UCHAR *ux_device_class_audio_stream_buffer; ULONG ux_device_class_audio_stream_buffer_size; ULONG ux_device_class_audio_stream_frame_buffer_size; + ULONG ux_device_class_audio_stream_buffer_error_count; UX_DEVICE_CLASS_AUDIO_FRAME *ux_device_class_audio_stream_transfer_pos; UX_DEVICE_CLASS_AUDIO_FRAME *ux_device_class_audio_stream_access_pos; @@ -429,6 +461,9 @@ typedef struct UX_DEVICE_CLASS_AUDIO_STRUCT #if !defined(UX_DEVICE_STANDALONE) UX_SEMAPHORE ux_device_class_audio_status_semaphore; UX_MUTEX ux_device_class_audio_status_mutex; +#else + UINT ux_device_class_audio_interrupt_task_state; + UINT ux_device_class_audio_interrupt_task_status; #endif #endif } UX_DEVICE_CLASS_AUDIO; @@ -452,7 +487,8 @@ UINT _ux_device_class_audio_stream_get(UX_DEVICE_CLASS_AUDIO *audio, ULONG st VOID _ux_device_class_audio_write_thread_entry(ULONG audio_stream); VOID _ux_device_class_audio_read_thread_entry(ULONG audio_stream); - +UINT _ux_device_class_audio_write_task_function(UX_DEVICE_CLASS_AUDIO_STREAM *stream); +UINT _ux_device_class_audio_read_task_function(UX_DEVICE_CLASS_AUDIO_STREAM *stream); UINT _ux_device_class_audio_reception_start(UX_DEVICE_CLASS_AUDIO_STREAM *audio); UINT _ux_device_class_audio_sample_read8(UX_DEVICE_CLASS_AUDIO_STREAM *audio, UCHAR *sample); UINT _ux_device_class_audio_sample_read16(UX_DEVICE_CLASS_AUDIO_STREAM *audio, USHORT *sample); @@ -469,13 +505,18 @@ UINT _ux_device_class_audio_write_frame_get(UX_DEVICE_CLASS_AUDIO_STREAM *aud UINT _ux_device_class_audio_write_frame_commit(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG length); VOID _ux_device_class_audio_feedback_thread_entry(ULONG audio_stream); +UINT _ux_device_class_audio_feedback_task_function(UX_DEVICE_CLASS_AUDIO_STREAM *stream); UINT _ux_device_class_audio_feedback_set(UX_DEVICE_CLASS_AUDIO_STREAM *audio, UCHAR *encoded_feedback); UINT _ux_device_class_audio_feedback_get(UX_DEVICE_CLASS_AUDIO_STREAM *audio, UCHAR *encoded_feedback); ULONG _ux_device_class_audio_speed_get(UX_DEVICE_CLASS_AUDIO_STREAM *audio); VOID _ux_device_class_audio_interrupt_thread_entry(ULONG audio_inst); +UINT _ux_device_class_audio_interrupt_task_function(UX_DEVICE_CLASS_AUDIO *audio); UINT _ux_device_class_audio_interrupt_send(UX_DEVICE_CLASS_AUDIO *audio, UCHAR *int_data); +#if defined(UX_DEVICE_STANDALONE) +UINT _ux_device_class_audio_tasks_run(VOID *instance); +#endif /* Define Device Class Audio API prototypes. */ @@ -484,6 +525,9 @@ UINT _ux_device_class_audio_interrupt_send(UX_DEVICE_CLASS_AUDIO *audio, UCHA #define ux_device_class_audio_read_thread_entry _ux_device_class_audio_read_thread_entry #define ux_device_class_audio_write_thread_entry _ux_device_class_audio_write_thread_entry +#define ux_device_class_audio_read_task_function _ux_device_class_audio_read_task_function +#define ux_device_class_audio_write_task_function _ux_device_class_audio_write_task_function + #define ux_device_class_audio_stream_get _ux_device_class_audio_stream_get #define ux_device_class_audio_reception_start _ux_device_class_audio_reception_start @@ -505,6 +549,7 @@ UINT _ux_device_class_audio_interrupt_send(UX_DEVICE_CLASS_AUDIO *audio, UCHA #define ux_device_class_audio_speed_get _ux_device_class_audio_speed_get #define ux_device_class_audio_feedback_thread_entry _ux_device_class_audio_feedback_thread_entry +#define ux_device_class_audio_feedback_task_function _ux_device_class_audio_feedback_task_function #define ux_device_class_audio_feedback_get _ux_device_class_audio_feedback_get #define ux_device_class_audio_feedback_set _ux_device_class_audio_feedback_set diff --git a/common/usbx_device_classes/inc/ux_device_class_cdc_ecm.h b/common/usbx_device_classes/inc/ux_device_class_cdc_ecm.h index 3f662d8a..54f3ac77 100644 --- a/common/usbx_device_classes/inc/ux_device_class_cdc_ecm.h +++ b/common/usbx_device_classes/inc/ux_device_class_cdc_ecm.h @@ -24,7 +24,7 @@ /* COMPONENT DEFINITION RELEASE */ /* */ /* ux_device_class_cdc_ecm.h PORTABLE C */ -/* 6.1.11 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -52,6 +52,9 @@ /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */ /* fixed standalone compile, */ /* resulting in version 6.1.11 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* added wait definitions, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ @@ -274,6 +277,12 @@ VOID _ux_network_driver_link_down(VOID *ux_network_handle); #define UX_DEVICE_CLASS_CDC_ECM_PACKET_POOL_WAIT 1000 #endif +#ifndef UX_DEVICE_CLASS_CDC_ECM_PACKET_POOL_INST_WAIT +#define UX_DEVICE_CLASS_CDC_ECM_PACKET_POOL_INST_WAIT 1000 +#endif + +#define UX_DEVICE_CLASS_CDC_ECM_LINK_CHECK_WAIT 10 + /* Define Slave CDC_ECM Class Calling Parameter structure */ typedef struct UX_SLAVE_CLASS_CDC_ECM_PARAMETER_STRUCT @@ -316,7 +325,6 @@ typedef struct UX_SLAVE_CLASS_CDC_ECM_STRUCT UCHAR ux_slave_class_cdc_ecm_remote_node_id[UX_DEVICE_CLASS_CDC_ECM_NODE_ID_LENGTH]; ULONG ux_slave_class_cdc_ecm_nx_ip_address; ULONG ux_slave_class_cdc_ecm_nx_ip_network_mask; - UCHAR *ux_slave_class_cdc_ecm_pool_memory; #if !defined(UX_DEVICE_STANDALONE) NX_IP *ux_slave_class_cdc_ecm_nx_ip; @@ -324,7 +332,7 @@ typedef struct UX_SLAVE_CLASS_CDC_ECM_STRUCT NX_PACKET *ux_slave_class_cdc_ecm_xmit_queue; NX_PACKET *ux_slave_class_cdc_ecm_xmit_queue_tail; NX_PACKET *ux_slave_class_cdc_ecm_receive_queue; - NX_PACKET_POOL ux_slave_class_cdc_ecm_packet_pool; + NX_PACKET_POOL *ux_slave_class_cdc_ecm_packet_pool; #endif #if !defined(UX_DEVICE_STANDALONE) diff --git a/common/usbx_device_classes/inc/ux_device_class_printer.h b/common/usbx_device_classes/inc/ux_device_class_printer.h index a77aff51..52ae8ce5 100644 --- a/common/usbx_device_classes/inc/ux_device_class_printer.h +++ b/common/usbx_device_classes/inc/ux_device_class_printer.h @@ -24,7 +24,7 @@ /* COMPONENT DEFINITION RELEASE */ /* */ /* ux_device_class_printer.h PORTABLE C */ -/* 6.1.12 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -44,6 +44,9 @@ /* resulting in version 6.1.11 */ /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */ /* resulting in version 6.1.12 */ +/* 10-31-2022 Yajun xia Modified comment(s), */ +/* added standalone support, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ @@ -92,6 +95,16 @@ extern "C" { #define UX_DEVICE_CLASS_PRINTER_IOCTL_READ_TIMEOUT_SET 2 #define UX_DEVICE_CLASS_PRINTER_IOCTL_WRITE_TIMEOUT_SET 3 +#if defined(UX_DEVICE_STANDALONE) + +/* Printer read state machine states. */ +#define UX_DEVICE_CLASS_PRINTER_READ_START (UX_STATE_STEP + 1) +#define UX_DEVICE_CLASS_PRINTER_READ_WAIT (UX_STATE_STEP + 2) + +/* Printer write state machine states. */ +#define UX_DEVICE_CLASS_PRINTER_WRITE_START (UX_STATE_STEP + 1) +#define UX_DEVICE_CLASS_PRINTER_WRITE_WAIT (UX_STATE_STEP + 2) +#endif /* Define Device Printer Class Calling Parameter structure */ @@ -117,6 +130,21 @@ typedef struct UX_DEVICE_CLASS_PRINTER_STRUCT #if !defined(UX_DEVICE_STANDALONE) UX_MUTEX ux_device_class_printer_endpoint_out_mutex; UX_MUTEX ux_device_class_printer_endpoint_in_mutex; +#else + UCHAR *ux_device_class_printer_read_buffer; + ULONG ux_device_class_printer_read_requested_length; + ULONG ux_device_class_printer_read_transfer_length; + ULONG ux_device_class_printer_read_actual_length; + UINT ux_device_class_printer_read_status; + UINT ux_device_class_printer_read_state; + + UCHAR *ux_device_class_printer_write_buffer; + ULONG ux_device_class_printer_write_transfer_length; + ULONG ux_device_class_printer_write_host_length; + ULONG ux_device_class_printer_write_requested_length; + ULONG ux_device_class_printer_write_actual_length; + UINT ux_device_class_printer_write_status; + UINT ux_device_class_printer_write_state; #endif } UX_DEVICE_CLASS_PRINTER; @@ -139,7 +167,12 @@ UINT _ux_device_class_printer_read(UX_DEVICE_CLASS_PRINTER *printer, UCHAR *buf UINT _ux_device_class_printer_ioctl(UX_DEVICE_CLASS_PRINTER *printer, ULONG ioctl_function, VOID *parameter); - +#if defined(UX_DEVICE_STANDALONE) +UINT _ux_device_class_printer_write_run(UX_DEVICE_CLASS_PRINTER *printer, UCHAR *buffer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_device_class_printer_read_run(UX_DEVICE_CLASS_PRINTER *printer, UCHAR *buffer, + ULONG requested_length, ULONG *actual_length); +#endif /* Define Device Printer Class API prototypes. */ @@ -148,6 +181,11 @@ UINT _ux_device_class_printer_ioctl(UX_DEVICE_CLASS_PRINTER *printer, ULONG ioc #define ux_device_class_printer_write _ux_device_class_printer_write #define ux_device_class_printer_ioctl _ux_device_class_printer_ioctl +#if defined(UX_DEVICE_STANDALONE) +#define ux_device_class_printer_read_run _ux_device_class_printer_read_run +#define ux_device_class_printer_write_run _ux_device_class_printer_write_run +#endif + /* Determine if a C++ compiler is being used. If so, complete the standard C conditional started above. */ #ifdef __cplusplus diff --git a/common/usbx_device_classes/inc/ux_device_class_rndis.h b/common/usbx_device_classes/inc/ux_device_class_rndis.h index 7ac55d82..abcd8332 100644 --- a/common/usbx_device_classes/inc/ux_device_class_rndis.h +++ b/common/usbx_device_classes/inc/ux_device_class_rndis.h @@ -24,7 +24,7 @@ /* COMPONENT DEFINITION RELEASE */ /* */ /* ux_device_class_rndis.h PORTABLE C */ -/* 6.1.11 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -52,6 +52,9 @@ /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */ /* fixed standalone compile, */ /* resulting in version 6.1.11 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* added wait and length DEFs, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ @@ -478,6 +481,16 @@ VOID _ux_network_driver_link_down(VOID *ux_network_handle); #define UX_DEVICE_CLASS_RNDIS_PACKET_POOL_WAIT 10 #endif +#ifndef UX_DEVICE_CLASS_RNDIS_PACKET_POOL_INST_WAIT +#define UX_DEVICE_CLASS_RNDIS_PACKET_POOL_INST_WAIT 100 +#endif + +/* Calculate message buffer length (not overflow). */ +#define UX_DEVICE_CLASS_RNDIS_MAX_MSG_LENGTH (UX_DEVICE_CLASS_RNDIS_MAX_PACKET_LENGTH + UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH) +#if UX_DEVICE_CLASS_RNDIS_MAX_MSG_LENGTH > UX_SLAVE_REQUEST_DATA_MAX_LENGTH +#error "Error: the maximum-sized RNDIS response cannot fit inside the control endpoint's data buffer. Increase UX_SLAVE_REQUEST_DATA_MAX_LENGTH." +#endif + /* Calculate response buffer length. */ #define UX_DEVICE_CLASS_RNDIS_OID_SUPPORTED_RESPONSE_LENGTH (UX_DEVICE_CLASS_RNDIS_CMPLT_QUERY_INFO_BUFFER + UX_DEVICE_CLASS_RNDIS_OID_SUPPORTED_LIST_LENGTH * 4) #define UX_DEVICE_CLASS_RNDIS_VENDOR_DESCRIPTION_MAX_RESPONSE_LENGTH (UX_DEVICE_CLASS_RNDIS_CMPLT_QUERY_INFO_BUFFER + UX_DEVICE_CLASS_RNDIS_VENDOR_DESCRIPTION_MAX_LENGTH) @@ -544,7 +557,6 @@ typedef struct UX_SLAVE_CLASS_RNDIS_STRUCT ULONG ux_slave_class_rndis_statistics_xmit_more_collisions; UCHAR ux_slave_class_rndis_local_node_id[UX_DEVICE_CLASS_RNDIS_NODE_ID_LENGTH]; UCHAR ux_slave_class_rndis_remote_node_id[UX_DEVICE_CLASS_RNDIS_NODE_ID_LENGTH]; - UCHAR *ux_slave_class_rndis_pool_memory; ULONG ux_slave_class_rndis_nx_ip_address; ULONG ux_slave_class_rndis_nx_ip_network_mask; @@ -553,7 +565,7 @@ typedef struct UX_SLAVE_CLASS_RNDIS_STRUCT NX_INTERFACE *ux_slave_class_rndis_nx_interface; NX_PACKET *ux_slave_class_rndis_xmit_queue; NX_PACKET *ux_slave_class_rndis_receive_queue; - NX_PACKET_POOL ux_slave_class_rndis_packet_pool; + NX_PACKET_POOL *ux_slave_class_rndis_packet_pool; #endif #if !defined(UX_DEVICE_STANDALONE) diff --git a/common/usbx_device_classes/inc/ux_device_class_video.h b/common/usbx_device_classes/inc/ux_device_class_video.h index 4c6d3e8e..9851532c 100644 --- a/common/usbx_device_classes/inc/ux_device_class_video.h +++ b/common/usbx_device_classes/inc/ux_device_class_video.h @@ -26,7 +26,7 @@ /* COMPONENT DEFINITION RELEASE */ /* */ /* ux_device_class_video.h PORTABLE C */ -/* 6.1.11 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -41,6 +41,9 @@ /* DATE NAME DESCRIPTION */ /* */ /* 04-25-2022 Chaoqiong Xiao Initial Version 6.1.11 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* added standalone support, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ @@ -508,6 +511,12 @@ typedef struct UX_DEVICE_CLASS_VIDEO_PAYLOAD_HEADER_STRUCT #define UX_DEVICE_CLASS_VIDEO_STREAM_ERROR_CODE_STILL_IMAGE_CAPTURE_ERROR 7 +/* Define Video Class Task states. */ +#define UX_DEVICE_CLASS_VIDEO_STREAM_RW_STOP (UX_STATE_RESET) +#define UX_DEVICE_CLASS_VIDEO_STREAM_RW_START (UX_STATE_STEP + 1) +#define UX_DEVICE_CLASS_VIDEO_STREAM_RW_WAIT (UX_STATE_STEP + 2) + + /* Define Video Class callback structure. */ struct UX_DEVICE_CLASS_VIDEO_STREAM_STRUCT; @@ -541,8 +550,12 @@ typedef struct UX_DEVICE_CLASS_VIDEO_PAYLOAD_STRUCT typedef struct UX_DEVICE_CLASS_VIDEO_STREAM_PARAMETER_STRUCT { +#if defined(UX_DEVICE_STANDALONE) + UINT (*ux_device_class_video_stream_parameter_task_function)(struct UX_DEVICE_CLASS_VIDEO_STREAM_STRUCT*); +#else ULONG ux_device_class_video_stream_parameter_thread_stack_size; VOID (*ux_device_class_video_stream_parameter_thread_entry)(ULONG id); +#endif UX_DEVICE_CLASS_VIDEO_STREAM_CALLBACKS ux_device_class_video_stream_parameter_callbacks; ULONG ux_device_class_video_stream_parameter_max_payload_buffer_size; @@ -572,8 +585,13 @@ typedef struct UX_DEVICE_CLASS_VIDEO_STREAM_STRUCT #if !defined(UX_DEVICE_STANDALONE) UCHAR *ux_device_class_video_stream_thread_stack; UX_THREAD ux_device_class_video_stream_thread; +#else + UINT (*ux_device_class_video_stream_task_function)(struct UX_DEVICE_CLASS_VIDEO_STREAM_STRUCT*); + UINT ux_device_class_video_stream_task_state; + UINT ux_device_class_video_stream_task_status; #endif + ULONG ux_device_class_video_stream_buffer_error_count; UCHAR *ux_device_class_video_stream_buffer; ULONG ux_device_class_video_stream_buffer_size; ULONG ux_device_class_video_stream_payload_buffer_size; @@ -636,6 +654,9 @@ UINT _ux_device_class_video_transmission_start(UX_DEVICE_CLASS_VIDEO_STREAM * UINT _ux_device_class_video_write_payload_get(UX_DEVICE_CLASS_VIDEO_STREAM *video, UCHAR **buffer, ULONG *max_length); UINT _ux_device_class_video_write_payload_commit(UX_DEVICE_CLASS_VIDEO_STREAM *video, ULONG length); +UINT _ux_device_class_video_tasks_run(VOID *instance); +UINT _ux_device_class_video_read_task_function(UX_DEVICE_CLASS_VIDEO_STREAM *stream); +UINT _ux_device_class_video_write_task_function(UX_DEVICE_CLASS_VIDEO_STREAM *stream); /* Define Video Class API prototypes. */ @@ -663,6 +684,9 @@ UINT _ux_device_class_video_write_payload_commit(UX_DEVICE_CLASS_VIDEO_STREAM #define ux_device_class_video_ioctl _ux_device_class_video_ioctl +#define ux_device_class_video_read_task_function _ux_device_class_video_read_task_function +#define ux_device_class_video_write_task_function _ux_device_class_video_write_task_function + /* Determine if a C++ compiler is being used. If so, complete the standard C conditional started above. */ diff --git a/common/usbx_device_classes/src/ux_device_class_audio_activate.c b/common/usbx_device_classes/src/ux_device_class_audio_activate.c index 53163cfe..2f9b89d7 100644 --- a/common/usbx_device_classes/src/ux_device_class_audio_activate.c +++ b/common/usbx_device_classes/src/ux_device_class_audio_activate.c @@ -33,7 +33,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_audio_activate PORTABLE C */ -/* 6.1.12 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -70,6 +70,9 @@ /* names conflict C++ keyword, */ /* added interrupt support, */ /* resulting in version 6.1.12 */ +/* 10-31-2022 Yajun Xia Modified comment(s), */ +/* added standalone support, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_device_class_audio_activate(UX_SLAVE_CLASS_COMMAND *command) @@ -166,6 +169,12 @@ ULONG stream_index; /* Store the class instance into the interface. */ stream_interface -> ux_slave_interface_class_instance = (VOID *)audio; +#if defined(UX_DEVICE_STANDALONE) + + /* Reset stream task state. */ + stream -> ux_device_class_audio_stream_task_state = UX_STATE_RESET; + stream -> ux_device_class_audio_stream_task_state = UX_SUCCESS; +#endif } /* If there is a activate function call it. */ diff --git a/common/usbx_device_classes/src/ux_device_class_audio_change.c b/common/usbx_device_classes/src/ux_device_class_audio_change.c index 35d4a3ae..9ac4e679 100644 --- a/common/usbx_device_classes/src/ux_device_class_audio_change.c +++ b/common/usbx_device_classes/src/ux_device_class_audio_change.c @@ -33,7 +33,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_audio_change PORTABLE C */ -/* 6.1.12 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -81,6 +81,9 @@ /* rx full packet for */ /* feedback, */ /* resulting in version 6.1.12 */ +/* 10-31-2022 Yajun Xia Modified comment(s), */ +/* added standalone support, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_device_class_audio_change(UX_SLAVE_CLASS_COMMAND *command) @@ -137,8 +140,9 @@ ULONG endpoint_dir; /* Parse all endpoints. */ #if defined(UX_DEVICE_STANDALONE) - /* Standalone mode not supported. */ - endpoint_dir = 0; + endpoint_dir = (stream -> ux_device_class_audio_stream_task_function == + _ux_device_class_audio_read_task_function) ? + UX_ENDPOINT_OUT: UX_ENDPOINT_IN; #else endpoint_dir = (stream -> ux_device_class_audio_stream_thread.tx_thread_entry == @@ -229,6 +233,15 @@ ULONG endpoint_dir; return(UX_DESCRIPTOR_CORRUPTED); } +#if defined(UX_DEVICE_STANDALONE) + + /* Reset background transfer state. */ + stream -> ux_device_class_audio_stream_task_state = UX_STATE_RESET; +#endif + + /* Now reset payload buffer error count. */ + stream -> ux_device_class_audio_stream_buffer_error_count = 0; + /* Now reset frame buffers. */ frame_buffer = stream -> ux_device_class_audio_stream_buffer; while(frame_buffer < stream -> ux_device_class_audio_stream_buffer + stream -> ux_device_class_audio_stream_buffer_size) @@ -243,7 +256,7 @@ ULONG endpoint_dir; } stream -> ux_device_class_audio_stream_transfer_pos = stream -> ux_device_class_audio_stream_access_pos; -#if defined(UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT) +#if defined(UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT) && !defined(UX_DEVICE_STANDALONE) /* If feedback supported, resume the thread. */ if (stream -> ux_device_class_audio_stream_feedback_thread_stack) diff --git a/common/usbx_device_classes/src/ux_device_class_audio_feedback_task_function.c b/common/usbx_device_classes/src/ux_device_class_audio_feedback_task_function.c new file mode 100644 index 00000000..8bcf8573 --- /dev/null +++ b/common/usbx_device_classes/src/ux_device_class_audio_feedback_task_function.c @@ -0,0 +1,164 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** USBX Component */ +/** */ +/** Device Audio Class */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define UX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "ux_api.h" +#include "ux_device_class_audio.h" +#include "ux_device_stack.h" + + +#if defined(UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT) && defined(UX_DEVICE_STANDALONE) +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _ux_device_class_audio_feedback_task_function PORTABLE C */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Yajun Xia, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is background task of ISO OUT/IN (feedback of IN/OUT) */ +/* for the Audio class. */ +/* */ +/* It's for standalone mode. */ +/* */ +/* INPUT */ +/* */ +/* stream Pointer to audio stream */ +/* */ +/* OUTPUT */ +/* */ +/* State machine status */ +/* UX_STATE_EXIT Device not configured */ +/* UX_STATE_IDLE No feedback transfer running */ +/* UX_STATE_WAIT Feedback transfer running */ +/* */ +/* CALLS */ +/* */ +/* _ux_system_error_handler System error trap */ +/* _ux_device_stack_transfer_run Run transfer state machine */ +/* */ +/* CALLED BY */ +/* */ +/* Audio Class (task) */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Yajun Xia Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ +UINT _ux_device_class_audio_feedback_task_function(UX_DEVICE_CLASS_AUDIO_STREAM *stream) +{ + +UINT status; +UX_SLAVE_DEVICE *device; +UX_SLAVE_ENDPOINT *endpoint; +UX_SLAVE_TRANSFER *transfer; +ULONG transfer_length; + + + /* Get stack device instance. */ + device = stream -> ux_device_class_audio_stream_audio -> ux_device_class_audio_device; + + /* Check if the device is configured. */ + if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED) + { + + /* Error trap. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CONFIGURATION_HANDLE_UNKNOWN); + + stream -> ux_device_class_audio_stream_feedback_task_state = UX_STATE_EXIT; + return(UX_STATE_EXIT); + } + + /* Get endpoint instance. */ + endpoint = stream -> ux_device_class_audio_stream_feedback; + + /* Endpoint not available, maybe it's alternate setting 0. */ + if (endpoint == UX_NULL) + { + + /* Error trap. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_ENDPOINT_HANDLE_UNKNOWN); + + stream -> ux_device_class_audio_stream_feedback_task_state = UX_STATE_RESET; + return(UX_STATE_IDLE); + } + + /* Get transfer instance. */ + transfer = &endpoint -> ux_slave_endpoint_transfer_request; + + /* Length is pre-set on interface alternate setting activate. */ + transfer_length = transfer -> ux_slave_transfer_request_requested_length; + + switch (stream -> ux_device_class_audio_stream_feedback_task_state) + { + case UX_STATE_RESET: + stream -> ux_device_class_audio_stream_feedback_task_state = UX_DEVICE_CLASS_AUDIO_STREAM_FEEDBACK_RW_WAIT; + stream -> ux_device_class_audio_stream_feedback_task_status = UX_TRANSFER_NO_ANSWER; + + /* Fall through. */ + case UX_DEVICE_CLASS_AUDIO_STREAM_FEEDBACK_RW_WAIT: + + /* Issue transfer request. */ + status = _ux_device_stack_transfer_run(transfer, transfer_length, transfer_length); + + /* Any error or success case. */ + if (status < UX_STATE_NEXT) + { + + /* Error notification! */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_ERROR); + + stream -> ux_device_class_audio_stream_feedback_task_state = UX_STATE_RESET; + stream -> ux_device_class_audio_stream_feedback_task_status = transfer -> ux_slave_transfer_request_completion_code; + return(UX_STATE_EXIT); + } + + /* Success case. */ + if (status == UX_STATE_NEXT) + { + stream -> ux_device_class_audio_stream_feedback_task_state = UX_DEVICE_CLASS_AUDIO_STREAM_FEEDBACK_RW_WAIT; + stream -> ux_device_class_audio_stream_feedback_task_status = transfer -> ux_slave_transfer_request_completion_code; + } + + /* Keep waiting. */ + return(UX_STATE_WAIT); + + default: + stream -> ux_device_class_audio_stream_feedback_task_state = UX_STATE_RESET; + stream -> ux_device_class_audio_stream_feedback_task_status = UX_INVALID_STATE; + break; + } + + /* Error case. */ + return(UX_STATE_EXIT); +} +#endif diff --git a/common/usbx_device_classes/src/ux_device_class_audio_feedback_thread_entry.c b/common/usbx_device_classes/src/ux_device_class_audio_feedback_thread_entry.c index 88525f1b..f71c0bd7 100644 --- a/common/usbx_device_classes/src/ux_device_class_audio_feedback_thread_entry.c +++ b/common/usbx_device_classes/src/ux_device_class_audio_feedback_thread_entry.c @@ -35,7 +35,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_audio_feedback_thread_entry PORTABLE C */ -/* 6.1.10 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -70,11 +70,17 @@ /* DATE NAME DESCRIPTION */ /* */ /* 01-31-2022 Chaoqiong Xiao Initial Version 6.1.10 */ +/* 10-31-2022 Yajun Xia Modified comment(s), */ +/* added standalone support, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ VOID _ux_device_class_audio_feedback_thread_entry(ULONG audio_stream) { - +#if defined(UX_DEVICE_STANDALONE) + UX_PARAMETER_NOT_USED(audio_stream); + return; +#else UINT status; UX_DEVICE_CLASS_AUDIO_STREAM *stream; UX_SLAVE_DEVICE *device; @@ -128,5 +134,6 @@ ULONG transfer_length; /* We need to suspend ourselves. We will be resumed by the device enumeration module or when a change of alternate setting happens. */ _ux_utility_thread_suspend(&stream -> ux_device_class_audio_stream_feedback_thread); } +#endif } #endif diff --git a/common/usbx_device_classes/src/ux_device_class_audio_initialize.c b/common/usbx_device_classes/src/ux_device_class_audio_initialize.c index 4887494f..4ba297a3 100644 --- a/common/usbx_device_classes/src/ux_device_class_audio_initialize.c +++ b/common/usbx_device_classes/src/ux_device_class_audio_initialize.c @@ -33,7 +33,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_audio_initialize PORTABLE C */ -/* 6.1.12 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -84,14 +84,13 @@ /* added interrupt support, */ /* refined internal logic, */ /* resulting in version 6.1.12 */ +/* 10-31-2022 Yajun Xia Modified comment(s), */ +/* added standalone support, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_device_class_audio_initialize(UX_SLAVE_CLASS_COMMAND *command) { -#if defined(UX_DEVICE_STANDALONE) - UX_PARAMETER_NOT_USED(command); - return(UX_FUNCTION_NOT_SUPPORTED); -#else UINT status = UX_SUCCESS; UX_DEVICE_CLASS_AUDIO *audio; @@ -153,8 +152,7 @@ ULONG i; audio_parameter -> ux_device_class_audio_parameter_status_size; audio -> ux_device_class_audio_status_queue_bytes = memory_size; -#if defined(UX_DEVICE_STANDALONE) -#else +#if !defined(UX_DEVICE_STANDALONE) if (UX_OVERFLOW_CHECK_ADD_ULONG(memory_size, UX_DEVICE_CLASS_AUDIO_INTERRUPT_THREAD_STACK_SIZE)) { _ux_utility_memory_free(audio); @@ -217,6 +215,15 @@ ULONG i; audio -> ux_device_class_audio_status_queue = (UCHAR *)audio_class -> ux_slave_class_thread_stack + UX_DEVICE_CLASS_AUDIO_INTERRUPT_THREAD_STACK_SIZE; +#else + audio -> ux_device_class_audio_status_queue = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size); + + /* Check for successful allocation. */ + if (audio -> ux_device_class_audio_status_queue == UX_NULL) + { + _ux_utility_memory_free(audio); + return(UX_MEMORY_INSUFFICIENT); + } #endif #endif @@ -268,6 +275,8 @@ ULONG i; stream -> ux_device_class_audio_stream_transfer_pos = (UX_DEVICE_CLASS_AUDIO_FRAME *)stream -> ux_device_class_audio_stream_buffer; stream -> ux_device_class_audio_stream_access_pos = stream -> ux_device_class_audio_stream_transfer_pos; +#if !defined(UX_DEVICE_STANDALONE) + /* Create memory block for streaming thread stack in addition. */ if (stream_parameter -> ux_device_class_audio_stream_parameter_thread_stack_size == 0) memory_size = UX_DEVICE_CLASS_AUDIO_FEEDBACK_THREAD_STACK_SIZE; @@ -298,13 +307,19 @@ ULONG i; } UX_THREAD_EXTENSION_PTR_SET(&(stream -> ux_device_class_audio_stream_thread), stream) +#else + + /* Save task function for streaming. */ + stream -> ux_device_class_audio_stream_task_function = stream_parameter -> ux_device_class_audio_stream_parameter_task_function; +#endif #if defined(UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT) +#if !defined(UX_DEVICE_STANDALONE) + /* Check entry to confirm feedback is supported. */ if (stream_parameter -> ux_device_class_audio_stream_parameter_feedback_thread_entry) { - /* Create memory block for streaming thread stack in addition. */ if (stream_parameter -> ux_device_class_audio_stream_parameter_feedback_thread_stack_size == 0) memory_size = UX_THREAD_STACK_SIZE; @@ -336,6 +351,14 @@ ULONG i; UX_THREAD_EXTENSION_PTR_SET(&(stream -> ux_device_class_audio_stream_feedback_thread), stream) } +#else + if (stream_parameter -> ux_device_class_audio_stream_parameter_feedback_task_function) + { + + /* Save task function for streaming. */ + stream -> ux_device_class_audio_stream_feedback_task_function = stream_parameter -> ux_device_class_audio_stream_parameter_feedback_task_function; + } +#endif #endif /* Save callbacks. */ @@ -365,6 +388,12 @@ ULONG i; &audio_parameter -> ux_device_class_audio_parameter_callbacks, sizeof(UX_DEVICE_CLASS_AUDIO_CALLBACKS)); /* Use case of memcpy is verified. */ +#if defined(UX_DEVICE_STANDALONE) + + /* Link task function. */ + audio_class -> ux_slave_class_task_function = _ux_device_class_audio_tasks_run; +#endif + /* Return completion status. */ return(UX_SUCCESS); } @@ -377,24 +406,27 @@ ULONG i; for (i = 0; i < audio -> ux_device_class_audio_streams_nb; i ++) { #if defined(UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT) +#if !defined(UX_DEVICE_STANDALONE) if (stream -> ux_device_class_audio_stream_feedback_thread_stack) { _ux_device_thread_delete(&stream -> ux_device_class_audio_stream_feedback_thread); _ux_utility_memory_free(stream -> ux_device_class_audio_stream_feedback_thread_stack); } #endif +#endif +#if !defined(UX_DEVICE_STANDALONE) if (stream -> ux_device_class_audio_stream_thread_stack) { _ux_device_thread_delete(&stream -> ux_device_class_audio_stream_thread); _ux_utility_memory_free(stream -> ux_device_class_audio_stream_thread_stack); } +#endif if (stream -> ux_device_class_audio_stream_buffer) _ux_utility_memory_free(stream -> ux_device_class_audio_stream_buffer); stream ++; } #if defined(UX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT) -#if defined(UX_DEVICE_STANDALONE) -#else +#if !defined(UX_DEVICE_STANDALONE) if (audio_class -> ux_slave_class_thread_stack) { _ux_device_thread_delete(&audio_class -> ux_slave_class_thread); @@ -403,10 +435,14 @@ ULONG i; _ux_device_semaphore_delete(&audio -> ux_device_class_audio_status_semaphore); _ux_device_mutex_delete(&audio -> ux_device_class_audio_status_mutex); } +#else + if (audio -> ux_device_class_audio_status_queue) + { + _ux_utility_memory_free(audio -> ux_device_class_audio_status_queue); + } #endif #endif _ux_utility_memory_free(audio); return(status); -#endif } diff --git a/common/usbx_device_classes/src/ux_device_class_audio_interrupt_send.c b/common/usbx_device_classes/src/ux_device_class_audio_interrupt_send.c index 72c51fba..eb5d4387 100644 --- a/common/usbx_device_classes/src/ux_device_class_audio_interrupt_send.c +++ b/common/usbx_device_classes/src/ux_device_class_audio_interrupt_send.c @@ -34,7 +34,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_audio_interrupt_send PORTABLE C */ -/* 6.1.12 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -68,6 +68,9 @@ /* DATE NAME DESCRIPTION */ /* */ /* 07-29-2022 Chaoqiong Xiao Initial Version 6.1.12 */ +/* 10-31-2022 Yajun Xia Modified comment(s), */ +/* added standalone support, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_device_class_audio_interrupt_send(UX_DEVICE_CLASS_AUDIO *audio, UCHAR *int_data) @@ -77,11 +80,6 @@ UINT _ux_device_class_audio_interrupt_send(UX_DEVICE_CLASS_AUDIO *audio, UCHA UX_PARAMETER_NOT_USED(int_data); return(UX_FUNCTION_NOT_SUPPORTED); #else -#if defined(UX_DEVICE_STANDALONE) - UX_PARAMETER_NOT_USED(audio); - UX_PARAMETER_NOT_USED(int_data); - return(UX_FUNCTION_NOT_SUPPORTED); -#else UX_SLAVE_DEVICE *device; UX_SLAVE_ENDPOINT *endpoint; @@ -169,5 +167,4 @@ ULONG i; /* Return success. */ return(UX_SUCCESS); #endif -#endif } diff --git a/common/usbx_device_classes/src/ux_device_class_audio_interrupt_task_function.c b/common/usbx_device_classes/src/ux_device_class_audio_interrupt_task_function.c new file mode 100644 index 00000000..eeac5c25 --- /dev/null +++ b/common/usbx_device_classes/src/ux_device_class_audio_interrupt_task_function.c @@ -0,0 +1,198 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** USBX Component */ +/** */ +/** Device Audio Class */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define UX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "ux_api.h" +#include "ux_device_class_audio.h" +#include "ux_device_stack.h" + +#if defined(UX_DEVICE_STANDALONE) && defined(UX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT) +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _ux_device_class_audio_interrupt_task_function PORTABLE C */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Yajun Xia, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is task of INTERRUPT IN from the Audio class. */ +/* */ +/* It's for standalone mode. */ +/* */ +/* INPUT */ +/* */ +/* audio Address of audio instance */ +/* */ +/* OUTPUT */ +/* */ +/* State machine Status to check */ +/* UX_STATE_EXIT Abnormal, to reset state */ +/* UX_STATE_IDLE No interrupt transfer running */ +/* UX_STATE_WAIT Keep running, waiting */ +/* */ +/* CALLS */ +/* */ +/* _ux_system_error_handler System error trap */ +/* _ux_utility_memory_copy Copy memory */ +/* _ux_device_stack_transfer_run Run Transfer state machine */ +/* */ +/* CALLED BY */ +/* */ +/* Audio Class (task) */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Yajun Xia Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ +UINT _ux_device_class_audio_interrupt_task_function(UX_DEVICE_CLASS_AUDIO *audio) +{ + +UINT status; +UX_SLAVE_DEVICE *device; +UX_SLAVE_ENDPOINT *endpoint; +UX_SLAVE_TRANSFER *transfer; +UCHAR *buff; + + + /* Get stack device instance. */ + device = audio -> ux_device_class_audio_device; + + /* Check if the device is configured. */ + if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED) + { + + /* Error trap. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CONFIGURATION_HANDLE_UNKNOWN); + + audio -> ux_device_class_audio_interrupt_task_state = UX_STATE_EXIT; + return(UX_STATE_EXIT); + } + + /* Get endpoint instance. */ + endpoint = audio -> ux_device_class_audio_interrupt; + + /* Endpoint not available, maybe it's alternate setting 0. */ + if (endpoint == UX_NULL) + { + + /* Error trap. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_ENDPOINT_HANDLE_UNKNOWN); + + audio -> ux_device_class_audio_interrupt_task_state = UX_STATE_RESET; + return(UX_STATE_IDLE); + } + + /* No packet in queue */ + if (audio -> ux_device_class_audio_status_queued == 0) + { + audio -> ux_device_class_audio_interrupt_task_state = UX_STATE_RESET; + audio -> ux_device_class_audio_interrupt_task_status = UX_TRANSFER_NOT_READY; + return(UX_STATE_EXIT); + } + + /* Get transfer instance. */ + transfer = &endpoint -> ux_slave_endpoint_transfer_request; + + /* Handle state cases. */ + switch(audio -> ux_device_class_audio_interrupt_task_state) + { + case UX_STATE_RESET: + audio -> ux_device_class_audio_interrupt_task_state = UX_DEVICE_CLASS_AUDIO_INTERRUPT_START; + audio -> ux_device_class_audio_interrupt_task_status = UX_TRANSFER_NO_ANSWER; + + /* Fall through. */ + case UX_DEVICE_CLASS_AUDIO_INTERRUPT_START: + if (audio -> ux_device_class_audio_status_size > transfer -> ux_slave_transfer_request_transfer_length) + { + + /* Error trap. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_ERROR); + + audio -> ux_device_class_audio_interrupt_task_state = UX_STATE_RESET; + audio -> ux_device_class_audio_interrupt_task_status = UX_ERROR; + return(UX_STATE_EXIT); + } + + _ux_utility_memory_copy(transfer -> ux_slave_transfer_request_data_pointer, + audio -> ux_device_class_audio_status_tail, audio -> ux_device_class_audio_status_size); /* Use case of memcpy is verified. */ + + audio -> ux_device_class_audio_interrupt_task_state = UX_DEVICE_CLASS_AUDIO_INTERRUPT_WAIT; + + /* Fall through. */ + case UX_DEVICE_CLASS_AUDIO_INTERRUPT_WAIT: + + /* Start frame transfer anyway. */ + status = _ux_device_stack_transfer_run(transfer, audio -> ux_device_class_audio_status_size, + audio -> ux_device_class_audio_status_size); + + /* Any error or success case. */ + if (status < UX_STATE_NEXT) + { + + /* Error notification! */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_ERROR); + + audio -> ux_device_class_audio_interrupt_task_state = UX_STATE_RESET; + audio -> ux_device_class_audio_interrupt_task_status = + transfer -> ux_slave_transfer_request_completion_code; + return(UX_STATE_EXIT); + } + + /* Success case. */ + if (status == UX_STATE_NEXT) + { + buff = audio -> ux_device_class_audio_status_tail; + buff += audio -> ux_device_class_audio_status_size; + + if (buff >= (audio -> ux_device_class_audio_status_queue + audio -> ux_device_class_audio_status_queue_bytes)) + buff = audio -> ux_device_class_audio_status_queue; + + audio -> ux_device_class_audio_status_tail = buff; + audio -> ux_device_class_audio_status_queued -= audio -> ux_device_class_audio_status_size; + audio -> ux_device_class_audio_interrupt_task_state = UX_DEVICE_CLASS_AUDIO_INTERRUPT_START; + audio -> ux_device_class_audio_interrupt_task_status = + transfer -> ux_slave_transfer_request_completion_code; + } + + /* Keep waiting. */ + return(UX_STATE_WAIT); + + default: /* Error. */ + audio -> ux_device_class_audio_interrupt_task_state = UX_STATE_RESET; + audio -> ux_device_class_audio_interrupt_task_status = UX_INVALID_STATE; + break; + } + + /* Error case. */ + return(UX_STATE_EXIT); +} +#endif diff --git a/common/usbx_device_classes/src/ux_device_class_audio_read_task_function.c b/common/usbx_device_classes/src/ux_device_class_audio_read_task_function.c new file mode 100644 index 00000000..03d43d89 --- /dev/null +++ b/common/usbx_device_classes/src/ux_device_class_audio_read_task_function.c @@ -0,0 +1,188 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** USBX Component */ +/** */ +/** Device Audio Class */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define UX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "ux_api.h" +#include "ux_device_class_audio.h" +#include "ux_device_stack.h" + + +#if defined(UX_DEVICE_STANDALONE) +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _ux_device_class_audio_read_task_function PORTABLE C */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Yajun Xia, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the background task of the audio stream read. */ +/* */ +/* It's for standalone mode. */ +/* */ +/* INPUT */ +/* */ +/* stream Pointer to audio stream */ +/* */ +/* OUTPUT */ +/* */ +/* State machine status */ +/* UX_STATE_EXIT Device not configured */ +/* UX_STATE_IDLE No streaming transfer running */ +/* UX_STATE_WAIT Streaming transfer running */ +/* */ +/* CALLS */ +/* */ +/* _ux_device_stack_transfer_run Run transfer state machine */ +/* _ux_utility_memory_copy Copy memory */ +/* */ +/* CALLED BY */ +/* */ +/* USBX Device Stack */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Yajun Xia Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ +UINT _ux_device_class_audio_read_task_function(UX_DEVICE_CLASS_AUDIO_STREAM *stream) +{ +UX_SLAVE_DEVICE *device; +UX_SLAVE_ENDPOINT *endpoint; +UX_SLAVE_TRANSFER *transfer; +UCHAR *next_pos; +UX_DEVICE_CLASS_AUDIO_FRAME *next_frame; +ULONG max_packet_size; +ULONG actual_length; +UINT status; + + + /* Get the pointer to the device. */ + device = stream -> ux_device_class_audio_stream_audio -> ux_device_class_audio_device; + + /* Check if the device is configured. */ + if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED) + { + stream -> ux_device_class_audio_stream_task_state = UX_STATE_EXIT; + return(UX_STATE_EXIT); + } + + /* Get the endpoint. */ + endpoint = stream -> ux_device_class_audio_stream_endpoint; + + /* No endpoint ready, maybe it's alternate setting 0. */ + if (endpoint == UX_NULL) + return(UX_STATE_IDLE); + + /* Check if background transfer task is started. */ + if (stream -> ux_device_class_audio_stream_task_state == UX_DEVICE_CLASS_AUDIO_STREAM_RW_STOP) + return(UX_STATE_IDLE); + + /* Get transfer instance. */ + transfer = &endpoint -> ux_slave_endpoint_transfer_request; + + /* If not started yet, reset transfer and start polling. */ + if (stream -> ux_device_class_audio_stream_task_state == UX_DEVICE_CLASS_AUDIO_STREAM_RW_START) + { + + /* Next state: transfer wait. */ + stream -> ux_device_class_audio_stream_task_state = UX_DEVICE_CLASS_AUDIO_STREAM_RW_WAIT; + + /* Reset transfer state. */ + UX_SLAVE_TRANSFER_STATE_RESET(transfer); + } + + /* Run transfer state machine. */ + max_packet_size = endpoint -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_transfer_length; + status = _ux_device_stack_transfer_run(transfer, max_packet_size, max_packet_size); + + /* Error case. */ + if (status < UX_STATE_NEXT) + { + + /* Error on background transfer task start. */ + stream -> ux_device_class_audio_stream_task_state = UX_STATE_RESET; + stream -> ux_device_class_audio_stream_task_status = + transfer -> ux_slave_transfer_request_completion_code; + + /* Error notification! */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_ERROR); + return(UX_STATE_EXIT); + } + + /* Success case. */ + if (status == UX_STATE_NEXT) + { + + /* Next state: start. */ + stream -> ux_device_class_audio_stream_task_state = UX_DEVICE_CLASS_AUDIO_STREAM_RW_START; + stream -> ux_device_class_audio_stream_task_status = + transfer -> ux_slave_transfer_request_completion_code; + + /* Get actual transfer length. */ + actual_length = transfer -> ux_slave_transfer_request_actual_length; + + /* Frame received, log it. */ + stream -> ux_device_class_audio_stream_transfer_pos -> ux_device_class_audio_frame_length = actual_length; + stream -> ux_device_class_audio_stream_transfer_pos -> ux_device_class_audio_frame_pos = 0; + _ux_utility_memory_copy(stream -> ux_device_class_audio_stream_transfer_pos -> ux_device_class_audio_frame_data, + transfer -> ux_slave_transfer_request_data_pointer, + actual_length); /* Use case of memcpy is verified. */ + + /* For simple, do not advance the transfer position if there is overflow. */ + next_pos = (UCHAR *)stream -> ux_device_class_audio_stream_transfer_pos; + next_pos += stream -> ux_device_class_audio_stream_frame_buffer_size; + if (next_pos >= stream -> ux_device_class_audio_stream_buffer + stream -> ux_device_class_audio_stream_buffer_size) + next_pos = stream -> ux_device_class_audio_stream_buffer; + next_frame = (UX_DEVICE_CLASS_AUDIO_FRAME *)next_pos; + + /* Check overflow! */ + if (next_frame -> ux_device_class_audio_frame_length > 0) + { + + /* Error notification! */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_BUFFER_OVERFLOW); + stream -> ux_device_class_audio_stream_buffer_error_count ++; + } + else + + /* Update transfer position. */ + stream -> ux_device_class_audio_stream_transfer_pos = next_frame; + + /* Invoke notification callback. */ + if (stream -> ux_device_class_audio_stream_callbacks.ux_device_class_audio_stream_frame_done != UX_NULL) + stream -> ux_device_class_audio_stream_callbacks.ux_device_class_audio_stream_frame_done(stream, actual_length); + } + + /* Keep waiting. */ + return(UX_STATE_WAIT); +} +#endif diff --git a/common/usbx_device_classes/src/ux_device_class_audio_read_thread_entry.c b/common/usbx_device_classes/src/ux_device_class_audio_read_thread_entry.c index 60460511..8af97f0e 100644 --- a/common/usbx_device_classes/src/ux_device_class_audio_read_thread_entry.c +++ b/common/usbx_device_classes/src/ux_device_class_audio_read_thread_entry.c @@ -34,7 +34,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_audio_read_thread_entry PORTABLE C */ -/* 6.1.10 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -81,6 +81,9 @@ /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */ /* refined macros names, */ /* resulting in version 6.1.10 */ +/* 10-31-2022 Yajun Xia Modified comment(s), */ +/* added standalone support, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ VOID _ux_device_class_audio_read_thread_entry(ULONG audio_stream) @@ -133,6 +136,7 @@ ULONG actual_length; /* Error notification! */ _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_ERROR); + stream -> ux_device_class_audio_stream_buffer_error_count ++; break; } @@ -159,6 +163,7 @@ ULONG actual_length; /* Error notification! */ _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_BUFFER_OVERFLOW); + stream -> ux_device_class_audio_stream_buffer_error_count ++; } else diff --git a/common/usbx_device_classes/src/ux_device_class_audio_reception_start.c b/common/usbx_device_classes/src/ux_device_class_audio_reception_start.c index 120eb1ea..078ce81e 100644 --- a/common/usbx_device_classes/src/ux_device_class_audio_reception_start.c +++ b/common/usbx_device_classes/src/ux_device_class_audio_reception_start.c @@ -34,7 +34,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_audio_reception_start PORTABLE C */ -/* 6.1.10 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -70,6 +70,9 @@ /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */ /* refined macros names, */ /* resulting in version 6.1.10 */ +/* 10-31-2022 Yajun Xia Modified comment(s), */ +/* added standalone support, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_device_class_audio_reception_start(UX_DEVICE_CLASS_AUDIO_STREAM *stream) @@ -103,7 +106,15 @@ UX_SLAVE_DEVICE *device; if (stream -> ux_device_class_audio_stream_transfer_pos -> ux_device_class_audio_frame_length > 0) return(UX_BUFFER_OVERFLOW); +#if defined(UX_DEVICE_STANDALONE) + + /* Start read task. */ + if (stream -> ux_device_class_audio_stream_task_state == UX_DEVICE_CLASS_AUDIO_STREAM_RW_STOP) + stream -> ux_device_class_audio_stream_task_state = UX_DEVICE_CLASS_AUDIO_STREAM_RW_START; +#else + /* Start read thread. */ _ux_device_thread_resume(&stream -> ux_device_class_audio_stream_thread); +#endif return(UX_SUCCESS); } diff --git a/common/usbx_device_classes/src/ux_device_class_audio_tasks_run.c b/common/usbx_device_classes/src/ux_device_class_audio_tasks_run.c new file mode 100644 index 00000000..2518ef26 --- /dev/null +++ b/common/usbx_device_classes/src/ux_device_class_audio_tasks_run.c @@ -0,0 +1,153 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** USBX Component */ +/** */ +/** Device Audio Class */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define UX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "ux_api.h" +#include "ux_device_class_audio.h" +#include "ux_device_stack.h" + + +#if defined(UX_DEVICE_STANDALONE) +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _ux_device_class_audio_tasks_run PORTABLE C */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Yajun Xia, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the background task of the audio. */ +/* */ +/* It's for standalone mode. */ +/* */ +/* INPUT */ +/* */ +/* instance Pointer to audio class */ +/* */ +/* OUTPUT */ +/* */ +/* State machine status */ +/* UX_STATE_EXIT Device not configured */ +/* UX_STATE_IDLE No streaming transfer running */ +/* UX_STATE_WAIT Streaming transfer running */ +/* */ +/* CALLS */ +/* */ +/* (ux_device_class_audio_stream_task_function) */ +/* Run stream task */ +/* (ux_device_class_audio_stream_feedback_task_function) */ +/* Run stream feedback task */ +/* */ +/* CALLED BY */ +/* */ +/* USBX Device Stack */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Yajun Xia Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ +UINT _ux_device_class_audio_tasks_run(VOID *instance) +{ +UX_SLAVE_DEVICE *device; +UX_DEVICE_CLASS_AUDIO *audio; +UX_DEVICE_CLASS_AUDIO_STREAM *stream; +ULONG stream_index; +UINT status; +#if defined(UX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT) +ULONG interrupt_running_count = 0; +#endif +ULONG stream_running_count = 0; +#if defined(UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT) +ULONG feedback_running_count = 0; +#endif + + /* Get audio instance. */ + audio = (UX_DEVICE_CLASS_AUDIO *) instance; + + /* Get the pointer to the device. */ + device = &_ux_system_slave -> ux_system_slave_device; + + /* Check if the device is configured. */ + if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED) + return(UX_STATE_EXIT); + +#if defined(UX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT) + + /* Run audio status tasks. */ + status = _ux_device_class_audio_interrupt_task_function(audio); + if (status == UX_STATE_EXIT) + return(status); + if (status == UX_STATE_WAIT) + interrupt_running_count++; +#endif + + for (stream_index = 0; + stream_index < audio -> ux_device_class_audio_streams_nb; + stream_index ++) + { + stream = &audio -> ux_device_class_audio_streams[stream_index]; + status = stream -> ux_device_class_audio_stream_task_function(stream); + if (status == UX_STATE_EXIT) + return(status); + if (status == UX_STATE_WAIT) + stream_running_count ++; + +#if defined(UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT) + if (stream -> ux_device_class_audio_stream_feedback_task_function != UX_NULL) + { + status = stream -> ux_device_class_audio_stream_feedback_task_function(stream); + if (status == UX_STATE_EXIT) + return(status); + if (status == UX_STATE_WAIT) + feedback_running_count ++; + } +#endif + } + + if ((stream_running_count > 0) +#if defined(UX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT) + || (interrupt_running_count > 0) +#endif +#if defined(UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT) + || (feedback_running_count > 0) +#endif + ) + { + return UX_STATE_WAIT; + } + else + { + return UX_STATE_IDLE; + } +} + +#endif \ No newline at end of file diff --git a/common/usbx_device_classes/src/ux_device_class_audio_transmission_start.c b/common/usbx_device_classes/src/ux_device_class_audio_transmission_start.c index 050390c9..69b58c50 100644 --- a/common/usbx_device_classes/src/ux_device_class_audio_transmission_start.c +++ b/common/usbx_device_classes/src/ux_device_class_audio_transmission_start.c @@ -34,7 +34,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_audio_transmission_start PORTABLE C */ -/* 6.1.10 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -70,6 +70,9 @@ /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */ /* refined macros names, */ /* resulting in version 6.1.10 */ +/* 10-31-2022 Yajun Xia Modified comment(s), */ +/* added standalone support, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_device_class_audio_transmission_start(UX_DEVICE_CLASS_AUDIO_STREAM *stream) @@ -103,7 +106,15 @@ UX_SLAVE_DEVICE *device; if (stream -> ux_device_class_audio_stream_transfer_pos -> ux_device_class_audio_frame_length == 0) return(UX_BUFFER_OVERFLOW); +#if defined(UX_DEVICE_STANDALONE) + + /* Start write task. */ + if (stream -> ux_device_class_audio_stream_task_state == UX_DEVICE_CLASS_AUDIO_STREAM_RW_STOP) + stream -> ux_device_class_audio_stream_task_state = UX_DEVICE_CLASS_AUDIO_STREAM_RW_START; +#else + /* Start write thread. */ _ux_device_thread_resume(&stream -> ux_device_class_audio_stream_thread); +#endif return(UX_SUCCESS); } diff --git a/common/usbx_device_classes/src/ux_device_class_audio_write_task_function.c b/common/usbx_device_classes/src/ux_device_class_audio_write_task_function.c new file mode 100644 index 00000000..2c30a3c3 --- /dev/null +++ b/common/usbx_device_classes/src/ux_device_class_audio_write_task_function.c @@ -0,0 +1,210 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** USBX Component */ +/** */ +/** Device Audio Class */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define UX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "ux_api.h" +#include "ux_device_class_audio.h" +#include "ux_device_stack.h" + + +#if defined(UX_DEVICE_STANDALONE) +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _ux_device_class_audio_write_task_function PORTABLE C */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Yajun Xia, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the background task of the audio stream write. */ +/* */ +/* It's for standalone mode. */ +/* */ +/* INPUT */ +/* */ +/* audio_class Address of audio class */ +/* container */ +/* */ +/* OUTPUT */ +/* */ +/* State machine status */ +/* UX_STATE_EXIT Device not configured */ +/* UX_STATE_IDLE No streaming transfer running */ +/* UX_STATE_WAIT Streaming transfer running */ +/* */ +/* CALLS */ +/* */ +/* _ux_device_stack_transfer_run Run transfer state machine */ +/* _ux_utility_memory_copy Copy memory */ +/* */ +/* CALLED BY */ +/* */ +/* USBX Device Stack */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Yajun Xia Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ +UINT _ux_device_class_audio_write_task_function(UX_DEVICE_CLASS_AUDIO_STREAM *stream) +{ +UX_SLAVE_DEVICE *device; +UX_SLAVE_ENDPOINT *endpoint; +UX_SLAVE_TRANSFER *transfer; +UCHAR *next_pos; +UX_DEVICE_CLASS_AUDIO_FRAME *next_frame; +ULONG transfer_length; +ULONG actual_length; +UINT status; + + + /* Get the pointer to the device. */ + device = stream -> ux_device_class_audio_stream_audio -> ux_device_class_audio_device; + + /* Check if the device is configured. */ + if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED) + { + stream -> ux_device_class_audio_stream_task_state = UX_STATE_EXIT; + return(UX_STATE_EXIT); + } + + /* Get the endpoint. */ + endpoint = stream -> ux_device_class_audio_stream_endpoint; + + /* No endpoint ready, maybe it's alternate setting 0. */ + if (endpoint == UX_NULL) + return(UX_STATE_IDLE); + + /* Check if background transfer task is started. */ + if (stream -> ux_device_class_audio_stream_task_state == UX_DEVICE_CLASS_AUDIO_STREAM_RW_STOP) + return(UX_STATE_IDLE); + + /* Get transfer instance. */ + transfer = &endpoint -> ux_slave_endpoint_transfer_request; + + /* If not started yet, prepare data, reset transfer and start polling. */ + if (stream -> ux_device_class_audio_stream_task_state == UX_DEVICE_CLASS_AUDIO_STREAM_RW_START) + { + + /* Next state: transfer wait. */ + stream -> ux_device_class_audio_stream_task_state = UX_DEVICE_CLASS_AUDIO_STREAM_RW_WAIT; + + /* Start frame transfer anyway (even ZLP). */ + transfer_length = stream -> ux_device_class_audio_stream_transfer_pos -> ux_device_class_audio_frame_length; + if (transfer_length) + _ux_utility_memory_copy(transfer -> ux_slave_transfer_request_data_pointer, + stream -> ux_device_class_audio_stream_transfer_pos -> ux_device_class_audio_frame_data, transfer_length); /* Use case of memcpy is verified. */ + + /* Reset transfer state. */ + UX_SLAVE_TRANSFER_STATE_RESET(transfer); + } + + /* Get current transfer length. */ + transfer_length = stream -> ux_device_class_audio_stream_transfer_pos -> ux_device_class_audio_frame_length; + + /* Run transfer states. */ + status = _ux_device_stack_transfer_run(transfer, transfer_length, transfer_length); + + /* Error case. */ + if (status < UX_STATE_NEXT) + { + + /* Error on background transfer task start. */ + stream -> ux_device_class_audio_stream_task_state = UX_STATE_RESET; + stream -> ux_device_class_audio_stream_task_status = + transfer -> ux_slave_transfer_request_completion_code; + + /* Error notification! */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_ERROR); + return(UX_STATE_EXIT); + } + + /* Success case. */ + if (status == UX_STATE_NEXT) + { + + /* Next state: start. */ + stream -> ux_device_class_audio_stream_task_state = UX_DEVICE_CLASS_AUDIO_STREAM_RW_START; + stream -> ux_device_class_audio_stream_task_status = + transfer -> ux_slave_transfer_request_completion_code; + + /* Frame sent, free it. */ + stream -> ux_device_class_audio_stream_transfer_pos -> ux_device_class_audio_frame_length = 0; + + /* Get actual transfer length. */ + actual_length = transfer -> ux_slave_transfer_request_actual_length; + + /* Calculate next position. */ + next_pos = (UCHAR *)stream -> ux_device_class_audio_stream_transfer_pos; + next_pos += stream -> ux_device_class_audio_stream_frame_buffer_size; + if (next_pos >= stream -> ux_device_class_audio_stream_buffer + stream -> ux_device_class_audio_stream_buffer_size) + next_pos = stream -> ux_device_class_audio_stream_buffer; + next_frame = (UX_DEVICE_CLASS_AUDIO_FRAME *)next_pos; + + /* Underflow check! */ + if (transfer_length) + { + + /* Advance position. */ + stream -> ux_device_class_audio_stream_transfer_pos = next_frame; + + /* Error trap! */ + if (next_frame -> ux_device_class_audio_frame_length == 0) + { + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_BUFFER_OVERFLOW); + stream -> ux_device_class_audio_stream_buffer_error_count ++; + } + } + else + { + + /* Advance position if next payload available. */ + if (next_frame -> ux_device_class_audio_frame_length) + stream -> ux_device_class_audio_stream_transfer_pos = next_frame; + else + { + + /* Error trap! */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_BUFFER_OVERFLOW); + stream -> ux_device_class_audio_stream_buffer_error_count ++; + } + } + + /* Invoke notification callback. */ + if (stream -> ux_device_class_audio_stream_callbacks.ux_device_class_audio_stream_frame_done != UX_NULL) + stream -> ux_device_class_audio_stream_callbacks.ux_device_class_audio_stream_frame_done(stream, actual_length); + } + + /* Keep waiting. */ + return(UX_STATE_WAIT); +} +#endif + diff --git a/common/usbx_device_classes/src/ux_device_class_audio_write_thread_entry.c b/common/usbx_device_classes/src/ux_device_class_audio_write_thread_entry.c index f6c1cf0e..ce6bd7bf 100644 --- a/common/usbx_device_classes/src/ux_device_class_audio_write_thread_entry.c +++ b/common/usbx_device_classes/src/ux_device_class_audio_write_thread_entry.c @@ -34,7 +34,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_audio_write_thread_entry PORTABLE C */ -/* 6.1.10 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -75,6 +75,9 @@ /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */ /* refined macros names, */ /* resulting in version 6.1.10 */ +/* 10-31-2022 Yajun Xia Modified comment(s), */ +/* added standalone support, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ VOID _ux_device_class_audio_write_thread_entry(ULONG audio_stream) @@ -153,7 +156,10 @@ ULONG actual_length; /* Error trap! */ if (next_frame -> ux_device_class_audio_frame_length == 0) + { + stream -> ux_device_class_audio_stream_buffer_error_count ++; _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_BUFFER_OVERFLOW); + } } else { @@ -162,9 +168,12 @@ ULONG actual_length; if (next_frame -> ux_device_class_audio_frame_length) stream -> ux_device_class_audio_stream_transfer_pos = next_frame; else + { /* Error trap! */ _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_BUFFER_OVERFLOW); + stream -> ux_device_class_audio_stream_buffer_error_count ++; + } } /* Invoke notification callback. */ diff --git a/common/usbx_device_classes/src/ux_device_class_cdc_acm_read_run.c b/common/usbx_device_classes/src/ux_device_class_cdc_acm_read_run.c index 4086b03c..e89212a9 100644 --- a/common/usbx_device_classes/src/ux_device_class_cdc_acm_read_run.c +++ b/common/usbx_device_classes/src/ux_device_class_cdc_acm_read_run.c @@ -37,7 +37,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_cdc_acm_read_run PORTABLE C */ -/* 6.1.10 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -79,6 +79,9 @@ /* DATE NAME DESCRIPTION */ /* */ /* 01-31-2022 Chaoqiong Xiao Initial Version 6.1.10 */ +/* 10-31-2022 Yajun Xia Modified comment(s), */ +/* fixed return code, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_device_class_cdc_acm_read_run(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, @@ -200,7 +203,7 @@ UINT status = UX_SUCCESS; cdc_acm -> ux_device_class_cdc_acm_read_state = UX_STATE_RESET; cdc_acm -> ux_device_class_cdc_acm_read_status = transfer_request -> ux_slave_transfer_request_completion_code; - return(UX_STATE_EXIT); + return(UX_STATE_ERROR); } /* Success case. */ diff --git a/common/usbx_device_classes/src/ux_device_class_cdc_acm_tasks_run.c b/common/usbx_device_classes/src/ux_device_class_cdc_acm_tasks_run.c index 63c4e8f6..55f5dddb 100644 --- a/common/usbx_device_classes/src/ux_device_class_cdc_acm_tasks_run.c +++ b/common/usbx_device_classes/src/ux_device_class_cdc_acm_tasks_run.c @@ -31,8 +31,11 @@ #if defined(UX_DEVICE_STANDALONE) + +#ifndef UX_DEVICE_CLASS_CDC_ACM_TRANSMISSION_DISABLE static inline VOID _ux_device_class_cdc_acm_transmission_read_run(UX_SLAVE_CLASS_CDC_ACM *cdc_acm); static inline VOID _ux_device_class_cdc_acm_transmission_write_run(UX_SLAVE_CLASS_CDC_ACM *cdc_acm); +#endif /**************************************************************************/ @@ -40,7 +43,7 @@ static inline VOID _ux_device_class_cdc_acm_transmission_write_run(UX_SLAVE_CLAS /* FUNCTION RELEASE */ /* */ /* _ux_device_class_cdc_acm_tasks_run PORTABLE C */ -/* 6.1.12 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -80,21 +83,23 @@ static inline VOID _ux_device_class_cdc_acm_transmission_write_run(UX_SLAVE_CLAS /* names conflict C++ keyword, */ /* supported write auto ZLP, */ /* resulting in version 6.1.12 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* fixed compile warnings, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_device_class_cdc_acm_tasks_run(VOID *instance) { -UX_SLAVE_DEVICE *device; -UX_SLAVE_CLASS_CDC_ACM *cdc_acm; UINT status = UX_STATE_IDLE; +#ifndef UX_DEVICE_CLASS_CDC_ACM_TRANSMISSION_DISABLE +UX_SLAVE_DEVICE *device; +UX_SLAVE_CLASS_CDC_ACM *cdc_acm; /* Get CDC ACM instance. */ cdc_acm = (UX_SLAVE_CLASS_CDC_ACM*) instance; -#ifndef UX_DEVICE_CLASS_CDC_ACM_TRANSMISSION_DISABLE - /* Check if transmission is started. */ if (!cdc_acm -> ux_slave_class_cdc_acm_transmission_status) return(status); diff --git a/common/usbx_device_classes/src/ux_device_class_cdc_acm_write_run.c b/common/usbx_device_classes/src/ux_device_class_cdc_acm_write_run.c index 630bea7d..35ea2ad3 100644 --- a/common/usbx_device_classes/src/ux_device_class_cdc_acm_write_run.c +++ b/common/usbx_device_classes/src/ux_device_class_cdc_acm_write_run.c @@ -37,7 +37,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_cdc_acm_write_run PORTABLE C */ -/* 6.1.12 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -83,6 +83,9 @@ /* names conflict C++ keyword, */ /* added auto ZLP support, */ /* resulting in version 6.1.12 */ +/* 10-31-2022 Yajun Xia Modified comment(s), */ +/* fixed return code, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_device_class_cdc_acm_write_run(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, @@ -125,7 +128,7 @@ UINT status = 0; cdc_acm -> ux_device_class_cdc_acm_write_state = UX_STATE_RESET; cdc_acm -> ux_device_class_cdc_acm_write_status = UX_CONFIGURATION_HANDLE_UNKNOWN; - return(UX_CONFIGURATION_HANDLE_UNKNOWN); + return(UX_STATE_EXIT); } /* We need the interface to the class. */ @@ -224,7 +227,7 @@ UINT status = 0; cdc_acm -> ux_device_class_cdc_acm_write_state = UX_STATE_RESET; cdc_acm -> ux_device_class_cdc_acm_write_status = transfer_request -> ux_slave_transfer_request_completion_code; - return(UX_STATE_EXIT); + return(UX_STATE_ERROR); } /* Success case. */ diff --git a/common/usbx_device_classes/src/ux_device_class_cdc_ecm_bulkin_thread.c b/common/usbx_device_classes/src/ux_device_class_cdc_ecm_bulkin_thread.c index a30a9bda..57968f64 100644 --- a/common/usbx_device_classes/src/ux_device_class_cdc_ecm_bulkin_thread.c +++ b/common/usbx_device_classes/src/ux_device_class_cdc_ecm_bulkin_thread.c @@ -35,7 +35,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_cdc_ecm_bulkin_thread PORTABLE C */ -/* 6.1.11 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -83,6 +83,9 @@ /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */ /* fixed standalone compile, */ /* resulting in version 6.1.11 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* used NX API to copy data, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ VOID _ux_device_class_cdc_ecm_bulkin_thread(ULONG cdc_ecm_class) @@ -95,8 +98,8 @@ UX_SLAVE_TRANSFER *transfer_request; UINT status; ULONG actual_flags; NX_PACKET *current_packet; -UCHAR *packet_header; ULONG transfer_length; +ULONG copied; /* Cast properly the cdc_ecm instance. */ UX_THREAD_EXTENSION_PTR_GET(class_ptr, UX_SLAVE_CLASS, cdc_ecm_class) @@ -148,24 +151,26 @@ ULONG transfer_length; if (cdc_ecm -> ux_slave_class_cdc_ecm_link_state == UX_DEVICE_CLASS_CDC_ECM_LINK_STATE_UP) { - /* Load the address of the current packet header at the physical header. */ - packet_header = current_packet -> nx_packet_prepend_ptr; - /* Can the packet fit in the transfer requests data buffer? */ if (current_packet -> nx_packet_length <= UX_SLAVE_REQUEST_DATA_MAX_LENGTH) { /* Copy the packet in the transfer descriptor buffer. */ - _ux_utility_memory_copy(transfer_request -> ux_slave_transfer_request_data_pointer, packet_header, current_packet -> nx_packet_length); /* Use case of memcpy is verified. */ + status = nx_packet_data_extract_offset(current_packet, 0, + transfer_request -> ux_slave_transfer_request_data_pointer, + current_packet -> nx_packet_length, &copied); + if (status == UX_SUCCESS) + { - /* Calculate the transfer length. */ - transfer_length = current_packet -> nx_packet_length; - - /* If trace is enabled, insert this event into the trace buffer. */ - UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_CDC_ECM_PACKET_TRANSMIT, cdc_ecm, 0, 0, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0) + /* Calculate the transfer length. */ + transfer_length = current_packet -> nx_packet_length; + + /* If trace is enabled, insert this event into the trace buffer. */ + UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_CDC_ECM_PACKET_TRANSMIT, cdc_ecm, 0, 0, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0) - /* Send the request to the device controller. */ - status = _ux_device_stack_transfer_request(transfer_request, transfer_length, UX_DEVICE_CLASS_CDC_ECM_ETHERNET_PACKET_SIZE); + /* Send the request to the device controller. */ + status = _ux_device_stack_transfer_request(transfer_request, transfer_length, UX_DEVICE_CLASS_CDC_ECM_ETHERNET_PACKET_SIZE + 1); + } /* Check error code. */ if (status != UX_SUCCESS) diff --git a/common/usbx_device_classes/src/ux_device_class_cdc_ecm_bulkout_thread.c b/common/usbx_device_classes/src/ux_device_class_cdc_ecm_bulkout_thread.c index 6b0ba9fc..8b1cc267 100644 --- a/common/usbx_device_classes/src/ux_device_class_cdc_ecm_bulkout_thread.c +++ b/common/usbx_device_classes/src/ux_device_class_cdc_ecm_bulkout_thread.c @@ -35,7 +35,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_cdc_ecm_bulkout_thread PORTABLE C */ -/* 6.1.11 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -83,6 +83,11 @@ /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */ /* fixed standalone compile, */ /* resulting in version 6.1.11 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* fixed EP not ready issue, */ +/* used pool from NX IP inst, */ +/* used NX API to copy data, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ VOID _ux_device_class_cdc_ecm_bulkout_thread(ULONG cdc_ecm_class) @@ -94,7 +99,7 @@ UX_SLAVE_DEVICE *device; UX_SLAVE_TRANSFER *transfer_request; UINT status; NX_PACKET *packet; -ULONG ip_given_length; +USB_NETWORK_DEVICE_TYPE *ux_nx_device; /* Cast properly the cdc_ecm instance. */ UX_THREAD_EXTENSION_PTR_GET(class_ptr, UX_SLAVE_CLASS, cdc_ecm_class) @@ -113,8 +118,38 @@ ULONG ip_given_length; while (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED) { + /* Check if packet pool is ready. */ + if (cdc_ecm -> ux_slave_class_cdc_ecm_packet_pool == UX_NULL) + { + + /* Get the network device handle. */ + ux_nx_device = (USB_NETWORK_DEVICE_TYPE *)(cdc_ecm -> ux_slave_class_cdc_ecm_network_handle); + + /* Get packet pool from IP instance (if available). */ + if (ux_nx_device -> ux_network_device_ip_instance != UX_NULL) + { + cdc_ecm -> ux_slave_class_cdc_ecm_packet_pool = ux_nx_device -> ux_network_device_ip_instance -> nx_ip_default_packet_pool; + } + else + { + + /* Error trap. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CLASS_ETH_PACKET_POOL_ERROR); + + _ux_utility_delay_ms(UX_DEVICE_CLASS_CDC_ECM_PACKET_POOL_INST_WAIT); + continue; + } + } + + /* Check if Bulk OUT endpoint is ready. */ + if (cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_endpoint == UX_NULL) + { + _ux_utility_delay_ms(UX_DEVICE_CLASS_CDC_ECM_LINK_CHECK_WAIT); + continue; + } + /* We can accept new reception. Get a NX Packet */ - status = nx_packet_allocate(&cdc_ecm -> ux_slave_class_cdc_ecm_packet_pool, &packet, + status = nx_packet_allocate(cdc_ecm -> ux_slave_class_cdc_ecm_packet_pool, &packet, NX_RECEIVE_PACKET, UX_MS_TO_TICK(UX_DEVICE_CLASS_CDC_ECM_PACKET_POOL_WAIT)); if (status == NX_SUCCESS) @@ -136,7 +171,7 @@ ULONG ip_given_length; /* Send the request to the device controller. */ status = _ux_device_stack_transfer_request(transfer_request, UX_DEVICE_CLASS_CDC_ECM_MAX_PACKET_LENGTH, UX_DEVICE_CLASS_CDC_ECM_MAX_PACKET_LENGTH); - + /* Check the completion code. */ if (status == UX_SUCCESS) { @@ -147,26 +182,27 @@ ULONG ip_given_length; /* Adjust the prepend pointer to take into account the non 3 bit alignment of the ethernet header. */ packet -> nx_packet_prepend_ptr += sizeof(USHORT); - - /* Set the prepend, length, and append fields. */ - packet -> nx_packet_length = transfer_request -> ux_slave_transfer_request_actual_length; - packet -> nx_packet_append_ptr = packet -> nx_packet_prepend_ptr + transfer_request -> ux_slave_transfer_request_actual_length; - + packet -> nx_packet_append_ptr += sizeof(USHORT); + /* Copy the received packet in the IP packet data area. */ - _ux_utility_memory_copy(packet -> nx_packet_prepend_ptr, transfer_request -> ux_slave_transfer_request_data_pointer, packet -> nx_packet_length); /* Use case of memcpy is verified. */ - - /* Calculate the accurate packet length from ip header. */ - if((*(packet -> nx_packet_prepend_ptr + 12) == 0x08) && - (*(packet -> nx_packet_prepend_ptr + 13) == 0)) + status = nx_packet_data_append(packet, + transfer_request -> ux_slave_transfer_request_data_pointer, + transfer_request -> ux_slave_transfer_request_actual_length, + cdc_ecm -> ux_slave_class_cdc_ecm_packet_pool, + UX_MS_TO_TICK(UX_DEVICE_CLASS_CDC_ECM_PACKET_POOL_WAIT)); + if (status == NX_SUCCESS) + { + + /* Send that packet to the NetX USB broker. */ + _ux_network_driver_packet_received(cdc_ecm -> ux_slave_class_cdc_ecm_network_handle, packet); + } + else { - ip_given_length = _ux_utility_short_get_big_endian(packet -> nx_packet_prepend_ptr + 16) + UX_DEVICE_CLASS_CDC_ECM_ETHERNET_SIZE; - packet -> nx_packet_length = ip_given_length ; - packet -> nx_packet_append_ptr = packet -> nx_packet_prepend_ptr + ip_given_length; + /* We received a malformed packet. Report to application. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CLASS_MALFORMED_PACKET_RECEIVED_ERROR); + nx_packet_release(packet); } - - /* Send that packet to the NetX USB broker. */ - _ux_network_driver_packet_received(cdc_ecm -> ux_slave_class_cdc_ecm_network_handle, packet); } else diff --git a/common/usbx_device_classes/src/ux_device_class_cdc_ecm_initialize.c b/common/usbx_device_classes/src/ux_device_class_cdc_ecm_initialize.c index f1723be2..84ae21ba 100644 --- a/common/usbx_device_classes/src/ux_device_class_cdc_ecm_initialize.c +++ b/common/usbx_device_classes/src/ux_device_class_cdc_ecm_initialize.c @@ -27,14 +27,13 @@ #include "ux_device_class_cdc_ecm.h" #include "ux_device_stack.h" -UX_DEVICE_CLASS_CDC_ECM_NX_ETHERNET_POOL_ALLOCSIZE_ASSERT /**************************************************************************/ /* */ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_cdc_ecm_initialize PORTABLE C */ -/* 6.1.12 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -61,8 +60,6 @@ UX_DEVICE_CLASS_CDC_ECM_NX_ETHERNET_POOL_ALLOCSIZE_ASSERT /* _ux_utility_event_flags_delete Delete Flag group */ /* _ux_device_thread_create Create Thread */ /* _ux_device_thread_delete Delete Thread */ -/* nx_packet_pool_create Create NetX packet pool */ -/* nx_packet_pool_delete Delete NetX packet pool */ /* */ /* CALLED BY */ /* */ @@ -89,6 +86,9 @@ UX_DEVICE_CLASS_CDC_ECM_NX_ETHERNET_POOL_ALLOCSIZE_ASSERT /* fixed parameter/variable */ /* names conflict C++ keyword, */ /* resulting in version 6.1.12 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* removed internal NX pool, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_device_class_cdc_ecm_initialize(UX_SLAVE_CLASS_COMMAND *command) @@ -153,28 +153,6 @@ UINT status; status = (UX_MEMORY_INSUFFICIENT); } - /* Allocate some packet pool for reception. */ - if (status == UX_SUCCESS) - { - - /* UX_DEVICE_CLASS_CDC_ECM_NX_ETHERNET_POOL_ALLOCSIZE overflow has been checked by - * UX_DEVICE_CLASS_CDC_ECM_NX_ETHERNET_POOL_ALLOCSIZE_ASSERT outside of function. - */ - cdc_ecm -> ux_slave_class_cdc_ecm_pool_memory = - _ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY, UX_DEVICE_CLASS_CDC_ECM_NX_ETHERNET_POOL_ALLOCSIZE); - - /* Check for successful allocation. */ - if (cdc_ecm -> ux_slave_class_cdc_ecm_pool_memory == UX_NULL) - status = (UX_MEMORY_INSUFFICIENT); - else - { - /* Create a packet pool. */ - status = nx_packet_pool_create(&cdc_ecm -> ux_slave_class_cdc_ecm_packet_pool, "CDC ECM Device Packet Pool", - UX_DEVICE_CLASS_CDC_ECM_NX_PAYLOAD_SIZE, cdc_ecm -> ux_slave_class_cdc_ecm_pool_memory, - UX_DEVICE_CLASS_CDC_ECM_NX_ETHERNET_POOL_ALLOCSIZE); - } - } - /* Interrupt endpoint treatment needs to be running in a different thread. So start a new thread. We pass a pointer to the cdc_ecm instance to the new thread. This thread does not start until we have a instance of the class. */ @@ -267,10 +245,6 @@ UINT status; /* Free allocated resources. */ - if (cdc_ecm -> ux_slave_class_cdc_ecm_packet_pool.nx_packet_pool_id) - nx_packet_pool_delete(&cdc_ecm -> ux_slave_class_cdc_ecm_packet_pool); - if (cdc_ecm -> ux_slave_class_cdc_ecm_pool_memory) - _ux_utility_memory_free(cdc_ecm -> ux_slave_class_cdc_ecm_pool_memory); if (cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_thread_stack) _ux_utility_memory_free(cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_thread_stack); if (cdc_ecm -> ux_slave_class_cdc_ecm_interrupt_thread_stack) diff --git a/common/usbx_device_classes/src/ux_device_class_cdc_ecm_uninitialize.c b/common/usbx_device_classes/src/ux_device_class_cdc_ecm_uninitialize.c index c429632f..43ae2175 100644 --- a/common/usbx_device_classes/src/ux_device_class_cdc_ecm_uninitialize.c +++ b/common/usbx_device_classes/src/ux_device_class_cdc_ecm_uninitialize.c @@ -35,7 +35,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_cdc_ecm_uninitialize PORTABLE C */ -/* 6.1.12 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -82,6 +82,9 @@ /* fixed parameter/variable */ /* names conflict C++ keyword, */ /* resulting in version 6.1.12 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* removed internal NX pool, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_device_class_cdc_ecm_uninitialize(UX_SLAVE_CLASS_COMMAND *command) @@ -131,14 +134,8 @@ UX_SLAVE_CLASS *class_ptr; /* Delete the interrupt thread sync event flags group. */ _ux_device_event_flags_delete(&cdc_ecm -> ux_slave_class_cdc_ecm_event_flags_group); - /* Delete the reception packet pool. */ - nx_packet_pool_delete(&cdc_ecm -> ux_slave_class_cdc_ecm_packet_pool); - #endif - /* Free the packet pool memory. */ - _ux_utility_memory_free(cdc_ecm -> ux_slave_class_cdc_ecm_pool_memory); - /* Free the resources. */ _ux_utility_memory_free(cdc_ecm); } diff --git a/common/usbx_device_classes/src/ux_device_class_hid_control_request.c b/common/usbx_device_classes/src/ux_device_class_hid_control_request.c old mode 100755 new mode 100644 diff --git a/common/usbx_device_classes/src/ux_device_class_hid_initialize.c b/common/usbx_device_classes/src/ux_device_class_hid_initialize.c index 22f8e46b..74fc89b5 100644 --- a/common/usbx_device_classes/src/ux_device_class_hid_initialize.c +++ b/common/usbx_device_classes/src/ux_device_class_hid_initialize.c @@ -33,7 +33,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_hid_initialize PORTABLE C */ -/* 6.1.12 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -85,6 +85,9 @@ /* fixed parameter/variable */ /* names conflict C++ keyword, */ /* resulting in version 6.1.12 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* fixed compile warnings, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_device_class_hid_initialize(UX_SLAVE_CLASS_COMMAND *command) @@ -228,8 +231,13 @@ UINT status = UX_SUCCESS; } +#if !defined(UX_DEVICE_STANDALONE) || defined(UX_DEVICE_CLASS_HID_INTERRUPT_OUT_SUPPORT) + + /* There is still initialization activities after array creation, + * and some error occurs in this stage. */ /* Free allocated event array memory. */ _ux_utility_memory_free(hid -> ux_device_class_hid_event_array); +#endif } else diff --git a/common/usbx_device_classes/src/ux_device_class_printer_initialize.c b/common/usbx_device_classes/src/ux_device_class_printer_initialize.c index 1007d29e..f07e4462 100644 --- a/common/usbx_device_classes/src/ux_device_class_printer_initialize.c +++ b/common/usbx_device_classes/src/ux_device_class_printer_initialize.c @@ -33,7 +33,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_printer_initialize PORTABLE C */ -/* 6.1.11 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -69,19 +69,20 @@ /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */ /* fixed standalone compile, */ /* resulting in version 6.1.11 */ +/* 10-31-2022 Yajun Xia Modified comment(s), */ +/* added standalone support, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_device_class_printer_initialize(UX_SLAVE_CLASS_COMMAND *command) { -#if defined(UX_DEVICE_STANDALONE) - UX_PARAMETER_NOT_USED(command); - return(UX_FUNCTION_NOT_SUPPORTED); -#else UX_DEVICE_CLASS_PRINTER *printer; UX_DEVICE_CLASS_PRINTER_PARAMETER *printer_parameter; UX_SLAVE_CLASS *printer_class; +#if !defined(UX_DEVICE_STANDALONE) UINT status; +#endif /* Get the class container. */ printer_class = command -> ux_slave_class_command_class_ptr; @@ -105,6 +106,7 @@ UINT status; printer -> ux_device_class_printer_parameter.ux_device_class_printer_instance_deactivate = printer_parameter -> ux_device_class_printer_instance_deactivate; printer -> ux_device_class_printer_parameter.ux_device_class_printer_soft_reset = printer_parameter -> ux_device_class_printer_soft_reset; +#if !defined(UX_DEVICE_STANDALONE) /* Create the Mutex for each endpoint as multiple threads cannot access each pipe at the same time. */ status = _ux_utility_mutex_create(&printer -> ux_device_class_printer_endpoint_in_mutex, "ux_device_class_printer_in_mutex"); @@ -135,11 +137,14 @@ UINT status; /* Return fatal error. */ return(UX_MUTEX_ERROR); } +#else + printer -> ux_device_class_printer_write_state = UX_STATE_RESET; + printer -> ux_device_class_printer_read_state = UX_STATE_RESET; +#endif /* Reset port status. */ printer -> ux_device_class_printer_port_status = 0; /* Return completion status. */ return(UX_SUCCESS); -#endif } diff --git a/common/usbx_device_classes/src/ux_device_class_printer_read_run.c b/common/usbx_device_classes/src/ux_device_class_printer_read_run.c new file mode 100644 index 00000000..acfb3901 --- /dev/null +++ b/common/usbx_device_classes/src/ux_device_class_printer_read_run.c @@ -0,0 +1,238 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** USBX Component */ +/** */ +/** Device Printer Class */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define UX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "ux_api.h" +#include "ux_device_class_printer.h" +#include "ux_device_stack.h" + + +#if defined(UX_DEVICE_STANDALONE) + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _ux_device_class_printer_read_run PORTABLE C */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Yajun Xia, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function reads from the Printer class. */ +/* */ +/* It's for standalone mode. */ +/* */ +/* INPUT */ +/* */ +/* printer Address of printer 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 */ +/* */ +/* OUTPUT */ +/* */ +/* State machine Status to check */ +/* UX_STATE_NEXT Transfer done, to next state */ +/* UX_STATE_EXIT Abnormal, to reset state */ +/* (others) Keep running, waiting */ +/* */ +/* CALLS */ +/* */ +/* _ux_device_stack_transfer_run Transfer request */ +/* _ux_utility_memory_copy Copy memory */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Yajun xia Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ +UINT _ux_device_class_printer_read_run(UX_DEVICE_CLASS_PRINTER *printer, UCHAR *buffer, + ULONG requested_length, ULONG *actual_length) +{ + +UX_SLAVE_ENDPOINT *endpoint; +UX_SLAVE_DEVICE *device; +UX_SLAVE_TRANSFER *transfer_request; +ULONG max_transfer_length; +UINT status = UX_SUCCESS; + + /* If trace is enabled, insert this event into the trace buffer. */ + UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_PRINTER_READ, printer, buffer, requested_length, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0) + + /* Get the pointer to the device. */ + device = &_ux_system_slave -> ux_system_slave_device; + + /* As long as the device is in the CONFIGURED state. */ + if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED) + { + + /* Error trap. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CONFIGURATION_HANDLE_UNKNOWN); + + /* If trace is enabled, insert this event into the trace buffer. */ + UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_CONFIGURATION_HANDLE_UNKNOWN, device, 0, 0, UX_TRACE_ERRORS, 0, 0) + + /* Cannot proceed with command, the interface is down. */ + printer -> ux_device_class_printer_read_state = UX_STATE_RESET; + printer -> ux_device_class_printer_read_status = UX_CONFIGURATION_HANDLE_UNKNOWN; + + return(UX_STATE_EXIT); + } + + /* Locate the endpoint. */ + endpoint = printer -> ux_device_class_printer_endpoint_out; + + /* All Printer reading are on the endpoint OUT, from the host. */ + transfer_request = &endpoint -> ux_slave_endpoint_transfer_request; + + /* Handle state cases. */ + switch(printer -> ux_device_class_printer_read_state) + { + case UX_STATE_RESET: + + /* If trace is enabled, insert this event into the trace buffer. */ + UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_PRINTER_READ, printer, buffer, requested_length, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0) + + printer -> ux_device_class_printer_read_state = UX_DEVICE_CLASS_PRINTER_READ_START; + printer -> ux_device_class_printer_read_status = UX_TRANSFER_NO_ANSWER; + printer -> ux_device_class_printer_read_buffer = buffer; + printer -> ux_device_class_printer_read_requested_length = requested_length; + printer -> ux_device_class_printer_read_actual_length = 0; + + /* Fall through. */ + case UX_DEVICE_CLASS_PRINTER_READ_START: + + /* Get remaining transfer length. */ + requested_length = printer -> ux_device_class_printer_read_requested_length - + printer -> ux_device_class_printer_read_actual_length; + + /* There is nothing remaining, it's done. */ + if (requested_length == 0) + { + *actual_length = printer -> ux_device_class_printer_read_actual_length; + printer -> ux_device_class_printer_read_state = UX_STATE_RESET; + printer -> ux_device_class_printer_read_status = UX_SUCCESS; + return(UX_STATE_NEXT); + } + + printer -> ux_device_class_printer_read_transfer_length = requested_length; + + /* Next state. */ + printer -> ux_device_class_printer_read_state = UX_DEVICE_CLASS_PRINTER_READ_WAIT; + UX_SLAVE_TRANSFER_STATE_RESET(transfer_request); + + /* Fall through. */ + case UX_DEVICE_CLASS_PRINTER_READ_WAIT: + + /* Get a full packet each time */ + max_transfer_length = endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize; + + /* Run the transfer state machine. */ + status = _ux_device_stack_transfer_run(transfer_request, + max_transfer_length, + max_transfer_length); + + /* Error case. */ + if (status < UX_STATE_NEXT) + { + printer -> ux_device_class_printer_read_state = UX_STATE_RESET; + printer -> ux_device_class_printer_read_status = + transfer_request -> ux_slave_transfer_request_completion_code; + return(UX_STATE_ERROR); + } + + /* Success case. */ + if (status == UX_STATE_NEXT) + { + /* Check overflow */ + if (printer -> ux_device_class_printer_read_transfer_length < + transfer_request -> ux_slave_transfer_request_actual_length) + { + printer -> ux_device_class_printer_read_state = UX_STATE_ERROR; + printer -> ux_device_class_printer_read_status = UX_TRANSFER_BUFFER_OVERFLOW; + return(UX_STATE_ERROR); + } + + /* We need to copy the buffer locally. */ + _ux_utility_memory_copy(printer -> ux_device_class_printer_read_buffer, + transfer_request -> ux_slave_transfer_request_data_pointer, + transfer_request -> ux_slave_transfer_request_actual_length); /* Use case of memcpy is verified. */ + + /* Next buffer address. */ + printer -> ux_device_class_printer_read_buffer += + transfer_request -> ux_slave_transfer_request_actual_length; + + /* Set the length actually received. */ + printer -> ux_device_class_printer_read_actual_length += + transfer_request -> ux_slave_transfer_request_actual_length; + + /* Last transfer status. */ + printer -> ux_device_class_printer_read_status = + transfer_request -> ux_slave_transfer_request_completion_code; + + /* Update actual length. */ + *actual_length = printer -> ux_device_class_printer_read_actual_length; + + /* Check short packet. */ + if (transfer_request -> ux_slave_transfer_request_actual_length < + transfer_request -> ux_slave_transfer_request_requested_length) + { + + /* It's done. */ + printer -> ux_device_class_printer_read_state = UX_STATE_RESET; + return(UX_STATE_NEXT); + } + + /* Next state. */ + printer -> ux_device_class_printer_read_state = UX_DEVICE_CLASS_PRINTER_READ_START; + } + + /* Keep waiting. */ + return(UX_STATE_WAIT); + + default: /* Error. */ + printer -> ux_device_class_printer_read_state = UX_STATE_RESET; + printer -> ux_device_class_printer_read_status = UX_INVALID_STATE; + break; + } + + /* Error cases. */ + return(UX_STATE_EXIT); +} + +#endif diff --git a/common/usbx_device_classes/src/ux_device_class_printer_soft_reset.c b/common/usbx_device_classes/src/ux_device_class_printer_soft_reset.c index fa96f3b7..9d41d968 100644 --- a/common/usbx_device_classes/src/ux_device_class_printer_soft_reset.c +++ b/common/usbx_device_classes/src/ux_device_class_printer_soft_reset.c @@ -34,7 +34,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_printer_soft_reset PORTABLE C */ -/* 6.1.10 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -66,6 +66,9 @@ /* DATE NAME DESCRIPTION */ /* */ /* 01-31-2022 Chaoqiong Xiao Initial Version 6.1.10 */ +/* 10-31-2022 Yajun Xia Modified comment(s), */ +/* added standalone support, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ VOID _ux_device_class_printer_soft_reset(UX_DEVICE_CLASS_PRINTER *printer) @@ -76,11 +79,17 @@ UX_SLAVE_ENDPOINT *endpoint; /* Stop OUT. */ endpoint = printer -> ux_device_class_printer_endpoint_out; _ux_device_stack_transfer_all_request_abort(endpoint, UX_ENDPOINT_RESET); +#if defined(UX_DEVICE_STANDALONE) + printer -> ux_device_class_printer_write_state = UX_STATE_RESET; +#endif /* Stop IN (optional). */ endpoint = printer -> ux_device_class_printer_endpoint_in; if (endpoint != UX_NULL) { _ux_device_stack_transfer_all_request_abort(endpoint, UX_ENDPOINT_RESET); +#if defined(UX_DEVICE_STANDALONE) + printer -> ux_device_class_printer_read_state = UX_STATE_RESET; +#endif } } diff --git a/common/usbx_device_classes/src/ux_device_class_printer_uninitialize.c b/common/usbx_device_classes/src/ux_device_class_printer_uninitialize.c index 1ff77aae..6a4e9560 100644 --- a/common/usbx_device_classes/src/ux_device_class_printer_uninitialize.c +++ b/common/usbx_device_classes/src/ux_device_class_printer_uninitialize.c @@ -34,7 +34,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_printer_uninitialize PORTABLE C */ -/* 6.1.12 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -72,6 +72,9 @@ /* fixed parameter/variable */ /* names conflict C++ keyword, */ /* resulting in version 6.1.12 */ +/* 10-31-2022 Yajun Xia Modified comment(s), */ +/* added standalone support, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_device_class_printer_uninitialize(UX_SLAVE_CLASS_COMMAND *command) @@ -89,13 +92,13 @@ UX_SLAVE_CLASS *class_ptr; /* Sanity check. */ if (printer != UX_NULL) { - +#if !defined(UX_DEVICE_STANDALONE) /* Delete the IN endpoint mutex. */ _ux_device_mutex_delete(&printer -> ux_device_class_printer_endpoint_in_mutex); /* Out Mutex. */ _ux_device_mutex_delete(&printer -> ux_device_class_printer_endpoint_out_mutex); - +#endif /* Free the resources. */ _ux_utility_memory_free(printer); } diff --git a/common/usbx_device_classes/src/ux_device_class_printer_write_run.c b/common/usbx_device_classes/src/ux_device_class_printer_write_run.c new file mode 100644 index 00000000..d078cd4e --- /dev/null +++ b/common/usbx_device_classes/src/ux_device_class_printer_write_run.c @@ -0,0 +1,258 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** USBX Component */ +/** */ +/** Device Printer Class */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define UX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "ux_api.h" +#include "ux_device_class_printer.h" +#include "ux_device_stack.h" + + +#if defined(UX_DEVICE_STANDALONE) + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _ux_device_class_printer_write_run PORTABLE C */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Yajun Xia, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function writes to the Printer class. */ +/* */ +/* It's for standalone mode. */ +/* */ +/* INPUT */ +/* */ +/* printer Address of printer class */ +/* instance */ +/* buffer Pointer to data to write */ +/* requested_length Length of bytes to write, */ +/* set to 0 to issue ZLP */ +/* actual_length Pointer to save number of */ +/* bytes written */ +/* */ +/* OUTPUT */ +/* */ +/* State machine Status to check */ +/* UX_STATE_NEXT Transfer done, to next state */ +/* UX_STATE_EXIT Abnormal, to reset state */ +/* (others) Keep running, waiting */ +/* */ +/* CALLS */ +/* */ +/* _ux_device_stack_transfer_run Run Transfer state machine */ +/* _ux_utility_memory_copy Copy memory */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Yajun Xia Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ +UINT _ux_device_class_printer_write_run(UX_DEVICE_CLASS_PRINTER *printer, UCHAR *buffer, + ULONG requested_length, ULONG *actual_length) +{ + +UX_SLAVE_ENDPOINT *endpoint; +UX_SLAVE_DEVICE *device; +UX_SLAVE_TRANSFER *transfer_request; +UINT zlp = UX_FALSE; +UINT status = 0; + + /* If trace is enabled, insert this event into the trace buffer. */ + UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_PRINTER_WRITE, printer, buffer, requested_length, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0) + + /* Get the pointer to the device. */ + device = &_ux_system_slave -> ux_system_slave_device; + + /* As long as the device is in the CONFIGURED state. */ + if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED) + { + + /* Error trap. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CONFIGURATION_HANDLE_UNKNOWN); + + /* If trace is enabled, insert this event into the trace buffer. */ + UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_CONFIGURATION_HANDLE_UNKNOWN, device, 0, 0, UX_TRACE_ERRORS, 0, 0) + + /* Cannot proceed with command, the interface is down. */ + printer -> ux_device_class_printer_write_state = UX_STATE_RESET; + printer -> ux_device_class_printer_write_status = UX_CONFIGURATION_HANDLE_UNKNOWN; + + return(UX_STATE_EXIT); + } + + /* Locate the endpoints. */ + endpoint = printer -> ux_device_class_printer_endpoint_in; + + /* Check if it's available. */ + if (endpoint == UX_NULL) + { + /* Error trap. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_ENDPOINT_HANDLE_UNKNOWN); + + printer -> ux_device_class_printer_write_state = UX_STATE_RESET; + printer -> ux_device_class_printer_write_status = UX_ENDPOINT_HANDLE_UNKNOWN; + + return(UX_STATE_EXIT); + } + + /* We are writing to the IN endpoint. */ + transfer_request = &endpoint -> ux_slave_endpoint_transfer_request; + + /* Handle state cases. */ + switch(printer -> ux_device_class_printer_write_state) + { + case UX_STATE_RESET: + printer -> ux_device_class_printer_write_state = UX_DEVICE_CLASS_PRINTER_WRITE_START; + printer -> ux_device_class_printer_write_status = UX_TRANSFER_NO_ANSWER; + printer -> ux_device_class_printer_write_buffer = buffer; + printer -> ux_device_class_printer_write_requested_length = requested_length; + printer -> ux_device_class_printer_write_actual_length = 0; + printer -> ux_device_class_printer_write_host_length = UX_SLAVE_REQUEST_DATA_MAX_LENGTH; + if (requested_length == 0) + zlp = UX_TRUE; + + /* Fall through. */ + case UX_DEVICE_CLASS_PRINTER_WRITE_START: + + /* Get remaining requested length. */ + requested_length = printer -> ux_device_class_printer_write_requested_length - + printer -> ux_device_class_printer_write_actual_length; + + /* There is no remaining, we are done. */ + if (requested_length == 0 && !zlp) + { + *actual_length = printer -> ux_device_class_printer_write_actual_length; + printer -> ux_device_class_printer_write_state = UX_STATE_RESET; + printer -> ux_device_class_printer_write_status = UX_SUCCESS; + return(UX_STATE_NEXT); + } + + /* Check if we have enough in the local buffer. */ + if (requested_length > UX_SLAVE_REQUEST_DATA_MAX_LENGTH) + + /* We have too much to transfer. */ + printer -> ux_device_class_printer_write_transfer_length = + UX_SLAVE_REQUEST_DATA_MAX_LENGTH; + + else + { + + /* We can proceed with the demanded length. */ + printer -> ux_device_class_printer_write_transfer_length = requested_length; + +#if !defined(UX_DEVICE_CLASS_PRINTER_WRITE_AUTO_ZLP) + + /* Assume expected length and transfer length match. */ + printer -> ux_device_class_printer_write_host_length = requested_length; +#else + + /* Assume expected more than transfer to let stack append ZLP if needed. */ + printer -> ux_device_class_printer_write_host_length = UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1; +#endif + } + + + /* On a out, we copy the buffer to the caller. Not very efficient but it makes the API + easier. */ + _ux_utility_memory_copy(transfer_request -> ux_slave_transfer_request_data_pointer, + printer -> ux_device_class_printer_write_buffer, + printer -> ux_device_class_printer_write_transfer_length); /* Use case of memcpy is verified. */ + + /* Next state. */ + printer -> ux_device_class_printer_write_state = UX_DEVICE_CLASS_PRINTER_WRITE_WAIT; + UX_SLAVE_TRANSFER_STATE_RESET(transfer_request); + + /* Fall through. */ + case UX_DEVICE_CLASS_PRINTER_WRITE_WAIT: + + /* Send the request to the device controller. */ + status = _ux_device_stack_transfer_run(transfer_request, + printer -> ux_device_class_printer_write_transfer_length, + printer -> ux_device_class_printer_write_host_length); + + /* Error case. */ + if (status < UX_STATE_NEXT) + { + + printer -> ux_device_class_printer_write_state = UX_STATE_RESET; + printer -> ux_device_class_printer_write_status = + transfer_request -> ux_slave_transfer_request_completion_code; + return(UX_STATE_ERROR); + } + + /* Success case. */ + if (status == UX_STATE_NEXT) + { + + /* Next buffer address. */ + printer -> ux_device_class_printer_write_buffer += + transfer_request -> ux_slave_transfer_request_actual_length; + + /* Set the length actually received. */ + printer -> ux_device_class_printer_write_actual_length += + transfer_request -> ux_slave_transfer_request_actual_length; + + /* Last transfer status. */ + printer -> ux_device_class_printer_write_status = + transfer_request -> ux_slave_transfer_request_completion_code; + + /* Update actual done length. */ + *actual_length = printer -> ux_device_class_printer_write_actual_length; + + /* Check ZLP case. */ + if (printer -> ux_device_class_printer_write_requested_length == 0) + { + printer -> ux_device_class_printer_write_state = UX_STATE_RESET; + return(UX_STATE_NEXT); + } + + /* Next state. */ + printer -> ux_device_class_printer_write_state = UX_DEVICE_CLASS_PRINTER_WRITE_START; + } + + /* Keep waiting. */ + return(UX_STATE_WAIT); + + default: /* Error. */ + printer -> ux_device_class_printer_write_state = UX_STATE_RESET; + break; + } + + /* Error case. */ + return(UX_STATE_EXIT); +} + +#endif diff --git a/common/usbx_device_classes/src/ux_device_class_rndis_bulkin_thread.c b/common/usbx_device_classes/src/ux_device_class_rndis_bulkin_thread.c index be900a96..92c11151 100644 --- a/common/usbx_device_classes/src/ux_device_class_rndis_bulkin_thread.c +++ b/common/usbx_device_classes/src/ux_device_class_rndis_bulkin_thread.c @@ -35,7 +35,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_rndis_bulkin_thread PORTABLE C */ -/* 6.1.11 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -85,6 +85,9 @@ /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */ /* fixed standalone compile, */ /* resulting in version 6.1.11 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* used NX API to copy data, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ VOID _ux_device_class_rndis_bulkin_thread(ULONG rndis_class) @@ -97,8 +100,8 @@ UX_SLAVE_TRANSFER *transfer_request; UINT status; ULONG actual_flags; NX_PACKET *current_packet; -UCHAR *packet_header; ULONG transfer_length; +ULONG copied; /* Cast properly the rndis instance. */ UX_THREAD_EXTENSION_PTR_GET(class_ptr, UX_SLAVE_CLASS, rndis_class) @@ -150,9 +153,6 @@ ULONG transfer_length; if (rndis -> ux_slave_class_rndis_link_state == UX_DEVICE_CLASS_RNDIS_LINK_STATE_UP) { - /* Load the address of the current packet header at the physical header. */ - packet_header = current_packet -> nx_packet_prepend_ptr; - /* Calculate the transfer length. */ transfer_length = current_packet -> nx_packet_length + UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH; @@ -161,21 +161,27 @@ ULONG transfer_length; { /* Copy the packet in the transfer descriptor buffer. */ - _ux_utility_memory_copy (transfer_request -> ux_slave_transfer_request_data_pointer + UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH, packet_header, current_packet -> nx_packet_length); /* Use case of memcpy is verified. */ - - /* Add the RNDIS header to this packet. */ - _ux_utility_long_put(transfer_request -> ux_slave_transfer_request_data_pointer + UX_DEVICE_CLASS_RNDIS_PACKET_MESSAGE_TYPE, UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_MSG); - _ux_utility_long_put(transfer_request -> ux_slave_transfer_request_data_pointer + UX_DEVICE_CLASS_RNDIS_PACKET_MESSAGE_LENGTH, transfer_length); - _ux_utility_long_put(transfer_request -> ux_slave_transfer_request_data_pointer + UX_DEVICE_CLASS_RNDIS_PACKET_DATA_OFFSET, - UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH - UX_DEVICE_CLASS_RNDIS_PACKET_DATA_OFFSET); - _ux_utility_long_put(transfer_request -> ux_slave_transfer_request_data_pointer + UX_DEVICE_CLASS_RNDIS_PACKET_DATA_LENGTH, current_packet -> nx_packet_length); - - /* If trace is enabled, insert this event into the trace buffer. */ - UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_RNDIS_PACKET_TRANSMIT, rndis, 0, 0, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0) - - /* Send the request to the device controller. */ - status = _ux_device_stack_transfer_request(transfer_request, transfer_length, UX_DEVICE_CLASS_RNDIS_ETHERNET_PACKET_SIZE); - + status = nx_packet_data_extract_offset(current_packet, 0, + transfer_request -> ux_slave_transfer_request_data_pointer + + UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH, + current_packet -> nx_packet_length, &copied); + if (status == NX_SUCCESS) + { + + /* Add the RNDIS header to this packet. */ + _ux_utility_long_put(transfer_request -> ux_slave_transfer_request_data_pointer + UX_DEVICE_CLASS_RNDIS_PACKET_MESSAGE_TYPE, UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_MSG); + _ux_utility_long_put(transfer_request -> ux_slave_transfer_request_data_pointer + UX_DEVICE_CLASS_RNDIS_PACKET_MESSAGE_LENGTH, transfer_length); + _ux_utility_long_put(transfer_request -> ux_slave_transfer_request_data_pointer + UX_DEVICE_CLASS_RNDIS_PACKET_DATA_OFFSET, + UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH - UX_DEVICE_CLASS_RNDIS_PACKET_DATA_OFFSET); + _ux_utility_long_put(transfer_request -> ux_slave_transfer_request_data_pointer + UX_DEVICE_CLASS_RNDIS_PACKET_DATA_LENGTH, current_packet -> nx_packet_length); + + /* If trace is enabled, insert this event into the trace buffer. */ + UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_RNDIS_PACKET_TRANSMIT, rndis, 0, 0, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0) + + /* Send the request to the device controller. */ + status = _ux_device_stack_transfer_request(transfer_request, transfer_length, UX_DEVICE_CLASS_RNDIS_ETHERNET_PACKET_SIZE + 1); + } + /* Check for error. */ if (status != UX_SUCCESS) diff --git a/common/usbx_device_classes/src/ux_device_class_rndis_bulkout_thread.c b/common/usbx_device_classes/src/ux_device_class_rndis_bulkout_thread.c index a569e5f5..1fcc35a1 100644 --- a/common/usbx_device_classes/src/ux_device_class_rndis_bulkout_thread.c +++ b/common/usbx_device_classes/src/ux_device_class_rndis_bulkout_thread.c @@ -35,7 +35,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_rndis_bulkout_thread PORTABLE C */ -/* 6.1.11 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -84,6 +84,10 @@ /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */ /* fixed standalone compile, */ /* resulting in version 6.1.11 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* used NX API to copy data, */ +/* used linked NX IP pool, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ VOID _ux_device_class_rndis_bulkout_thread(ULONG rndis_class) @@ -95,8 +99,8 @@ UX_SLAVE_DEVICE *device; UX_SLAVE_TRANSFER *transfer_request; UINT status; NX_PACKET *packet; -ULONG ip_given_length; ULONG packet_payload; +USB_NETWORK_DEVICE_TYPE *ux_nx_device; /* Cast properly the rndis instance. */ UX_THREAD_EXTENSION_PTR_GET(class_ptr, UX_SLAVE_CLASS, rndis_class) @@ -117,16 +121,39 @@ ULONG packet_payload; /* As long as the device is in the CONFIGURED state. */ while (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED) { - + + /* Check if packet pool is ready. */ + if (rndis -> ux_slave_class_rndis_packet_pool == UX_NULL) + { + + /* Get the network device handle. */ + ux_nx_device = (USB_NETWORK_DEVICE_TYPE *)(rndis -> ux_slave_class_rndis_network_handle); + + /* Get packet pool from IP instance (if available). */ + if (ux_nx_device -> ux_network_device_ip_instance != UX_NULL) + { + rndis -> ux_slave_class_rndis_packet_pool = ux_nx_device -> ux_network_device_ip_instance -> nx_ip_default_packet_pool; + } + else + { + + /* Error trap. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CLASS_ETH_PACKET_POOL_ERROR); + + _ux_utility_delay_ms(UX_DEVICE_CLASS_RNDIS_PACKET_POOL_INST_WAIT); + continue; + } + } + /* We can accept new reception. Get a NX Packet. */ - status = nx_packet_allocate(&rndis -> ux_slave_class_rndis_packet_pool, &packet, + status = nx_packet_allocate(rndis -> ux_slave_class_rndis_packet_pool, &packet, NX_RECEIVE_PACKET, UX_MS_TO_TICK(UX_DEVICE_CLASS_RNDIS_PACKET_POOL_WAIT)); if (status == NX_SUCCESS) { /* And length. */ - transfer_request -> ux_slave_transfer_request_requested_length = UX_DEVICE_CLASS_RNDIS_MAX_PACKET_LENGTH; + transfer_request -> ux_slave_transfer_request_requested_length = UX_DEVICE_CLASS_RNDIS_MAX_MSG_LENGTH; transfer_request -> ux_slave_transfer_request_actual_length = 0; /* Memorize this packet at the beginning of the queue. */ @@ -136,8 +163,8 @@ ULONG packet_payload; packet -> nx_packet_queue_next = UX_NULL; /* Send the request to the device controller. */ - status = _ux_device_stack_transfer_request(transfer_request, UX_DEVICE_CLASS_RNDIS_MAX_PACKET_LENGTH + UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH, - UX_DEVICE_CLASS_RNDIS_MAX_PACKET_LENGTH + UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH); + status = _ux_device_stack_transfer_request(transfer_request, UX_DEVICE_CLASS_RNDIS_MAX_MSG_LENGTH, + UX_DEVICE_CLASS_RNDIS_MAX_MSG_LENGTH); /* Check the completion code. */ if (status == UX_SUCCESS) @@ -147,63 +174,71 @@ ULONG packet_payload; /* If trace is enabled, insert this event into the trace buffer. */ UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_RNDIS_PACKET_RECEIVE, rndis, 0, 0, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0) - /* Check the state of the transfer. If there is an error, we do not proceed with this report. Also ensure the header has a valid ID of 1. */ - if (_ux_utility_long_get(transfer_request -> ux_slave_transfer_request_data_pointer + UX_DEVICE_CLASS_RNDIS_PACKET_MESSAGE_TYPE) == UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_MSG) + /* Check the state of the transfer. If there is an error, we do not proceed with this report. + Ensure this packet is at least larger than the header. + Also ensure the header has a valid ID of 1. */ + if (transfer_request -> ux_slave_transfer_request_actual_length > UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH && + _ux_utility_long_get(transfer_request -> ux_slave_transfer_request_data_pointer + UX_DEVICE_CLASS_RNDIS_PACKET_MESSAGE_TYPE) == UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_MSG) { - /* Ensure this packet is at least larger than the header. */ - if (transfer_request -> ux_slave_transfer_request_actual_length > UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH) - { - - /* Get the size of the payload. */ - packet_payload = _ux_utility_long_get(transfer_request -> ux_slave_transfer_request_data_pointer + UX_DEVICE_CLASS_RNDIS_PACKET_DATA_LENGTH); - - /* Ensure the length reported in the RNDIS header is not larger than it actually is. - The reason we can't check to see if the length reported in the header and the - actual length are exactly equal is because there might other data after the payload - (padding, or even a message). */ - if (packet_payload <= transfer_request -> ux_slave_transfer_request_actual_length - UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH) - { + /* Get the size of the payload. */ + packet_payload = _ux_utility_long_get(transfer_request -> ux_slave_transfer_request_data_pointer + UX_DEVICE_CLASS_RNDIS_PACKET_DATA_LENGTH); - /* Adjust the prepend pointer to take into account the non 3 bit alignment of the ethernet header. */ - packet -> nx_packet_prepend_ptr += sizeof(USHORT); - - /* Adjust the prepend, length, and append fields. */ - packet -> nx_packet_length = packet_payload; - packet -> nx_packet_append_ptr = packet -> nx_packet_prepend_ptr + packet_payload; - + /* Ensure the length reported in the RNDIS header is not larger than it actually is. + The reason we can't check to see if the length reported in the header and the + actual length are exactly equal is because there might other data after the payload + (padding, or even a message). */ + if (packet_payload <= transfer_request -> ux_slave_transfer_request_actual_length - UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH) + { - /* Copy the received packet in the IP packet data area. */ - _ux_utility_memory_copy(packet -> nx_packet_prepend_ptr, transfer_request -> ux_slave_transfer_request_data_pointer + UX_DEVICE_CLASS_RNDIS_PACKET_BUFFER, packet_payload); /* Use case of memcpy is verified. */ - - /* Calculate the accurate packet length from ip header */ - if((*(packet -> nx_packet_prepend_ptr + 12) == 0x08) && - (*(packet -> nx_packet_prepend_ptr + 13) == 0)) - { + /* Adjust the prepend pointer to take into account the non 3 bit alignment of the ethernet header. */ + packet -> nx_packet_prepend_ptr += sizeof(USHORT); + packet -> nx_packet_append_ptr += sizeof(USHORT); - ip_given_length = _ux_utility_short_get_big_endian(packet -> nx_packet_prepend_ptr + 16) + UX_DEVICE_CLASS_RNDIS_ETHERNET_SIZE; - packet -> nx_packet_length = ip_given_length ; - packet -> nx_packet_append_ptr = packet -> nx_packet_prepend_ptr + ip_given_length; - } + /* Copy the received packet in the IP packet data area. */ + status = nx_packet_data_append(packet, + transfer_request -> ux_slave_transfer_request_data_pointer + + UX_DEVICE_CLASS_RNDIS_PACKET_BUFFER, + packet_payload, + rndis -> ux_slave_class_rndis_packet_pool, + UX_MS_TO_TICK(UX_DEVICE_CLASS_RNDIS_PACKET_POOL_WAIT)); + if (status == UX_SUCCESS) + { /* Send that packet to the NetX USB broker. */ _ux_network_driver_packet_received(rndis -> ux_slave_class_rndis_network_handle, packet); } else + { - /* We received a malformed packet. Report to application. */ - _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CLASS_MALFORMED_PACKET_RECEIVED_ERROR); + /* Error. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CLASS_ETH_PACKET_ERROR); + nx_packet_release(packet); + } } else + { /* We received a malformed packet. Report to application. */ _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CLASS_MALFORMED_PACKET_RECEIVED_ERROR); + nx_packet_release(packet); + } + } + else + { + + /* We received a malformed packet. Report to application. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CLASS_MALFORMED_PACKET_RECEIVED_ERROR); + nx_packet_release(packet); } } else + { /* Free the packet that was not successfully received. */ nx_packet_release(packet); + } + } else { diff --git a/common/usbx_device_classes/src/ux_device_class_rndis_initialize.c b/common/usbx_device_classes/src/ux_device_class_rndis_initialize.c index 8af77324..18604e89 100644 --- a/common/usbx_device_classes/src/ux_device_class_rndis_initialize.c +++ b/common/usbx_device_classes/src/ux_device_class_rndis_initialize.c @@ -78,7 +78,7 @@ ULONG ux_device_class_rndis_oid_supported_list[UX_DEVICE_CLASS_RNDIS_OID_SUPPORT /* FUNCTION RELEASE */ /* */ /* _ux_device_class_rndis_initialize PORTABLE C */ -/* 6.1.12 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -136,6 +136,9 @@ ULONG ux_device_class_rndis_oid_supported_list[UX_DEVICE_CLASS_RNDIS_OID_SUPPORT /* fixed parameter/variable */ /* names conflict C++ keyword, */ /* resulting in version 6.1.12 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* removed internal NX pool, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_device_class_rndis_initialize(UX_SLAVE_CLASS_COMMAND *command) @@ -294,31 +297,6 @@ UINT status; status = UX_EVENT_ERROR; } - /* Allocate some packet pool for reception. */ - if (status == UX_SUCCESS) - { - - /* UX_DEVICE_CLASS_RNDIS_NX_ETHERNET_POOL_ALLOCSIZE overflow has been checked by - * UX_DEVICE_CLASS_RNDIS_NX_ETHERNET_POOL_ALLOCSIZE_ASSERT outside of function. - */ - rndis -> ux_slave_class_rndis_pool_memory = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY, UX_DEVICE_CLASS_RNDIS_NX_ETHERNET_POOL_ALLOCSIZE); - - /* Check the completion status. */ - if (rndis -> ux_slave_class_rndis_pool_memory == UX_NULL) - status = UX_MEMORY_INSUFFICIENT; - } - - /* Create a packet pool. */ - if (status == UX_SUCCESS) - { - status = nx_packet_pool_create(&rndis -> ux_slave_class_rndis_packet_pool, "Rndis Device Packet Pool", - UX_DEVICE_CLASS_RNDIS_NX_PAYLOAD_SIZE, rndis -> ux_slave_class_rndis_pool_memory, UX_DEVICE_CLASS_RNDIS_NX_ETHERNET_POOL_ALLOCSIZE); - - /* Check for pool creation error. */ - if (status != UX_SUCCESS) - status = UX_MEMORY_INSUFFICIENT; - } - /* Create a semaphore for protecting the driver entry. */ if (status == UX_SUCCESS) { @@ -338,14 +316,6 @@ UINT status; if (rndis -> ux_slave_class_rndis_semaphore.tx_semaphore_id != 0) _ux_device_semaphore_delete(&rndis -> ux_slave_class_rndis_semaphore); - /* Delete the packet pool. */ - if (rndis -> ux_slave_class_rndis_packet_pool.nx_packet_pool_id != 0) - nx_packet_pool_delete(&rndis -> ux_slave_class_rndis_packet_pool); - - /* Free rndis -> ux_slave_class_rndis_pool_memory. */ - if (rndis -> ux_slave_class_rndis_pool_memory) - _ux_utility_memory_free(rndis -> ux_slave_class_rndis_pool_memory); - /* Delete rndis -> ux_slave_class_rndis_event_flags_group. */ if (rndis -> ux_slave_class_rndis_event_flags_group.tx_event_flags_group_id != 0) _ux_utility_event_flags_delete(&rndis -> ux_slave_class_rndis_event_flags_group); diff --git a/common/usbx_device_classes/src/ux_device_class_storage_tasks_run.c b/common/usbx_device_classes/src/ux_device_class_storage_tasks_run.c index 2acafd4e..a3652f67 100644 --- a/common/usbx_device_classes/src/ux_device_class_storage_tasks_run.c +++ b/common/usbx_device_classes/src/ux_device_class_storage_tasks_run.c @@ -65,7 +65,7 @@ static inline VOID _ux_device_class_storage_disk_error(UX_SLAVE_CLASS_STORAGE *s /* FUNCTION RELEASE */ /* */ /* _ux_device_class_storage_tasks_run PORTABLE C */ -/* 6.1.10 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -125,6 +125,9 @@ static inline VOID _ux_device_class_storage_disk_error(UX_SLAVE_CLASS_STORAGE *s /* DATE NAME DESCRIPTION */ /* */ /* 01-31-2022 Chaoqiong Xiao Initial Version 6.1.10 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* improved internal logic, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_device_class_storage_tasks_run(VOID *instance) @@ -148,13 +151,14 @@ static inline UINT _ux_device_class_storage_task_usb(UX_SLAVE_CLASS_STORAGE *sto UX_SLAVE_DEVICE *device; UCHAR state; UINT status; +INT immediate_state = UX_TRUE; /* Get pointer to the device. */ device = &_ux_system_slave -> ux_system_slave_device; /* Run states once. */ - while(1) + while(immediate_state) { /* General check for MSC ready. */ @@ -301,9 +305,12 @@ UINT status; break; } - /* Unhandled, just do again by app call. */ - return(UX_STATE_EXIT); + /* Unhandled, just break the loop and do again by app call. */ + immediate_state = UX_FALSE; } + + /* Unhandled state. */ + return(UX_STATE_EXIT); } static inline VOID _ux_device_class_storage_cbw_receive(UX_SLAVE_CLASS_STORAGE *storage) @@ -979,9 +986,10 @@ static inline VOID _ux_device_class_storage_task_disk(UX_SLAVE_CLASS_STORAGE *st { UCHAR state = storage -> ux_device_class_storage_disk_state; UINT status; +INT immediate_state = UX_TRUE; /* Run states once. */ - while(1) + while(immediate_state) { /* Update state. */ @@ -1035,8 +1043,8 @@ UINT status; break; } - /* Task run once. */ - return; + /* Task run once, break the loop. */ + immediate_state = UX_FALSE; } } static inline VOID _ux_device_class_storage_disk_start(UX_SLAVE_CLASS_STORAGE *storage) @@ -1058,6 +1066,8 @@ ULONG max_n_blocks; /* Max blocks for one buffer. */ block_size = storage -> ux_slave_class_storage_lun[storage -> ux_slave_class_storage_cbw_lun]. ux_slave_class_storage_media_block_length; + if (block_size == 0) + UX_ASSERT(UX_FALSE); max_n_blocks = UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE / block_size; /* Prepare next disk read. */ diff --git a/common/usbx_device_classes/src/ux_device_class_video_activate.c b/common/usbx_device_classes/src/ux_device_class_video_activate.c index 80e71f62..7d780482 100644 --- a/common/usbx_device_classes/src/ux_device_class_video_activate.c +++ b/common/usbx_device_classes/src/ux_device_class_video_activate.c @@ -33,7 +33,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_video_activate PORTABLE C */ -/* 6.1.12 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -67,6 +67,9 @@ /* fixed parameter/variable */ /* names conflict C++ keyword, */ /* resulting in version 6.1.12 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* added standalone support, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_device_class_video_activate(UX_SLAVE_CLASS_COMMAND *command) @@ -154,6 +157,14 @@ ULONG stream_index; /* Store the class instance into the interface. */ stream_interface -> ux_slave_interface_class_instance = (VOID *)video; + +#if defined(UX_DEVICE_STANDALONE) + + /* Reset stream task state. */ + stream -> ux_device_class_video_stream_task_state = UX_STATE_RESET; + stream -> ux_device_class_video_stream_task_status = UX_SUCCESS; +#endif + } /* If there is a activate function call it. */ diff --git a/common/usbx_device_classes/src/ux_device_class_video_change.c b/common/usbx_device_classes/src/ux_device_class_video_change.c index 199fcc62..9bf5e016 100644 --- a/common/usbx_device_classes/src/ux_device_class_video_change.c +++ b/common/usbx_device_classes/src/ux_device_class_video_change.c @@ -33,7 +33,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_video_change PORTABLE C */ -/* 6.1.12 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -67,6 +67,9 @@ /* fixed parameter/variable */ /* names conflict C++ keyword, */ /* resulting in version 6.1.12 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* added standalone support, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_device_class_video_change(UX_SLAVE_CLASS_COMMAND *command) @@ -160,6 +163,15 @@ ULONG stream_index; return(UX_DESCRIPTOR_CORRUPTED); } +#if defined(UX_DEVICE_STANDALONE) + + /* Reset background transfer state. */ + stream -> ux_device_class_video_stream_task_state = UX_STATE_RESET; +#endif + + /* Now reset payload buffer error count. */ + stream -> ux_device_class_video_stream_buffer_error_count = 0; + /* Now reset payload buffers. */ payload_buffer = stream -> ux_device_class_video_stream_buffer; while(payload_buffer < stream -> ux_device_class_video_stream_buffer + stream -> ux_device_class_video_stream_buffer_size) diff --git a/common/usbx_device_classes/src/ux_device_class_video_initialize.c b/common/usbx_device_classes/src/ux_device_class_video_initialize.c index 8ffb9fe9..625bc4f0 100644 --- a/common/usbx_device_classes/src/ux_device_class_video_initialize.c +++ b/common/usbx_device_classes/src/ux_device_class_video_initialize.c @@ -33,7 +33,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_video_initialize PORTABLE C */ -/* 6.1.11 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -67,14 +67,13 @@ /* DATE NAME DESCRIPTION */ /* */ /* 04-25-2022 Chaoqiong Xiao Initial Version 6.1.11 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* added standalone support, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_device_class_video_initialize(UX_SLAVE_CLASS_COMMAND *command) { -#if defined(UX_DEVICE_STANDALONE) - UX_PARAMETER_NOT_USED(command); - return(UX_FUNCTION_NOT_SUPPORTED); -#else UINT status = UX_SUCCESS; UX_DEVICE_CLASS_VIDEO *video; @@ -163,6 +162,9 @@ ULONG i; stream -> ux_device_class_video_stream_transfer_pos = (UX_DEVICE_CLASS_VIDEO_PAYLOAD *)stream -> ux_device_class_video_stream_buffer; stream -> ux_device_class_video_stream_access_pos = stream -> ux_device_class_video_stream_transfer_pos; + +#if !defined(UX_DEVICE_STANDALONE) + /* Create memory block for streaming thread stack in addition. */ if (stream_parameter -> ux_device_class_video_stream_parameter_thread_stack_size == 0) memory_size = UX_DEVICE_CLASS_VIDEO_THREAD_STACK_SIZE; @@ -189,6 +191,11 @@ ULONG i; break; UX_THREAD_EXTENSION_PTR_SET(&(stream -> ux_device_class_video_stream_thread), stream) +#else + + /* Save task function for streaming. */ + stream -> ux_device_class_video_stream_task_function = stream_parameter -> ux_device_class_video_stream_parameter_task_function; +#endif /* Save callbacks. */ _ux_utility_memory_copy(&stream -> ux_device_class_video_stream_callbacks, @@ -217,6 +224,12 @@ ULONG i; &video_parameter -> ux_device_class_video_parameter_callbacks, sizeof(UX_DEVICE_CLASS_VIDEO_CALLBACKS)); /* Use case of memcpy is verified. */ +#if defined(UX_DEVICE_STANDALONE) + + /* Link task function. */ + class_inst -> ux_slave_class_task_function = _ux_device_class_video_tasks_run; +#endif + /* Return completion status. */ return(UX_SUCCESS); } @@ -228,10 +241,14 @@ ULONG i; stream = video -> ux_device_class_video_streams; for (i = 0; i < video -> ux_device_class_video_streams_nb; i ++) { + +#if !defined(UX_DEVICE_STANDALONE) if (stream -> ux_device_class_video_stream_thread.tx_thread_id) _ux_utility_thread_delete(&stream -> ux_device_class_video_stream_thread); if (stream -> ux_device_class_video_stream_thread_stack) _ux_utility_memory_free(stream -> ux_device_class_video_stream_thread_stack); +#endif + if (stream -> ux_device_class_video_stream_buffer) _ux_utility_memory_free(stream -> ux_device_class_video_stream_buffer); stream ++; @@ -239,5 +256,4 @@ ULONG i; _ux_utility_memory_free(video); return(status); -#endif } diff --git a/common/usbx_device_classes/src/ux_device_class_video_read_task_function.c b/common/usbx_device_classes/src/ux_device_class_video_read_task_function.c new file mode 100644 index 00000000..a7422cc8 --- /dev/null +++ b/common/usbx_device_classes/src/ux_device_class_video_read_task_function.c @@ -0,0 +1,188 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** USBX Component */ +/** */ +/** Device Video Class */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define UX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "ux_api.h" +#include "ux_device_class_video.h" +#include "ux_device_stack.h" + + +#if defined(UX_DEVICE_STANDALONE) +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _ux_device_class_video_read_task_function PORTABLE C */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Chaoqiong Xiao, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the background task of the video stream read. */ +/* */ +/* It's for standalone mode. */ +/* */ +/* INPUT */ +/* */ +/* stream Pointer to video stream */ +/* */ +/* OUTPUT */ +/* */ +/* State machine status */ +/* UX_STATE_EXIT Device not configured */ +/* UX_STATE_IDLE No streaming transfer running */ +/* UX_STATE_WAIT Streaming transfer running */ +/* */ +/* CALLS */ +/* */ +/* _ux_device_stack_transfer_run Run transfer state machine */ +/* _ux_utility_memory_copy Copy memory */ +/* */ +/* CALLED BY */ +/* */ +/* USBX Device Stack */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Chaoqiong Xiao Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ +UINT _ux_device_class_video_read_task_function(UX_DEVICE_CLASS_VIDEO_STREAM *stream) +{ +UX_SLAVE_DEVICE *device; +UX_SLAVE_ENDPOINT *endpoint; +UX_SLAVE_TRANSFER *transfer; +UCHAR *next_pos; +UX_DEVICE_CLASS_VIDEO_PAYLOAD *next_payload; +ULONG max_packet_size; +ULONG actual_length; +UINT status; + + + /* Get the pointer to the device. */ + device = stream -> ux_device_class_video_stream_video -> ux_device_class_video_device; + + /* Check if the device is configured. */ + if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED) + { + stream -> ux_device_class_video_stream_task_state = UX_STATE_EXIT; + return(UX_STATE_EXIT); + } + + /* Get the endpoint. */ + endpoint = stream -> ux_device_class_video_stream_endpoint; + + /* No endpoint ready, maybe it's alternate setting 0. */ + if (endpoint == UX_NULL) + return(UX_STATE_IDLE); + + /* Check if background transfer task is started. */ + if (stream -> ux_device_class_video_stream_task_state == UX_DEVICE_CLASS_VIDEO_STREAM_RW_STOP) + return(UX_STATE_IDLE); + + /* Get transfer instance. */ + transfer = &endpoint -> ux_slave_endpoint_transfer_request; + + /* If not started yet, reset transfer and start polling. */ + if (stream -> ux_device_class_video_stream_task_state == UX_DEVICE_CLASS_VIDEO_STREAM_RW_START) + { + + /* Next state: transfer wait. */ + stream -> ux_device_class_video_stream_task_state = UX_DEVICE_CLASS_VIDEO_STREAM_RW_WAIT; + + /* Reset transfer state. */ + UX_SLAVE_TRANSFER_STATE_RESET(transfer); + } + + /* Run transfer state machine. */ + max_packet_size = endpoint -> ux_slave_endpoint_transfer_request. + ux_slave_transfer_request_transfer_length; + status = _ux_device_stack_transfer_run(transfer, max_packet_size, max_packet_size); + + /* Error case. */ + if (status < UX_STATE_NEXT) + { + + /* Error on background transfer task start. */ + stream -> ux_device_class_video_stream_task_state = UX_STATE_RESET; + stream -> ux_device_class_video_stream_task_status = + transfer -> ux_slave_transfer_request_completion_code; + + /* Error notification! */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_ERROR); + return(UX_STATE_EXIT); + } + + /* Success case. */ + if (status == UX_STATE_NEXT) + { + + /* Next state: start. */ + stream -> ux_device_class_video_stream_task_state = UX_DEVICE_CLASS_VIDEO_STREAM_RW_START; + stream -> ux_device_class_video_stream_task_status = + transfer -> ux_slave_transfer_request_completion_code; + + /* Get actual transfer length. */ + actual_length = transfer -> ux_slave_transfer_request_actual_length; + + /* Frame received, log it. */ + stream -> ux_device_class_video_stream_transfer_pos -> ux_device_class_video_payload_length = actual_length; + _ux_utility_memory_copy(stream -> ux_device_class_video_stream_transfer_pos -> ux_device_class_video_payload_data, + transfer -> ux_slave_transfer_request_data_pointer, + actual_length); /* Use case of memcpy is verified. */ + + /* For simple, do not advance the transfer position if there is overflow. */ + next_pos = (UCHAR *)stream -> ux_device_class_video_stream_transfer_pos; + next_pos += stream -> ux_device_class_video_stream_payload_buffer_size; + if (next_pos >= stream -> ux_device_class_video_stream_buffer + stream -> ux_device_class_video_stream_buffer_size) + next_pos = stream -> ux_device_class_video_stream_buffer; + next_payload = (UX_DEVICE_CLASS_VIDEO_PAYLOAD *)next_pos; + + /* Check overflow! */ + if (next_payload -> ux_device_class_video_payload_length > 0) + { + + /* Error notification! */ + stream -> ux_device_class_video_stream_buffer_error_count ++; + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_BUFFER_OVERFLOW); + } + else + + /* Update transfer position. */ + stream -> ux_device_class_video_stream_transfer_pos = next_payload; + + /* Invoke notification callback. */ + if (stream -> ux_device_class_video_stream_callbacks.ux_device_class_video_stream_payload_done != UX_NULL) + stream -> ux_device_class_video_stream_callbacks.ux_device_class_video_stream_payload_done(stream, actual_length); + } + + /* Keep waiting. */ + return(UX_STATE_WAIT); +} +#endif diff --git a/common/usbx_device_classes/src/ux_device_class_video_read_thread_entry.c b/common/usbx_device_classes/src/ux_device_class_video_read_thread_entry.c index e9cd669c..060723d3 100644 --- a/common/usbx_device_classes/src/ux_device_class_video_read_thread_entry.c +++ b/common/usbx_device_classes/src/ux_device_class_video_read_thread_entry.c @@ -35,7 +35,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_video_read_thread_entry PORTABLE C */ -/* 6.1.11 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -69,6 +69,9 @@ /* DATE NAME DESCRIPTION */ /* */ /* 04-25-2022 Chaoqiong Xiao Initial Version 6.1.11 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* added error statistics, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ VOID _ux_device_class_video_read_thread_entry(ULONG video_stream) @@ -145,6 +148,7 @@ ULONG actual_length; { /* Error notification! */ + stream -> ux_device_class_video_stream_buffer_error_count ++; _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_BUFFER_OVERFLOW); } else diff --git a/common/usbx_device_classes/src/ux_device_class_video_reception_start.c b/common/usbx_device_classes/src/ux_device_class_video_reception_start.c index 84be153c..342b00e1 100644 --- a/common/usbx_device_classes/src/ux_device_class_video_reception_start.c +++ b/common/usbx_device_classes/src/ux_device_class_video_reception_start.c @@ -34,7 +34,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_video_reception_start PORTABLE C */ -/* 6.1.11 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -65,14 +65,13 @@ /* DATE NAME DESCRIPTION */ /* */ /* 04-25-2022 Chaoqiong Xiao Initial Version 6.1.11 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* added standalone support, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_device_class_video_reception_start(UX_DEVICE_CLASS_VIDEO_STREAM *stream) { -#if defined(UX_DEVICE_STANDALONE) - UX_PARAMETER_NOT_USED(stream); - return(UX_FUNCTION_NOT_SUPPORTED); -#else UX_SLAVE_ENDPOINT *endpoint; UX_SLAVE_DEVICE *device; @@ -102,8 +101,16 @@ UX_SLAVE_DEVICE *device; if (stream -> ux_device_class_video_stream_transfer_pos -> ux_device_class_video_payload_length > 0) return(UX_BUFFER_OVERFLOW); +#if defined(UX_DEVICE_STANDALONE) + + /* Start read task. */ + if (stream -> ux_device_class_video_stream_task_state == UX_DEVICE_CLASS_VIDEO_STREAM_RW_STOP) + stream -> ux_device_class_video_stream_task_state = UX_DEVICE_CLASS_VIDEO_STREAM_RW_START; + +#else /* Start read thread. */ _ux_utility_thread_resume(&stream -> ux_device_class_video_stream_thread); - return(UX_SUCCESS); #endif + + return(UX_SUCCESS); } diff --git a/common/usbx_device_classes/src/ux_device_class_video_tasks_run.c b/common/usbx_device_classes/src/ux_device_class_video_tasks_run.c new file mode 100644 index 00000000..24ca2ede --- /dev/null +++ b/common/usbx_device_classes/src/ux_device_class_video_tasks_run.c @@ -0,0 +1,113 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** USBX Component */ +/** */ +/** Device Video Class */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define UX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "ux_api.h" +#include "ux_device_class_video.h" +#include "ux_device_stack.h" + + +#if defined(UX_DEVICE_STANDALONE) +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _ux_device_class_video_tasks_run PORTABLE C */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Chaoqiong Xiao, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the background task of the video. */ +/* */ +/* It's for standalone mode. */ +/* */ +/* INPUT */ +/* */ +/* instance Pointer to video class */ +/* */ +/* OUTPUT */ +/* */ +/* State machine status */ +/* UX_STATE_EXIT Device not configured */ +/* UX_STATE_IDLE No streaming transfer running */ +/* UX_STATE_WAIT Streaming transfer running */ +/* */ +/* CALLS */ +/* */ +/* (ux_device_class_video_stream_task_function) */ +/* Run stream task */ +/* */ +/* CALLED BY */ +/* */ +/* USBX Device Stack */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Chaoqiong Xiao Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ +UINT _ux_device_class_video_tasks_run(VOID *instance) +{ +UX_SLAVE_DEVICE *device; +UX_DEVICE_CLASS_VIDEO *video; +UX_DEVICE_CLASS_VIDEO_STREAM *stream; +ULONG stream_index; +UINT status; +ULONG running_count; + + + /* Get Video instance. */ + video = (UX_DEVICE_CLASS_VIDEO *) instance; + + /* Get the pointer to the device. */ + device = &_ux_system_slave -> ux_system_slave_device; + + /* Check if the device is configured. */ + if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED) + return(UX_STATE_EXIT); + + /* Run video streaming tasks. */ + running_count = 0; + for (stream_index = 0; + stream_index < video -> ux_device_class_video_streams_nb; + stream_index ++) + { + stream = &video -> ux_device_class_video_streams[stream_index]; + status = stream -> ux_device_class_video_stream_task_function(stream); + if (status == UX_STATE_EXIT) + return(status); + if (status == UX_STATE_WAIT) + running_count ++; + } + + /* Return state running. */ + return (running_count > 0) ? (UX_STATE_WAIT) : (UX_STATE_IDLE); +} +#endif diff --git a/common/usbx_device_classes/src/ux_device_class_video_transmission_start.c b/common/usbx_device_classes/src/ux_device_class_video_transmission_start.c index 63a6c303..c01f1179 100644 --- a/common/usbx_device_classes/src/ux_device_class_video_transmission_start.c +++ b/common/usbx_device_classes/src/ux_device_class_video_transmission_start.c @@ -34,7 +34,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_video_transmission_start PORTABLE C */ -/* 6.1.11 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -65,14 +65,13 @@ /* DATE NAME DESCRIPTION */ /* */ /* 04-25-2022 Chaoqiong Xiao Initial Version 6.1.11 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* added standalone support, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_device_class_video_transmission_start(UX_DEVICE_CLASS_VIDEO_STREAM *stream) { -#if defined(UX_DEVICE_STANDALONE) - UX_PARAMETER_NOT_USED(stream); - return(UX_FUNCTION_NOT_SUPPORTED); -#else UX_SLAVE_ENDPOINT *endpoint; UX_SLAVE_DEVICE *device; @@ -102,8 +101,17 @@ UX_SLAVE_DEVICE *device; if (stream -> ux_device_class_video_stream_transfer_pos -> ux_device_class_video_payload_length == 0) return(UX_BUFFER_OVERFLOW); +#if defined(UX_DEVICE_STANDALONE) + + /* Start write task. */ + if (stream -> ux_device_class_video_stream_task_state == UX_DEVICE_CLASS_VIDEO_STREAM_RW_STOP) + stream -> ux_device_class_video_stream_task_state = UX_DEVICE_CLASS_VIDEO_STREAM_RW_START; + +#else + /* Start write thread. */ - _ux_utility_thread_resume(&stream -> ux_device_class_video_stream_thread); - return(UX_SUCCESS); + _ux_device_thread_resume(&stream -> ux_device_class_video_stream_thread); #endif + + return(UX_SUCCESS); } diff --git a/common/usbx_device_classes/src/ux_device_class_video_write_task_function.c b/common/usbx_device_classes/src/ux_device_class_video_write_task_function.c new file mode 100644 index 00000000..55dba42a --- /dev/null +++ b/common/usbx_device_classes/src/ux_device_class_video_write_task_function.c @@ -0,0 +1,209 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** USBX Component */ +/** */ +/** Device Video Class */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define UX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "ux_api.h" +#include "ux_device_class_video.h" +#include "ux_device_stack.h" + + +#if defined(UX_DEVICE_STANDALONE) +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _ux_device_class_video_write_task_function PORTABLE C */ +/* 6.2.0 */ +/* AUTHOR */ +/* */ +/* Chaoqiong Xiao, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the background task of the video stream write. */ +/* */ +/* It's for standalone mode. */ +/* */ +/* INPUT */ +/* */ +/* video_class Address of video class */ +/* container */ +/* */ +/* OUTPUT */ +/* */ +/* State machine status */ +/* UX_STATE_EXIT Device not configured */ +/* UX_STATE_IDLE No streaming transfer running */ +/* UX_STATE_WAIT Streaming transfer running */ +/* */ +/* CALLS */ +/* */ +/* _ux_device_stack_transfer_run Run transfer state machine */ +/* _ux_utility_memory_copy Copy memory */ +/* */ +/* CALLED BY */ +/* */ +/* USBX Device Stack */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 10-31-2022 Chaoqiong Xiao Initial Version 6.2.0 */ +/* */ +/**************************************************************************/ +UINT _ux_device_class_video_write_task_function(UX_DEVICE_CLASS_VIDEO_STREAM *stream) +{ +UX_SLAVE_DEVICE *device; +UX_SLAVE_ENDPOINT *endpoint; +UX_SLAVE_TRANSFER *transfer; +UCHAR *next_pos; +UX_DEVICE_CLASS_VIDEO_PAYLOAD *next_payload; +ULONG transfer_length; +ULONG actual_length; +UINT status; + + + /* Get the pointer to the device. */ + device = stream -> ux_device_class_video_stream_video -> ux_device_class_video_device; + + /* Check if the device is configured. */ + if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED) + { + stream -> ux_device_class_video_stream_task_state = UX_STATE_EXIT; + return(UX_STATE_EXIT); + } + + /* Get the endpoint. */ + endpoint = stream -> ux_device_class_video_stream_endpoint; + + /* No endpoint ready, maybe it's alternate setting 0. */ + if (endpoint == UX_NULL) + return(UX_STATE_IDLE); + + /* Check if background transfer task is started. */ + if (stream -> ux_device_class_video_stream_task_state == UX_DEVICE_CLASS_VIDEO_STREAM_RW_STOP) + return(UX_STATE_IDLE); + + /* Get transfer instance. */ + transfer = &endpoint -> ux_slave_endpoint_transfer_request; + + /* If not started yet, prepare data, reset transfer and start polling. */ + if (stream -> ux_device_class_video_stream_task_state == UX_DEVICE_CLASS_VIDEO_STREAM_RW_START) + { + + /* Next state: transfer wait. */ + stream -> ux_device_class_video_stream_task_state = UX_DEVICE_CLASS_VIDEO_STREAM_RW_WAIT; + + /* Start payload transfer anyway (even ZLP). */ + transfer_length = stream -> ux_device_class_video_stream_transfer_pos -> ux_device_class_video_payload_length; + if (transfer_length) + _ux_utility_memory_copy(transfer -> ux_slave_transfer_request_data_pointer, + stream -> ux_device_class_video_stream_transfer_pos -> ux_device_class_video_payload_data, transfer_length); /* Use case of memcpy is verified. */ + + /* Reset transfer state. */ + UX_SLAVE_TRANSFER_STATE_RESET(transfer); + } + + /* Get current transfer length. */ + transfer_length = stream -> ux_device_class_video_stream_transfer_pos -> ux_device_class_video_payload_length; + + /* Run transfer states. */ + status = _ux_device_stack_transfer_run(transfer, transfer_length, transfer_length); + + /* Error case. */ + if (status < UX_STATE_NEXT) + { + + /* Error on background transfer task start. */ + stream -> ux_device_class_video_stream_task_state = UX_STATE_RESET; + stream -> ux_device_class_video_stream_task_status = + transfer -> ux_slave_transfer_request_completion_code; + + /* Error notification! */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_ERROR); + return(UX_STATE_EXIT); + } + + /* Success case. */ + if (status == UX_STATE_NEXT) + { + + /* Next state: start. */ + stream -> ux_device_class_video_stream_task_state = UX_DEVICE_CLASS_VIDEO_STREAM_RW_START; + stream -> ux_device_class_video_stream_task_status = + transfer -> ux_slave_transfer_request_completion_code; + + /* Frame sent, free it. */ + stream -> ux_device_class_video_stream_transfer_pos -> ux_device_class_video_payload_length = 0; + + /* Get actual transfer length. */ + actual_length = transfer -> ux_slave_transfer_request_actual_length; + + /* Calculate next position. */ + next_pos = (UCHAR *)stream -> ux_device_class_video_stream_transfer_pos; + next_pos += stream -> ux_device_class_video_stream_payload_buffer_size; + if (next_pos >= stream -> ux_device_class_video_stream_buffer + stream -> ux_device_class_video_stream_buffer_size) + next_pos = stream -> ux_device_class_video_stream_buffer; + next_payload = (UX_DEVICE_CLASS_VIDEO_PAYLOAD *)next_pos; + + /* Underflow check! */ + if (transfer_length) + { + + /* Advance position. */ + stream -> ux_device_class_video_stream_transfer_pos = next_payload; + + /* Error trap! */ + if (next_payload -> ux_device_class_video_payload_length == 0) + { + stream -> ux_device_class_video_stream_buffer_error_count ++; + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_BUFFER_OVERFLOW); + } + } + else + { + + /* Advance position if next payload available. */ + if (next_payload -> ux_device_class_video_payload_length) + stream -> ux_device_class_video_stream_transfer_pos = next_payload; + else + { + + /* Error trap! */ + stream -> ux_device_class_video_stream_buffer_error_count ++; + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_BUFFER_OVERFLOW); + } + } + + /* Invoke notification callback. */ + if (stream -> ux_device_class_video_stream_callbacks.ux_device_class_video_stream_payload_done != UX_NULL) + stream -> ux_device_class_video_stream_callbacks.ux_device_class_video_stream_payload_done(stream, actual_length); + } + + /* Keep waiting. */ + return(UX_STATE_WAIT); +} +#endif diff --git a/common/usbx_device_classes/src/ux_device_class_video_write_thread_entry.c b/common/usbx_device_classes/src/ux_device_class_video_write_thread_entry.c index 43006d6d..3dce6367 100644 --- a/common/usbx_device_classes/src/ux_device_class_video_write_thread_entry.c +++ b/common/usbx_device_classes/src/ux_device_class_video_write_thread_entry.c @@ -35,7 +35,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_video_write_thread_entry PORTABLE C */ -/* 6.1.11 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -69,6 +69,9 @@ /* DATE NAME DESCRIPTION */ /* */ /* 04-25-2022 Chaoqiong Xiao Initial Version 6.1.11 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* added error statistics, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ VOID _ux_device_class_video_write_thread_entry(ULONG video_stream) @@ -147,7 +150,10 @@ ULONG actual_length; /* Error trap! */ if (next_payload -> ux_device_class_video_payload_length == 0) + { + stream -> ux_device_class_video_stream_buffer_error_count ++; _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_BUFFER_OVERFLOW); + } } else { @@ -156,9 +162,12 @@ ULONG actual_length; if (next_payload -> ux_device_class_video_payload_length) stream -> ux_device_class_video_stream_transfer_pos = next_payload; else + { /* Error trap! */ + stream -> ux_device_class_video_stream_buffer_error_count ++; _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_BUFFER_OVERFLOW); + } } /* Invoke notification callback. */ diff --git a/common/usbx_host_classes/inc/ux_host_class_asix.h b/common/usbx_host_classes/inc/ux_host_class_asix.h index dac0f481..250fd209 100644 --- a/common/usbx_host_classes/inc/ux_host_class_asix.h +++ b/common/usbx_host_classes/inc/ux_host_class_asix.h @@ -26,7 +26,7 @@ /* COMPONENT DEFINITION RELEASE */ /* */ /* ux_host_class_asix.h PORTABLE C */ -/* 6.1.11 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -53,6 +53,13 @@ /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */ /* fixed standalone compile, */ /* resulting in version 6.1.11 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* supported NX packet chain, */ +/* refined VID/PID check flow, */ +/* removed internal NX pool, */ +/* added some new definitions, */ +/* refined reception handling, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ @@ -93,6 +100,17 @@ extern "C" { #define UX_HOST_CLASS_ASIX_VENDOR_FUJIEI_ID 0X0B95 #define UX_HOST_CLASS_ASIX_PRODUCT_FUJIEI_ID 0X772B +#define UX_HOST_CLASS_ASIX_VENDOR_LINKSYS_ID 0X13B1 +#define UX_HOST_CLASS_ASIX_PRODUCT_LINKSYS_ID 0X0018 + +/* Define ASIX supported VID and PID array (of 16-bits). */ +#ifndef UX_HOST_CLASS_ASIX_VID_PID_ARRAY +#define UX_HOST_CLASS_ASIX_VID_PID_ARRAY \ + UX_HOST_CLASS_ASIX_VENDOR_ID, UX_HOST_CLASS_ASIX_PRODUCT_ID, \ + UX_HOST_CLASS_ASIX_VENDOR_FUJIEI_ID, UX_HOST_CLASS_ASIX_PRODUCT_FUJIEI_ID, \ + UX_HOST_CLASS_ASIX_VENDOR_LINKSYS_ID, UX_HOST_CLASS_ASIX_PRODUCT_LINKSYS_ID +#endif + #define UX_HOST_CLASS_ASIX_SPEED_SELECTED_100MPBS 0x100 #define UX_HOST_CLASS_ASIX_SPEED_SELECTED_10MPBS 0x10 #define UX_HOST_CLASS_ASIX_LINK_STATE_DOWN 0 @@ -107,14 +125,29 @@ extern "C" { #define UX_HOST_CLASS_ASIX_ETHERNET_RARP 0x8035 #define UX_HOST_CLASS_ASIX_ETHERNET_PACKET_SIZE 1536 #define UX_HOST_CLASS_ASIX_NX_ALIGN_PADDING 2 -#ifndef UX_HOST_CLASS_ASIX_NX_PKPOOL_ENTRIES -#define UX_HOST_CLASS_ASIX_NX_PKPOOL_ENTRIES 16 +#define UX_HOST_CLASS_ASIX_RX_HEADER_SIZE 4 +#define UX_HOST_CLASS_ASIX_OVERHEAD_SIZE (UX_HOST_CLASS_ASIX_NX_ALIGN_PADDING + UX_HOST_CLASS_ASIX_RX_HEADER_SIZE) + +#define UX_HOST_CLASS_ASIX_TRANSMIT_BUFFER_SIZE UX_HOST_CLASS_ASIX_NX_PAYLOAD_SIZE + +#ifndef UX_HOST_CLASS_ASIX_RECEIVE_BUFFER_SIZE +#define UX_HOST_CLASS_ASIX_RECEIVE_BUFFER_SIZE 512 /* N*512. */ +#endif + +#ifdef NX_DISABLE_PACKET_CHAIN +#undef UX_HOST_CLASS_ASIX_PACKET_CHAIN_SUPPORT +#else +#define UX_HOST_CLASS_ASIX_PACKET_CHAIN_SUPPORT #endif #define UX_HOST_CLASS_ASIX_NX_PACKET_SIZE sizeof(NX_PACKET) -#define UX_HOST_CLASS_ASIX_NX_PAYLOAD_SIZE_ASSERT UX_COMPILE_TIME_ASSERT(!UX_OVERFLOW_CHECK_ADD_ULONG(UX_HOST_CLASS_ASIX_ETHERNET_PACKET_SIZE, UX_HOST_CLASS_ASIX_NX_ALIGN_PADDING), UX_HOST_CLASS_ASIX_NX_PAYLOAD_SIZE_calc_ovf) -#define UX_HOST_CLASS_ASIX_NX_PAYLOAD_SIZE (UX_HOST_CLASS_ASIX_ETHERNET_PACKET_SIZE + UX_HOST_CLASS_ASIX_NX_ALIGN_PADDING) +#define UX_HOST_CLASS_ASIX_NX_PAYLOAD_SIZE_ASSERT \ + UX_COMPILE_TIME_ASSERT(!UX_OVERFLOW_CHECK_ADD_ULONG( \ + UX_HOST_CLASS_ASIX_ETHERNET_PACKET_SIZE, \ + UX_HOST_CLASS_ASIX_OVERHEAD_SIZE), \ + UX_HOST_CLASS_ASIX_NX_PAYLOAD_SIZE_calc_ovf) +#define UX_HOST_CLASS_ASIX_NX_PAYLOAD_SIZE (UX_HOST_CLASS_ASIX_ETHERNET_PACKET_SIZE + UX_HOST_CLASS_ASIX_OVERHEAD_SIZE) #define UX_HOST_CLASS_ASIX_NX_BUFF_SIZE_ASSERT \ UX_HOST_CLASS_ASIX_NX_PAYLOAD_SIZE_ASSERT \ @@ -124,24 +157,15 @@ extern "C" { UX_HOST_CLASS_ASIX_NX_BUFF_SIZE_calc_ovf) #define UX_HOST_CLASS_ASIX_NX_BUFF_SIZE (UX_HOST_CLASS_ASIX_NX_PAYLOAD_SIZE + UX_HOST_CLASS_ASIX_NX_PACKET_SIZE) -#define UX_HOST_CLASS_ASIX_NX_ETHERNET_POOL_ALLOCSIZE_ASSERT \ - UX_HOST_CLASS_ASIX_NX_BUFF_SIZE_ASSERT \ - UX_COMPILE_TIME_ASSERT(!UX_OVERFLOW_CHECK_MULC_ULONG( \ - UX_HOST_CLASS_ASIX_NX_PKPOOL_ENTRIES, \ - UX_HOST_CLASS_ASIX_NX_BUFF_SIZE), \ - UX_HOST_CLASS_ASIX_NX_ETHERNET_POOL_ALLOCSIZE_calc1_ovf) \ - UX_COMPILE_TIME_ASSERT(!UX_OVERFLOW_CHECK_ADD_ULONG( \ - UX_HOST_CLASS_ASIX_NX_PKPOOL_ENTRIES * \ - UX_HOST_CLASS_ASIX_NX_BUFF_SIZE, \ - 32), UX_HOST_CLASS_ASIX_NX_ETHERNET_POOL_ALLOCSIZE_calc2_ovf) -#define UX_HOST_CLASS_ASIX_NX_ETHERNET_POOL_ALLOCSIZE (UX_HOST_CLASS_ASIX_NX_PKPOOL_ENTRIES * UX_HOST_CLASS_ASIX_NX_BUFF_SIZE + 32) - #define UX_HOST_CLASS_ASIX_ETHERNET_SIZE 14 #define UX_HOST_CLASS_ASIX_DEVICE_INIT_DELAY (1 * UX_PERIODIC_RATE) #define UX_HOST_CLASS_ASIX_CLASS_TRANSFER_TIMEOUT 300000 #define UX_HOST_CLASS_ASIX_SETUP_BUFFER_SIZE 16 +#define UX_HOST_CLASS_ASIX_PACKET_POOL_WAIT 100 +#define UX_HOST_CLASS_ASIX_PACKET_ALLOCATE_WAIT 2000 + /* Define NetX errors inside the Asix class. */ #define UX_HOST_CLASS_ASIX_NX_SUCCESS 0x00 #define UX_HOST_CLASS_ASIX_NX_NO_PACKET 0x01 @@ -206,6 +230,7 @@ extern "C" { #define UX_HOST_CLASS_ASIX_REQ_OWN_SMI 0x06 #define UX_HOST_CLASS_ASIX_REQ_READ_PHY_REG 0x07 #define UX_HOST_CLASS_ASIX_REQ_WRITE_PHY_REG 0x08 +#define UX_HOST_CLASS_ASIX_REQ_READ_STATION_STATUS 0x09 #define UX_HOST_CLASS_ASIX_REQ_WHO_OWNS_SMI 0x09 #define UX_HOST_CLASS_ASIX_REQ_RELEASE_SMI 0x0a #define UX_HOST_CLASS_ASIX_REQ_READ_SROM 0x0b @@ -280,16 +305,25 @@ extern "C" { #define UX_HOST_CLASS_ASIX_RXCR_AP 0x0020 #define UX_HOST_CLASS_ASIX_RXCR_SO 0x0080 +/* 88772. */ #define UX_HOST_CLASS_ASIX_RXCR_MFB_2048 0x0000 #define UX_HOST_CLASS_ASIX_RXCR_MFB_4096 0x0100 #define UX_HOST_CLASS_ASIX_RXCR_MFB_8192 0x0200 -#define UX_HOST_CLASS_ASIX_RXCR_MFB_16384 0x0300 +#define UX_HOST_CLASS_ASIX_RXCR_MFB_16384 0x0300 /* Default. */ + +/* 88772B. */ +#define UX_HOST_CLASS_ASIX_RXCR_RH1M 0x0100 /* Default 1. */ +#define UX_HOST_CLASS_ASIX_RXCR_RH2M 0x0200 /* Default 0. */ +#define UX_HOST_CLASS_ASIX_RXCR_RH3M 0x0400 /* Default 0. */ + /* Define ASIX Class packet equivalences. */ #define UX_HOST_CLASS_ASIX_PACKET_SIZE 128 #define UX_HOST_CLASS_ASIX_NODE_ID_LENGTH 6 +#define UX_HOST_CLASS_ASIX_RX_PACKET_LENGTH_MASK 0xFFF + /* Define ASIX PHY registers description. */ #define UX_HOST_CLASS_ASIX_PHY_REG_BMCR 0x00 @@ -391,10 +425,14 @@ typedef struct UX_HOST_CLASS_ASIX_STRUCT ULONG ux_host_class_asix_link_state; NX_PACKET *ux_host_class_asix_xmit_queue; +#ifdef UX_HOST_CLASS_ASIX_PACKET_CHAIN_SUPPORT + UCHAR *ux_host_class_asix_xmit_buffer; +#endif NX_PACKET *ux_host_class_asix_receive_queue; - NX_PACKET_POOL ux_host_class_asix_packet_pool; + UCHAR *ux_host_class_asix_receive_buffer; + NX_PACKET_POOL *ux_host_class_asix_packet_pool; + ULONG ux_host_class_asix_packet_available_min; - UCHAR *ux_host_class_asix_pool_memory; UCHAR ux_host_class_asix_node_id[UX_HOST_CLASS_ASIX_NODE_ID_LENGTH]; VOID (*ux_host_class_asix_device_status_change_callback)(struct UX_HOST_CLASS_ASIX_STRUCT *asix, ULONG device_state); diff --git a/common/usbx_host_classes/inc/ux_host_class_cdc_ecm.h b/common/usbx_host_classes/inc/ux_host_class_cdc_ecm.h index 524656f9..9a8b3884 100644 --- a/common/usbx_host_classes/inc/ux_host_class_cdc_ecm.h +++ b/common/usbx_host_classes/inc/ux_host_class_cdc_ecm.h @@ -26,7 +26,7 @@ /* COMPONENT DEFINITION RELEASE */ /* */ /* ux_host_class_cdc_ecm.h PORTABLE C */ -/* 6.1.11 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -57,6 +57,9 @@ /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */ /* fixed standalone compile, */ /* resulting in version 6.1.11 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* supported NX packet chain, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ @@ -144,12 +147,19 @@ extern "C" { 32), UX_HOST_CLASS_CDC_ECM_NX_ETHERNET_POOL_ALLOCSIZE_calc2_ovf) #define UX_HOST_CLASS_CDC_ECM_NX_ETHERNET_POOL_ALLOCSIZE (UX_HOST_CLASS_CDC_ECM_NX_PKPOOL_ENTRIES * UX_HOST_CLASS_CDC_ECM_NX_BUFF_SIZE + 32) +#ifdef NX_DISABLE_PACKET_CHAIN +#undef UX_HOST_CLASS_CDC_ECM_PACKET_CHAIN_SUPPORT +#else +#define UX_HOST_CLASS_CDC_ECM_PACKET_CHAIN_SUPPORT +#endif + #define UX_HOST_CLASS_CDC_ECM_ETHERNET_SIZE 14 #define UX_HOST_CLASS_CDC_ECM_DEVICE_INIT_DELAY (1 * UX_PERIODIC_RATE) #define UX_HOST_CLASS_CDC_ECM_CLASS_TRANSFER_TIMEOUT 300000 #define UX_HOST_CLASS_CDC_ECM_SETUP_BUFFER_SIZE 16 + /* Define NetX errors inside the CDC ECM class. */ #define UX_HOST_CLASS_CDC_ECM_NX_SUCCESS 0x00 #define UX_HOST_CLASS_CDC_ECM_NX_NO_PACKET 0x01 @@ -280,11 +290,10 @@ typedef struct UX_HOST_CLASS_CDC_ECM_STRUCT ULONG ux_host_class_cdc_ecm_link_state; NX_PACKET *ux_host_class_cdc_ecm_xmit_queue_head; NX_PACKET *ux_host_class_cdc_ecm_xmit_queue_tail; -#ifndef UX_HOST_CLASS_CDC_ECM_USE_PACKET_POOL_FROM_NETX - NX_PACKET_POOL ux_host_class_cdc_ecm_packet_pool; - UCHAR *ux_host_class_cdc_ecm_pool_memory; -#else NX_PACKET_POOL *ux_host_class_cdc_ecm_packet_pool; +#ifdef UX_HOST_CLASS_CDC_ECM_PACKET_CHAIN_SUPPORT + UCHAR *ux_host_class_cdc_ecm_xmit_buffer; + UCHAR *ux_host_class_cdc_ecm_receive_buffer; #endif UCHAR ux_host_class_cdc_ecm_node_id[UX_HOST_CLASS_CDC_ECM_NODE_ID_LENGTH]; diff --git a/common/usbx_host_classes/inc/ux_host_class_hid_keyboard.h b/common/usbx_host_classes/inc/ux_host_class_hid_keyboard.h index b8051751..b331bf4d 100644 --- a/common/usbx_host_classes/inc/ux_host_class_hid_keyboard.h +++ b/common/usbx_host_classes/inc/ux_host_class_hid_keyboard.h @@ -26,7 +26,7 @@ /* COMPONENT DEFINITION RELEASE */ /* */ /* ux_host_class_hid_keyboard.h PORTABLE C */ -/* 6.1.11 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -56,6 +56,10 @@ /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */ /* fixed clients management, */ /* resulting in version 6.1.11 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* improved HID OUTPUT report */ +/* handling in standalone mode,*/ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ @@ -215,6 +219,8 @@ typedef struct UX_HOST_CLASS_HID_KEYBOARD_STRUCT UX_THREAD ux_host_class_hid_keyboard_thread; UX_SEMAPHORE ux_host_class_hid_keyboard_semaphore; #else + UX_HOST_CLASS_HID_REPORT + *ux_host_class_hid_keyboard_out_report; UINT ux_host_class_hid_keyboard_status; UCHAR ux_host_class_hid_keyboard_enum_state; UCHAR ux_host_class_hid_keyboard_next_state; diff --git a/common/usbx_host_classes/inc/ux_host_class_storage.h b/common/usbx_host_classes/inc/ux_host_class_storage.h old mode 100755 new mode 100644 diff --git a/common/usbx_host_classes/src/ux_host_class_asix_activate.c b/common/usbx_host_classes/src/ux_host_class_asix_activate.c index a243a072..760b59ed 100644 --- a/common/usbx_host_classes/src/ux_host_class_asix_activate.c +++ b/common/usbx_host_classes/src/ux_host_class_asix_activate.c @@ -29,14 +29,13 @@ #include "ux_host_class_asix.h" #include "ux_host_stack.h" -UX_HOST_CLASS_ASIX_NX_ETHERNET_POOL_ALLOCSIZE_ASSERT /**************************************************************************/ /* */ /* FUNCTION RELEASE */ /* */ /* _ux_host_class_asix_activate PORTABLE C */ -/* 6.1.10 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -87,6 +86,11 @@ UX_HOST_CLASS_ASIX_NX_ETHERNET_POOL_ALLOCSIZE_ASSERT /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */ /* refined macros names, */ /* resulting in version 6.1.10 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* moved NX driver activate, */ +/* added reception buffer, */ +/* removed internal NX pool, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_host_class_asix_activate(UX_HOST_CLASS_COMMAND *command) @@ -103,7 +107,10 @@ UX_DEVICE *device; UX_HOST_CLASS_ASIX *asix; UINT status; UX_TRANSFER *transfer_request; - +ULONG physical_address_msw; +ULONG physical_address_lsw; + + /* We need to make sure that the value of the NX_PHYSICAL_HEADER is at least 20. This should be changed in the nx_user.h file */ @@ -199,27 +206,28 @@ UX_TRANSFER *transfer_request; status = _ux_host_stack_transfer_request(transfer_request); } - /* Allocate some packet pool for reception. */ + /* Allocate some memory for reception. */ if (status == UX_SUCCESS) { - - /* UX_HOST_CLASS_ASIX_NX_ETHERNET_POOL_ALLOCSIZE overflow has been checked by - * UX_HOST_CLASS_ASIX_NX_ETHERNET_POOL_ALLOCSIZE_ASSERT outside of function. - */ - asix -> ux_host_class_asix_pool_memory = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_ASIX_NX_ETHERNET_POOL_ALLOCSIZE); - if (asix -> ux_host_class_asix_pool_memory == UX_NULL) + asix -> ux_host_class_asix_receive_buffer = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_ASIX_RECEIVE_BUFFER_SIZE); + if (asix -> ux_host_class_asix_receive_buffer == UX_NULL) status = UX_MEMORY_INSUFFICIENT; } - /* Create a packet pool. */ + /* Activate network driver. */ if (status == UX_SUCCESS) { - status = nx_packet_pool_create(&asix -> ux_host_class_asix_packet_pool, "Asix Packet Pool", - UX_HOST_CLASS_ASIX_NX_PAYLOAD_SIZE, asix -> ux_host_class_asix_pool_memory, UX_HOST_CLASS_ASIX_NX_ETHERNET_POOL_ALLOCSIZE); - /* Check for pool creation error. */ - if (status) - status = UX_ERROR; + /* Setup the physical address of this IP instance. */ + physical_address_msw = (ULONG)((asix -> ux_host_class_asix_node_id[0] << 8) | (asix -> ux_host_class_asix_node_id[1])); + physical_address_lsw = (ULONG)((asix -> ux_host_class_asix_node_id[2] << 24) | (asix -> ux_host_class_asix_node_id[3] << 16) | + (asix -> ux_host_class_asix_node_id[4] << 8) | (asix -> ux_host_class_asix_node_id[5])); + + /* Register this interface to the NetX USB interface broker. */ + status = _ux_network_driver_activate((VOID *) asix, _ux_host_class_asix_write, + &asix -> ux_host_class_asix_network_handle, + physical_address_msw, + physical_address_lsw); } /* Do final things if success. */ @@ -250,12 +258,9 @@ UX_TRANSFER *transfer_request; /* There was a problem, so free the resources. */ - /* Last resource, asix -> ux_host_class_asix_packet_pool is not created or created error, - no need to free. */ - - /* Free asix -> ux_host_class_asix_pool_memory. */ - if (asix -> ux_host_class_asix_pool_memory) - _ux_utility_memory_free(asix -> ux_host_class_asix_pool_memory); + /* Free asix -> ux_host_class_asix_receive_buffer. */ + if (asix -> ux_host_class_asix_receive_buffer) + _ux_utility_memory_free(asix -> ux_host_class_asix_receive_buffer); /* Free asix -> ux_host_class_asix_thread. */ if (asix -> ux_host_class_asix_thread.tx_thread_id) diff --git a/common/usbx_host_classes/src/ux_host_class_asix_deactivate.c b/common/usbx_host_classes/src/ux_host_class_asix_deactivate.c index 32853e52..20d5c610 100644 --- a/common/usbx_host_classes/src/ux_host_class_asix_deactivate.c +++ b/common/usbx_host_classes/src/ux_host_class_asix_deactivate.c @@ -36,7 +36,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_host_class_asix_deactivate PORTABLE C */ -/* 6.1.11 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -85,6 +85,11 @@ /* internal clean up, */ /* fixed standalone compile, */ /* resulting in version 6.1.11 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* supported NX packet chain, */ +/* added reception buffer, */ +/* removed internal NX pool, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_host_class_asix_deactivate(UX_HOST_CLASS_COMMAND *command) @@ -196,12 +201,16 @@ UINT status; /* free its stack memory. */ _ux_utility_memory_free(asix -> ux_host_class_asix_thread_stack); - /* We may have allocated a packet pool. */ - if (asix -> ux_host_class_asix_pool_memory != UX_NULL) - - /* Free this pool of packets. */ - _ux_utility_memory_free(asix -> ux_host_class_asix_pool_memory); - + /* Free receive buffer memory. */ + _ux_utility_memory_free(asix -> ux_host_class_asix_receive_buffer); + +#ifdef UX_HOST_CLASS_ASIX_PACKET_CHAIN_SUPPORT + + /* Free transmit buffer memory. */ + if (asix -> ux_host_class_asix_xmit_buffer) + _ux_utility_memory_free(asix -> ux_host_class_asix_xmit_buffer); +#endif + /* Before we free the device resources, we need to inform the application that the device is removed. */ if (_ux_system_host -> ux_system_host_change_function != UX_NULL) diff --git a/common/usbx_host_classes/src/ux_host_class_asix_endpoints_get.c b/common/usbx_host_classes/src/ux_host_class_asix_endpoints_get.c index 0fae599e..7e676704 100644 --- a/common/usbx_host_classes/src/ux_host_class_asix_endpoints_get.c +++ b/common/usbx_host_classes/src/ux_host_class_asix_endpoints_get.c @@ -35,7 +35,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_host_class_asix_endpoints_get PORTABLE C */ -/* 6.1.9 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -75,6 +75,10 @@ /* use pre-calculated value */ /* instead of wMaxPacketSize, */ /* resulting in version 6.1.9 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* removed packet RX callback, */ +/* refined INT EP start time, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_host_class_asix_endpoints_get(UX_HOST_CLASS_ASIX *asix) @@ -156,9 +160,6 @@ UX_TRANSFER *transfer_request; /* There is a callback function associated with the transfer request, so we need the class instance. */ endpoint -> ux_endpoint_transfer_request.ux_transfer_request_class_instance = (VOID *) asix; - /* The transfer request has a callback function. */ - endpoint -> ux_endpoint_transfer_request.ux_transfer_request_completion_function = _ux_host_class_asix_reception_callback; - /* We have found the bulk endpoint, save it. */ asix -> ux_host_class_asix_bulk_in_endpoint = endpoint; break; @@ -220,22 +221,8 @@ UX_TRANSFER *transfer_request; transfer_request -> ux_transfer_request_data_pointer = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, transfer_request -> ux_transfer_request_requested_length); - /* If the endpoint is available and we have memory, we start the interrupt endpoint. */ - if (transfer_request -> ux_transfer_request_data_pointer != UX_NULL) - { - - /* The transfer on the interrupt endpoint can be started. */ - status = _ux_host_stack_transfer_request(transfer_request); - - /* Check error, if endpoint interrupt IN transfer not successful, do not proceed. */ - if (status != UX_SUCCESS) - - /* Error, do not proceed. */ - return(status); - - } - - else + /* If the endpoint is available and we have memory, it's started later after setup. */ + if (transfer_request -> ux_transfer_request_data_pointer == UX_NULL) { /* Error trap. */ diff --git a/common/usbx_host_classes/src/ux_host_class_asix_entry.c b/common/usbx_host_classes/src/ux_host_class_asix_entry.c index 8d4716eb..aba59b59 100644 --- a/common/usbx_host_classes/src/ux_host_class_asix_entry.c +++ b/common/usbx_host_classes/src/ux_host_class_asix_entry.c @@ -30,12 +30,17 @@ #include "ux_host_stack.h" +#if !defined(UX_HOST_STANDALONE) +static inline UINT _ux_host_class_asix_try_all_vid_pids(UX_HOST_CLASS_COMMAND *command); +#endif + + /**************************************************************************/ /* */ /* FUNCTION RELEASE */ /* */ /* _ux_host_class_asix_entry PORTABLE C */ -/* 6.1.11 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -74,6 +79,10 @@ /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */ /* fixed standalone compile, */ /* resulting in version 6.1.11 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* fixed compile warning, */ +/* refined VID/PID check flow, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_host_class_asix_entry(UX_HOST_CLASS_COMMAND *command) @@ -97,17 +106,8 @@ UINT status; this device or not. */ if(command -> ux_host_class_command_usage == UX_HOST_CLASS_COMMAND_USAGE_PIDVID) { - - /* Try all the possible PID/VID. */ - if ((command -> ux_host_class_command_pid == UX_HOST_CLASS_ASIX_PRODUCT_ID) && - (command -> ux_host_class_command_vid == UX_HOST_CLASS_ASIX_VENDOR_ID )) - return(UX_SUCCESS); - - /* Try all the possible PID/VID. */ - if ((command -> ux_host_class_command_pid == UX_HOST_CLASS_ASIX_PRODUCT_FUJIEI_ID) && - (command -> ux_host_class_command_vid == UX_HOST_CLASS_ASIX_VENDOR_FUJIEI_ID )) - return(UX_SUCCESS); - + if (_ux_host_class_asix_try_all_vid_pids(command) == UX_SUCCESS) + return(UX_SUCCESS); } /* No match. */ @@ -139,4 +139,23 @@ UINT status; } #endif } +#if !defined(UX_HOST_STANDALONE) +static const USHORT _ux_host_class_asix_vid_pid_array[] = +{ + UX_HOST_CLASS_ASIX_VID_PID_ARRAY +}; +static inline UINT _ux_host_class_asix_try_all_vid_pids(UX_HOST_CLASS_COMMAND *command) +{ +UINT i, pos; +UINT n_ids = sizeof(_ux_host_class_asix_vid_pid_array) >> 1; +UINT n_id_pairs = n_ids >> 1; + for (i = 0, pos = 0; i < n_id_pairs; i ++, pos += 2) + { + if ((command -> ux_host_class_command_pid == _ux_host_class_asix_vid_pid_array[pos + 1]) && + (command -> ux_host_class_command_vid == _ux_host_class_asix_vid_pid_array[pos ])) + return(UX_SUCCESS); + } + return(UX_NO_CLASS_MATCH); +} +#endif diff --git a/common/usbx_host_classes/src/ux_host_class_asix_interrupt_notification.c b/common/usbx_host_classes/src/ux_host_class_asix_interrupt_notification.c index 2a4437a6..5717311a 100644 --- a/common/usbx_host_classes/src/ux_host_class_asix_interrupt_notification.c +++ b/common/usbx_host_classes/src/ux_host_class_asix_interrupt_notification.c @@ -35,7 +35,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_host_class_asix_interrupt_notification PORTABLE C */ -/* 6.1.10 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -76,6 +76,10 @@ /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */ /* refined macros names, */ /* resulting in version 6.1.10 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* refined link up/down flow, */ +/* refined interrupt flow, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ VOID _ux_host_class_asix_interrupt_notification(UX_TRANSFER *transfer_request) @@ -127,6 +131,8 @@ UX_HOST_CLASS_ASIX *asix; /* We need to inform the asix thread of this change. */ _ux_host_semaphore_put(&asix -> ux_host_class_asix_interrupt_notification_semaphore); + /* Reactivate interrupt pipe after link up handled. */ + return; } } else @@ -138,53 +144,20 @@ UX_HOST_CLASS_ASIX *asix; { /* Memorize the new link state. */ - asix -> ux_host_class_asix_link_state = UX_HOST_CLASS_ASIX_LINK_STATE_PENDING_DOWN; - - /* We may have transaction pending on bulk in. Inform the class. */ - transfer_request = &asix -> ux_host_class_asix_bulk_in_endpoint -> ux_endpoint_transfer_request; - if (transfer_request -> ux_transfer_request_completion_code == UX_TRANSFER_STATUS_PENDING) - { - - /* Set the completion error code. */ - transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_NO_ANSWER; - - /* Error trap. */ - _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_NO_ANSWER); - - /* If trace is enabled, insert this event into the trace buffer. */ - UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_TRANSFER_NO_ANSWER, transfer_request, 0, 0, UX_TRACE_ERRORS, 0, 0) - - /* Wake up the semaphore on which the transaction is waiting. */ - _ux_host_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); - - } - - /* We may have transaction pending on bulk out. Inform the class. */ - transfer_request = &asix -> ux_host_class_asix_bulk_out_endpoint -> ux_endpoint_transfer_request; - if (transfer_request -> ux_transfer_request_completion_code == UX_TRANSFER_STATUS_PENDING) - { - - /* Set the completion error code. */ - transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_NO_ANSWER; - - /* Error trap. */ - _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_NO_ANSWER); + asix -> ux_host_class_asix_link_state = UX_HOST_CLASS_ASIX_LINK_STATE_PENDING_DOWN; - /* If trace is enabled, insert this event into the trace buffer. */ - UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_TRANSFER_NO_ANSWER, transfer_request, 0, 0, UX_TRACE_ERRORS, 0, 0) - - /* Wake up the semaphore on which the transaction is waiting. */ - _ux_host_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); + /* Abort possible pending bulk in requests. */ + _ux_host_stack_endpoint_transfer_abort(asix -> ux_host_class_asix_bulk_in_endpoint); - } - - /* We need to inform the asix thread of this change. */ _ux_host_semaphore_put(&asix -> ux_host_class_asix_interrupt_notification_semaphore); + + /* Reactivate interrupt pipe after link down handled. */ + return; } - } - } - } + } + } + } /* Reactivate the ASIX interrupt pipe. */ _ux_host_stack_transfer_request(transfer_request); diff --git a/common/usbx_host_classes/src/ux_host_class_asix_reception_callback.c b/common/usbx_host_classes/src/ux_host_class_asix_reception_callback.c index 75ad2e98..e6bff4c0 100644 --- a/common/usbx_host_classes/src/ux_host_class_asix_reception_callback.c +++ b/common/usbx_host_classes/src/ux_host_class_asix_reception_callback.c @@ -35,7 +35,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_host_class_asix_reception_callback PORTABLE C */ -/* 6.1.11 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -46,6 +46,8 @@ /* it is called when a full or partial transfer has been done for a */ /* bulk in transfer. It calls back the application. */ /* */ +/* It's deprecated. */ +/* */ /* INPUT */ /* */ /* transfer_request Pointer to transfer request */ @@ -76,6 +78,10 @@ /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */ /* fixed standalone compile, */ /* resulting in version 6.1.11 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* deprecated, no RX callback, */ +/* modified pool reference, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ VOID _ux_host_class_asix_reception_callback (UX_TRANSFER *transfer_request) @@ -125,7 +131,7 @@ UINT status; nx_packet_transmit_release(packet); /* We can accept new reception. Get a NX Packet */ - if (nx_packet_allocate(&asix -> ux_host_class_asix_packet_pool, &packet, + if (nx_packet_allocate(asix -> ux_host_class_asix_packet_pool, &packet, NX_RECEIVE_PACKET, NX_NO_WAIT) == NX_SUCCESS) { diff --git a/common/usbx_host_classes/src/ux_host_class_asix_thread.c b/common/usbx_host_classes/src/ux_host_class_asix_thread.c index 96f48037..9e301ddf 100644 --- a/common/usbx_host_classes/src/ux_host_class_asix_thread.c +++ b/common/usbx_host_classes/src/ux_host_class_asix_thread.c @@ -31,12 +31,15 @@ #if !defined(UX_HOST_STANDALONE) + +static inline UINT _ux_host_class_asix_link_up_controls(UX_HOST_CLASS_ASIX *asix); + /**************************************************************************/ /* */ /* FUNCTION RELEASE */ /* */ /* _ux_host_class_asix_thread PORTABLE C */ -/* 6.1.11 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -87,35 +90,49 @@ /* internal clean up, */ /* fixed standalone compile, */ /* resulting in version 6.1.11 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* removed internal NX pool, */ +/* moved NX driver activate, */ +/* refined control REQ flow, */ +/* refined reception flow, */ +/* refined interrupt flow, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ VOID _ux_host_class_asix_thread(ULONG parameter) { UX_HOST_CLASS_ASIX *asix; -UCHAR *setup_buffer; -UX_ENDPOINT *control_endpoint; UX_TRANSFER *transfer_request; NX_PACKET *packet; NX_PACKET *current_packet; NX_PACKET *next_packet; +UCHAR *buffer; +ULONG buffer_count; +ULONG asix_length; +ULONG asix_count; +ULONG asix_remain; +ULONG packet_discard; +ULONG buffer_remain; +ULONG copy_length; UINT status; -ULONG physical_address_msw; -ULONG physical_address_lsw; +UX_DEVICE *device; +ULONG available0, available1; +USB_NETWORK_DEVICE_TYPE *ux_nx_device; + /* Cast the parameter passed in the thread into the asix pointer. */ UX_THREAD_EXTENSION_PTR_GET(asix, UX_HOST_CLASS_ASIX, parameter) - /* Loop forever waiting for changes signaled through the semaphore. */ + /* Loop forever waiting for changes signaled through the semaphore. */ while (1) - { + { /* Wait for the semaphore to be put by the asix interrupt event. */ status = _ux_host_semaphore_get(&asix -> ux_host_class_asix_interrupt_notification_semaphore, UX_WAIT_FOREVER); /* Check for successful completion. */ if (status != UX_SUCCESS) - return; /* Protect Thread reentry to this instance. */ @@ -123,299 +140,323 @@ ULONG physical_address_lsw; /* Check for successful completion. */ if (status != UX_SUCCESS) - return; /* Check the link state. It is either pending up or down. */ if (asix -> ux_host_class_asix_link_state == UX_HOST_CLASS_ASIX_LINK_STATE_PENDING_UP) { - /* We need to get the default control endpoint transfer request pointer. */ - control_endpoint = &asix -> ux_host_class_asix_device -> ux_device_control_endpoint; - transfer_request = &control_endpoint -> ux_endpoint_transfer_request; - - /* Need to allocate memory for the buffer. */ - setup_buffer = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_ASIX_SETUP_BUFFER_SIZE); - if (setup_buffer == UX_NULL) + /* Issue a list of control requests to setup link up. */ + status = _ux_host_class_asix_link_up_controls(asix); + if (status != UX_SUCCESS) { /* Unprotect thread reentry to this instance. */ _ux_host_semaphore_put(&asix -> ux_host_class_asix_semaphore); + continue; + } - return; - } - - /* Request ownership of Serial Management Interface. */ - transfer_request -> ux_transfer_request_data_pointer = UX_NULL; - transfer_request -> ux_transfer_request_requested_length = 0; - transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_ASIX_REQ_OWN_SMI ; - transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_VENDOR | UX_REQUEST_TARGET_DEVICE; - transfer_request -> ux_transfer_request_value = 0; - transfer_request -> ux_transfer_request_index = 0; - - /* Send request to HCD layer. */ - status = _ux_host_stack_transfer_request(transfer_request); - - /* Check status, if error, do not proceed. */ - if (status != UX_SUCCESS || transfer_request -> ux_transfer_request_completion_code != UX_SUCCESS) - { - - /* Free all used resources. */ - _ux_utility_memory_free(setup_buffer); + /* Now the link is up. */ + asix -> ux_host_class_asix_link_state = UX_HOST_CLASS_ASIX_LINK_STATE_UP; - /* Unprotect thread reentry to this instance. */ - _ux_host_semaphore_put(&asix -> ux_host_class_asix_semaphore); + /* Communicate the state with the network driver. */ + _ux_network_driver_link_up(asix -> ux_host_class_asix_network_handle); - /* Return completion status. */ - return; - - } - - /* Get the value of the PHYIDR1 in the PHY register. */ - transfer_request -> ux_transfer_request_data_pointer = setup_buffer; - transfer_request -> ux_transfer_request_requested_length = 2; - transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_ASIX_REQ_READ_PHY_REG; - transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_VENDOR | UX_REQUEST_TARGET_DEVICE; - transfer_request -> ux_transfer_request_value = asix -> ux_host_class_asix_primary_phy_id; - transfer_request -> ux_transfer_request_index = UX_HOST_CLASS_ASIX_PHY_REG_ANLPAR; - - /* Send request to HCD layer. */ - status = _ux_host_stack_transfer_request(transfer_request); - - /* Check status, if error, do not proceed. */ - if (status != UX_SUCCESS || transfer_request -> ux_transfer_request_completion_code != UX_SUCCESS || - transfer_request -> ux_transfer_request_actual_length != 2) - { - - /* Free all used resources. */ - _ux_utility_memory_free(setup_buffer); + /* Reactivate interrupt notification polling. */ + _ux_host_stack_transfer_request(&asix -> ux_host_class_asix_interrupt_endpoint -> ux_endpoint_transfer_request); - /* Unprotect thread reentry to this instance. */ - _ux_host_semaphore_put(&asix -> ux_host_class_asix_semaphore); + /* Unprotect thread reentry to this instance. */ + _ux_host_semaphore_put(&asix -> ux_host_class_asix_semaphore); - /* Return completion status. */ - return; - - } + /* Re-check packet pool on link up. */ + asix -> ux_host_class_asix_packet_pool = UX_NULL; - /* Release SMI ownership. */ - transfer_request -> ux_transfer_request_data_pointer = UX_NULL; - transfer_request -> ux_transfer_request_requested_length = 0; - transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_ASIX_REQ_RELEASE_SMI; - transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_VENDOR | UX_REQUEST_TARGET_DEVICE; - transfer_request -> ux_transfer_request_value = 0; - transfer_request -> ux_transfer_request_index = 0; - - /* Send request to HCD layer. */ - status = _ux_host_stack_transfer_request(transfer_request); - - /* Check status, if error, do not proceed. */ - if (status != UX_SUCCESS || transfer_request -> ux_transfer_request_completion_code != UX_SUCCESS) - { - - /* Free all used resources. */ - _ux_utility_memory_free(setup_buffer); + /* Keep polling if device is connected and link is up. */ - /* Unprotect thread reentry to this instance. */ - _ux_host_semaphore_put(&asix -> ux_host_class_asix_semaphore); + /* Initialize variables. */ + device = asix -> ux_host_class_asix_device; + packet = UX_NULL; + buffer = UX_NULL; + asix_length = 0; + asix_count = 0; + buffer_count = 0; + packet_discard = UX_FALSE; + asix -> ux_host_class_asix_packet_available_min = 0xFFFFFFFF; - /* Return completion status. */ - return; - - } - - /* Check speed. */ - if (asix -> ux_host_class_asix_speed_selected == UX_HOST_CLASS_ASIX_SPEED_SELECTED_100MPBS) - - /* Set speed at 100MBPS. */ - transfer_request -> ux_transfer_request_value = UX_HOST_CLASS_ASIX_MEDIUM_PS; - - /* Write the value of the Medium Mode. */ - transfer_request -> ux_transfer_request_data_pointer = UX_NULL; - transfer_request -> ux_transfer_request_requested_length = 0; - transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_ASIX_REQ_WRITE_MEDIUM_MODE; - transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_VENDOR | UX_REQUEST_TARGET_DEVICE; - transfer_request -> ux_transfer_request_value |= (UX_HOST_CLASS_ASIX_MEDIUM_FD | UX_HOST_CLASS_ASIX_MEDIUM_BIT2 | UX_HOST_CLASS_ASIX_MEDIUM_RFC_ENABLED | - UX_HOST_CLASS_ASIX_MEDIUM_TFC_ENABLED | UX_HOST_CLASS_ASIX_MEDIUM_RE_ENABLED); - transfer_request -> ux_transfer_request_index = 0; - - /* Send request to HCD layer. */ - status = _ux_host_stack_transfer_request(transfer_request); - - /* Check status, if error, do not proceed. */ - if (status != UX_SUCCESS || transfer_request -> ux_transfer_request_completion_code != UX_SUCCESS) + /* Polling loop. */ + while(device -> ux_device_state == UX_DEVICE_CONFIGURED && + asix -> ux_host_class_asix_link_state == UX_HOST_CLASS_ASIX_LINK_STATE_UP) { - - /* Free all used resources. */ - _ux_utility_memory_free(setup_buffer); - /* Unprotect thread reentry to this instance. */ - _ux_host_semaphore_put(&asix -> ux_host_class_asix_semaphore); + /* Check if packet pool is ready. */ + if (asix -> ux_host_class_asix_packet_pool == UX_NULL) + { - /* Return completion status. */ - return; - - } + /* Get the network device handle. */ + ux_nx_device = (USB_NETWORK_DEVICE_TYPE *)(asix -> ux_host_class_asix_network_handle); - /* Set the Rx Control register value. */ - transfer_request -> ux_transfer_request_data_pointer = UX_NULL; - transfer_request -> ux_transfer_request_requested_length = 0; - transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_ASIX_REQ_WRITE_RX_CTL; - transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_VENDOR | UX_REQUEST_TARGET_DEVICE; - transfer_request -> ux_transfer_request_value = (UX_HOST_CLASS_ASIX_RXCR_AM | UX_HOST_CLASS_ASIX_RXCR_AB | - UX_HOST_CLASS_ASIX_RXCR_SO | UX_HOST_CLASS_ASIX_RXCR_MFB_2048); - transfer_request -> ux_transfer_request_index = 0; - - /* Send request to HCD layer. */ - status = _ux_host_stack_transfer_request(transfer_request); - - /* Check status, if error, do not proceed. */ - if (status != UX_SUCCESS || transfer_request -> ux_transfer_request_completion_code != UX_SUCCESS) - { - - /* Free all used resources. */ - _ux_utility_memory_free(setup_buffer); - - /* Unprotect thread reentry to this instance. */ - _ux_host_semaphore_put(&asix -> ux_host_class_asix_semaphore); + /* Get packet pool from IP instance (if available). */ + if (ux_nx_device -> ux_network_device_ip_instance != UX_NULL) + { + asix -> ux_host_class_asix_packet_pool = ux_nx_device -> ux_network_device_ip_instance -> nx_ip_default_packet_pool; + } + else + { - /* Return completion status. */ - return; - - } - - /* Set the multicast value. */ - transfer_request -> ux_transfer_request_data_pointer = setup_buffer; - transfer_request -> ux_transfer_request_requested_length = 8; - transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_ASIX_REQ_WRITE_MULTICAST_FILTER; - transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_VENDOR | UX_REQUEST_TARGET_DEVICE; - transfer_request -> ux_transfer_request_value = 0; - transfer_request -> ux_transfer_request_index = 0; - - /* Fill in the multicast filter. */ - _ux_utility_memory_set(setup_buffer, 0, 8); /* Use case of memset is verified. */ - *(setup_buffer +1) = 0x40; - - /* Send request to HCD layer. */ - status = _ux_host_stack_transfer_request(transfer_request); - - /* Check status, if error, do not proceed. */ - if (status != UX_SUCCESS || transfer_request -> ux_transfer_request_completion_code != UX_SUCCESS || - transfer_request -> ux_transfer_request_actual_length != 8) - { - - /* Free all used resources. */ - _ux_utility_memory_free(setup_buffer); - - /* Unprotect thread reentry to this instance. */ - _ux_host_semaphore_put(&asix -> ux_host_class_asix_semaphore); + /* Error trap. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CLASS_ETH_PACKET_POOL_ERROR); - /* Return completion status. */ - return; - - } + _ux_utility_delay_ms(UX_HOST_CLASS_ASIX_PACKET_POOL_WAIT); + continue; + } + } - /* Free all used resources. */ - _ux_utility_memory_free(setup_buffer); + /* Get transfer request for bulk in reception. */ + transfer_request = &asix -> ux_host_class_asix_bulk_in_endpoint -> ux_endpoint_transfer_request; - /* Setup the physical address of this IP instance. */ - physical_address_msw = (ULONG)((asix -> ux_host_class_asix_node_id[0] << 8) | (asix -> ux_host_class_asix_node_id[1])); - physical_address_lsw = (ULONG)((asix -> ux_host_class_asix_node_id[2] << 24) | (asix -> ux_host_class_asix_node_id[3] << 16) | - (asix -> ux_host_class_asix_node_id[4] << 8) | (asix -> ux_host_class_asix_node_id[5])); - - /* Register this interface to the NetX USB interface broker. */ - status = _ux_network_driver_activate((VOID *) asix, _ux_host_class_asix_write, - &asix -> ux_host_class_asix_network_handle, - physical_address_msw, - physical_address_lsw); - if (status != UX_SUCCESS) - { + /* If there is no buffer ready, read it. */ + if (buffer == UX_NULL) + { - /* Unprotect thread reentry to this instance. */ - _ux_host_semaphore_put(&asix -> ux_host_class_asix_semaphore); + /* Set the data pointer. */ + transfer_request -> ux_transfer_request_data_pointer = asix -> ux_host_class_asix_receive_buffer; + + /* And length. */ + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_ASIX_RECEIVE_BUFFER_SIZE; + transfer_request -> ux_transfer_request_actual_length = 0; + + /* Schedule a reception. */ + status = _ux_host_stack_transfer_request(transfer_request); + + /* Check if it's started successfully. */ + if (status != UX_SUCCESS) + { + + /* If a packet (chain) is on-going, release it. */ + if (packet != UX_NULL) + { + nx_packet_release(packet); + packet = UX_NULL; + } + continue; + } + + /* Wait for transfer completion. */ + _ux_host_semaphore_get_norc(&transfer_request -> ux_transfer_request_semaphore, UX_WAIT_FOREVER); + + /* Check completion code. */ + if (transfer_request -> ux_transfer_request_completion_code != UX_SUCCESS) + { + + /* Abort transfer. */ + _ux_host_stack_transfer_request_abort(transfer_request); + + /* If a packet (chain) is on-going, release it. */ + if (packet != UX_NULL) + { + nx_packet_release(packet); + packet = UX_NULL; + } + continue; + } + + /* If it's ZLP, reset buffer and ASIX packet and transfer again. */ + if (transfer_request -> ux_transfer_request_actual_length == 0) + { + + /* Packet should have been processed! */ + if (packet != UX_NULL) + { + + /* ASIX header corrupt? */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED); + nx_packet_release(packet); + packet = UX_NULL; + } + + buffer = UX_NULL; + buffer_count = 0; + asix_length = 0; + continue; + } + + /* Buffer is ready. */ + buffer = asix -> ux_host_class_asix_receive_buffer; + } - /* Return completion status. */ - return; - } + /* There is data in buffer, extract the data to packets. */ - /* Now the link is up. */ - asix -> ux_host_class_asix_link_state = UX_HOST_CLASS_ASIX_LINK_STATE_UP; + /* If there is no packet, allocate it. */ + if (packet == UX_NULL) + { - /* Communicate the state with the network driver. */ - _ux_network_driver_link_up(asix -> ux_host_class_asix_network_handle); - - /* We can accept reception. Get a NX Packet */ - if (nx_packet_allocate(&asix -> ux_host_class_asix_packet_pool, &packet, - NX_RECEIVE_PACKET, NX_NO_WAIT) == NX_SUCCESS) - { + /* Get a free NX Packet. */ + available0 = asix -> ux_host_class_asix_packet_pool -> nx_packet_pool_available; + status = nx_packet_allocate(asix -> ux_host_class_asix_packet_pool, + &packet, NX_RECEIVE_PACKET, + UX_MS_TO_TICK(UX_HOST_CLASS_ASIX_PACKET_ALLOCATE_WAIT)); + available1 = asix -> ux_host_class_asix_packet_pool -> nx_packet_pool_available; + if (asix -> ux_host_class_asix_packet_available_min > available1) + asix -> ux_host_class_asix_packet_available_min = available1; + if (asix -> ux_host_class_asix_packet_available_min > available0) + asix -> ux_host_class_asix_packet_available_min = available0; + if (status != NX_SUCCESS) + { + + /* Error trap. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CLASS_ETH_PACKET_ERROR); + continue; + } + + /* Adjust the prepend pointer to take into account the non 3 bit alignment of the ethernet header. */ + packet -> nx_packet_prepend_ptr += sizeof(USHORT); + packet -> nx_packet_append_ptr = packet -> nx_packet_prepend_ptr; + + /* Log the packet. */ + } - /* Adjust the prepend pointer to take into account the non 3 bit alignment of the ethernet header. */ - packet -> nx_packet_prepend_ptr += sizeof(USHORT); + /* Get remaining in buffer. */ + buffer_remain = transfer_request -> ux_transfer_request_actual_length - + buffer_count; - /* We have a packet. Link this packet to the reception transfer request on the bulk in endpoint. */ - transfer_request = &asix -> ux_host_class_asix_bulk_in_endpoint -> ux_endpoint_transfer_request; - - /* Set the data pointer. */ - transfer_request -> ux_transfer_request_data_pointer = packet -> nx_packet_prepend_ptr; + /* For new packet, get packet length from ASIX header. */ + if (asix_length == 0) + { - /* And length. */ - transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_ASIX_NX_PAYLOAD_SIZE; - transfer_request -> ux_transfer_request_actual_length = 0; + /* If remaining less than 2 bytes in buffer, read buffer again. */ + if (buffer_remain < 2) + { + buffer = UX_NULL; + buffer_count = 0; + continue; + } + + /* Get ASIX packet length. */ + asix_length = _ux_utility_short_get(buffer + buffer_count); + asix_length &= UX_HOST_CLASS_ASIX_RX_PACKET_LENGTH_MASK; + asix_count = 0; + + /* If remaining 2-3 bytes, skip 2 of next buffer. */ + if (buffer_remain < 4) + { + buffer = UX_NULL; + buffer_count = 2; + continue; + } + + /* Skip header in buffer, it's not copied to NX packet. */ + buffer_count += 4; + buffer_remain -= 4; + } - /* Store the packet that owns this transaction. */ - transfer_request -> ux_transfer_request_user_specific = packet; + /* Get remaining in ASIX packet. */ + asix_remain = asix_length - asix_count; - /* Memorize this packet at the beginning of the queue. */ - asix -> ux_host_class_asix_receive_queue = packet; - - /* Reset the queue pointer of this packet. */ - packet -> nx_packet_queue_next = UX_NULL; + /* Get actual length to process. */ + if (asix_remain <= buffer_remain) + copy_length = asix_remain; + else + copy_length = buffer_remain; - /* Ask USB to schedule a reception. */ - status = _ux_host_stack_transfer_request(transfer_request); + /* Check if the data is discarded. */ + if (packet_discard == UX_FALSE && copy_length) + { - /* Check if the transaction was armed successfully. We do not wait for the packet to be sent here. */ - if (status != UX_SUCCESS) + /* Append data to packet. */ + status = nx_packet_data_append(packet, + buffer + buffer_count, copy_length, + asix -> ux_host_class_asix_packet_pool, + UX_MS_TO_TICK(UX_HOST_CLASS_ASIX_PACKET_ALLOCATE_WAIT)); + if (status != NX_SUCCESS) + { + + /* There is error, this ASIX packet is discarded. */ + packet_discard = UX_TRUE; + } + } + + /* Update counts. */ + buffer_count += copy_length; + asix_count += copy_length; + + /* If packet size is odd, padding one byte is ignored. */ + if (asix_length & 0x1u) + buffer_count ++; + + /* Check if buffer ends. */ + if (buffer_count >= transfer_request -> ux_transfer_request_actual_length) { + buffer = UX_NULL; + buffer_count = 0; + } - /* Cancel the packet. */ - asix -> ux_host_class_asix_receive_queue = UX_NULL; - + /* Check if ASIX packet ends. + * - ASIX count achieve its length. + * - Buffer achieve its end and it's a short packet. + */ + if (asix_count >= asix_length || + (buffer == UX_NULL && + transfer_request -> ux_transfer_request_actual_length < + transfer_request -> ux_transfer_request_requested_length)) + { + + /* Check if packet is discarded. */ + if (packet_discard) + { + + packet_discard = UX_FALSE; + + /* Re-allocate packet. */ + nx_packet_release(packet); + packet = UX_NULL; + continue; + } + + /* Send that packet to the NetX USB broker. */ + _ux_network_driver_packet_received(asix -> ux_host_class_asix_network_handle, packet); + packet = UX_NULL; + + /* Reset ASIX packet. */ + asix_length = 0; + + continue; } + /* Buffer ends but packet continues. */ + /* Buffer already reset to start reception again. */ } - /* Unprotect thread reentry to this instance. */ - _ux_host_semaphore_put(&asix -> ux_host_class_asix_semaphore); - - return; + /* Release packet not sent to NX. */ + if (packet) + nx_packet_release(packet); } - - /* Check the link state. It is either pending up or down. */ - if (asix -> ux_host_class_asix_link_state == UX_HOST_CLASS_ASIX_LINK_STATE_PENDING_DOWN) + else { - + + /* Abort pending transfers. */ + _ux_host_stack_endpoint_transfer_abort(asix -> ux_host_class_asix_bulk_out_endpoint); + /* We need to free the packets that will not be sent. */ current_packet = asix -> ux_host_class_asix_xmit_queue; - + /* Get the next packet associated with the first packet. */ next_packet = current_packet -> nx_packet_queue_next; - + /* Parse all these packets that were scheduled. */ while (current_packet != UX_NULL) { - + /* Free the packet that was just sent. First do some housekeeping. */ - current_packet -> nx_packet_prepend_ptr = current_packet -> nx_packet_prepend_ptr + UX_HOST_CLASS_ASIX_ETHERNET_SIZE; + current_packet -> nx_packet_prepend_ptr = current_packet -> nx_packet_prepend_ptr + UX_HOST_CLASS_ASIX_ETHERNET_SIZE; current_packet -> nx_packet_length = current_packet -> nx_packet_length - UX_HOST_CLASS_ASIX_ETHERNET_SIZE; /* And ask Netx to release it. */ - nx_packet_transmit_release(current_packet); - + nx_packet_transmit_release(current_packet); + /* Next packet becomes the current one. */ current_packet = next_packet; - + /* Next packet now. */ if (current_packet != UX_NULL) @@ -423,20 +464,176 @@ ULONG physical_address_lsw; next_packet = current_packet -> nx_packet_queue_next; } - + + /* Communicate the state with the network driver. */ + _ux_network_driver_link_down(asix -> ux_host_class_asix_network_handle); /* Now the link is down. */ asix -> ux_host_class_asix_link_state = UX_HOST_CLASS_ASIX_LINK_STATE_DOWN; - /* Communicate the state with the network driver. */ - _ux_network_driver_link_down(asix -> ux_host_class_asix_network_handle); - + /* Reactivate interrupt notification polling. */ + _ux_host_stack_transfer_request(&asix -> ux_host_class_asix_interrupt_endpoint -> ux_endpoint_transfer_request); + /* Unprotect thread reentry to this instance. */ _ux_host_semaphore_put(&asix -> ux_host_class_asix_semaphore); - - return; - } } } + +static inline UINT _ux_host_class_asix_link_up_controls(UX_HOST_CLASS_ASIX *asix) +{ + +UCHAR *setup_buffer; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UINT status; + + + /* We need to get the default control endpoint transfer request pointer. */ + control_endpoint = &asix -> ux_host_class_asix_device -> ux_device_control_endpoint; + transfer_request = &control_endpoint -> ux_endpoint_transfer_request; + + /* Need to allocate memory for the buffer. */ + setup_buffer = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_ASIX_SETUP_BUFFER_SIZE); + if (setup_buffer == UX_NULL) + return(UX_MEMORY_INSUFFICIENT); + + /* Request ownership of Serial Management Interface. */ + transfer_request -> ux_transfer_request_data_pointer = UX_NULL; + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_ASIX_REQ_OWN_SMI ; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_VENDOR | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = 0; + + /* Send request to HCD layer. */ + status = _ux_host_stack_transfer_request(transfer_request); + + /* Check status, if error, do not proceed. */ + if (status != UX_SUCCESS || transfer_request -> ux_transfer_request_completion_code != UX_SUCCESS) + { + + /* Free all used resources. */ + _ux_utility_memory_free(setup_buffer); + return(UX_TRANSFER_ERROR); + } + + /* Get the value of the PHYIDR1 in the PHY register. */ + transfer_request -> ux_transfer_request_data_pointer = setup_buffer; + transfer_request -> ux_transfer_request_requested_length = 2; + transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_ASIX_REQ_READ_PHY_REG; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_VENDOR | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = asix -> ux_host_class_asix_primary_phy_id; + transfer_request -> ux_transfer_request_index = UX_HOST_CLASS_ASIX_PHY_REG_ANLPAR; + + /* Send request to HCD layer. */ + status = _ux_host_stack_transfer_request(transfer_request); + + /* Check status, if error, do not proceed. */ + if (status != UX_SUCCESS || transfer_request -> ux_transfer_request_completion_code != UX_SUCCESS || + transfer_request -> ux_transfer_request_actual_length != 2) + { + + /* Free all used resources. */ + _ux_utility_memory_free(setup_buffer); + return(UX_TRANSFER_ERROR); + } + + /* Release SMI ownership. */ + transfer_request -> ux_transfer_request_data_pointer = UX_NULL; + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_ASIX_REQ_RELEASE_SMI; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_VENDOR | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = 0; + + /* Send request to HCD layer. */ + status = _ux_host_stack_transfer_request(transfer_request); + + /* Check status, if error, do not proceed. */ + if (status != UX_SUCCESS || transfer_request -> ux_transfer_request_completion_code != UX_SUCCESS) + { + + /* Free all used resources. */ + _ux_utility_memory_free(setup_buffer); + return(UX_TRANSFER_ERROR); + } + + /* Check speed. */ + if (asix -> ux_host_class_asix_speed_selected == UX_HOST_CLASS_ASIX_SPEED_SELECTED_100MPBS) + + /* Set speed at 100MBPS. */ + transfer_request -> ux_transfer_request_value = UX_HOST_CLASS_ASIX_MEDIUM_PS; + + /* Write the value of the Medium Mode. */ + transfer_request -> ux_transfer_request_data_pointer = UX_NULL; + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_ASIX_REQ_WRITE_MEDIUM_MODE; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_VENDOR | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value |= (UX_HOST_CLASS_ASIX_MEDIUM_FD | UX_HOST_CLASS_ASIX_MEDIUM_BIT2 | UX_HOST_CLASS_ASIX_MEDIUM_RFC_ENABLED | + UX_HOST_CLASS_ASIX_MEDIUM_TFC_ENABLED | UX_HOST_CLASS_ASIX_MEDIUM_RE_ENABLED); + transfer_request -> ux_transfer_request_index = 0; + + /* Send request to HCD layer. */ + status = _ux_host_stack_transfer_request(transfer_request); + + /* Check status, if error, do not proceed. */ + if (status != UX_SUCCESS || transfer_request -> ux_transfer_request_completion_code != UX_SUCCESS) + { + + /* Free all used resources. */ + _ux_utility_memory_free(setup_buffer); + return(UX_TRANSFER_ERROR); + } + + /* Set the Rx Control register value. */ + transfer_request -> ux_transfer_request_data_pointer = UX_NULL; + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_ASIX_REQ_WRITE_RX_CTL; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_VENDOR | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = (UX_HOST_CLASS_ASIX_RXCR_AM | UX_HOST_CLASS_ASIX_RXCR_AB | + UX_HOST_CLASS_ASIX_RXCR_SO | UX_HOST_CLASS_ASIX_RXCR_MFB_2048); + transfer_request -> ux_transfer_request_index = 0; + + /* Send request to HCD layer. */ + status = _ux_host_stack_transfer_request(transfer_request); + + /* Check status, if error, do not proceed. */ + if (status != UX_SUCCESS || transfer_request -> ux_transfer_request_completion_code != UX_SUCCESS) + { + + /* Free all used resources. */ + _ux_utility_memory_free(setup_buffer); + return(UX_TRANSFER_ERROR); + } + + /* Set the multicast value. */ + transfer_request -> ux_transfer_request_data_pointer = setup_buffer; + transfer_request -> ux_transfer_request_requested_length = 8; + transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_ASIX_REQ_WRITE_MULTICAST_FILTER; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_VENDOR | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = 0; + + /* Fill in the multicast filter. */ + _ux_utility_memory_set(setup_buffer, 0, 8); /* Use case of memset is verified. */ + *(setup_buffer +1) = 0x40; + + /* Send request to HCD layer. */ + status = _ux_host_stack_transfer_request(transfer_request); + + /* Check status, if error, do not proceed. */ + if (status != UX_SUCCESS || transfer_request -> ux_transfer_request_completion_code != UX_SUCCESS || + transfer_request -> ux_transfer_request_actual_length != 8) + { + + /* Free all used resources. */ + _ux_utility_memory_free(setup_buffer); + return(UX_TRANSFER_ERROR); + } + + /* Free all used resources. */ + _ux_utility_memory_free(setup_buffer); + return(UX_SUCCESS); +} #endif diff --git a/common/usbx_host_classes/src/ux_host_class_asix_transmission_callback.c b/common/usbx_host_classes/src/ux_host_class_asix_transmission_callback.c index 204af595..13f29678 100644 --- a/common/usbx_host_classes/src/ux_host_class_asix_transmission_callback.c +++ b/common/usbx_host_classes/src/ux_host_class_asix_transmission_callback.c @@ -35,7 +35,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_host_class_asix_transmission_callback PORTABLE C */ -/* 6.1.11 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -77,6 +77,10 @@ /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */ /* fixed standalone compile, */ /* resulting in version 6.1.11 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* supported NX packet chain, */ +/* fixed empty queue handling, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ VOID _ux_host_class_asix_transmission_callback (UX_TRANSFER *transfer_request) @@ -89,6 +93,9 @@ UX_HOST_CLASS_ASIX *asix; NX_PACKET *current_packet; NX_PACKET *next_packet; UCHAR *packet_header; +#ifdef UX_HOST_CLASS_ASIX_PACKET_CHAIN_SUPPORT +ULONG copied; +#endif /* Get the class instance for this transfer request. */ asix = (UX_HOST_CLASS_ASIX *) transfer_request -> ux_transfer_request_class_instance; @@ -110,7 +117,19 @@ UCHAR *packet_header; /* Check if there is another transfer for this pipe. */ current_packet = asix -> ux_host_class_asix_xmit_queue; - + if (current_packet == UX_NULL) + return; + + /* Check if a ZLP is needed. */ + if ((transfer_request -> ux_transfer_request_actual_length > 0) && + ((transfer_request -> ux_transfer_request_actual_length % + transfer_request -> ux_transfer_request_packet_length) == 0)) + { + transfer_request -> ux_transfer_request_requested_length = 0; + _ux_host_stack_transfer_request(transfer_request); + return; + } + /* Get the next packet associated with the first packet. */ next_packet = current_packet -> nx_packet_queue_next; @@ -132,10 +151,33 @@ UCHAR *packet_header; /* Store the negative length of the payload in the first USHORT. */ _ux_utility_short_put(packet_header+ sizeof(USHORT), (USHORT)(~next_packet -> nx_packet_length)); - - /* Prepare the values for this new transmission. */ - transfer_request -> ux_transfer_request_data_pointer = packet_header; - transfer_request -> ux_transfer_request_requested_length = next_packet -> nx_packet_length + (ULONG)sizeof(USHORT) * 2; + +#ifdef UX_HOST_CLASS_ASIX_PACKET_CHAIN_SUPPORT + + /* Check if the packets are chained. */ + if (next_packet -> nx_packet_next) + { + + next_packet -> nx_packet_length += sizeof(USHORT) * 2; + next_packet -> nx_packet_prepend_ptr -= sizeof(USHORT) * 2; + nx_packet_data_extract_offset(next_packet, 0, asix -> ux_host_class_asix_xmit_buffer, next_packet -> nx_packet_length, &copied); + + /* Setup the transaction parameters. */ + transfer_request -> ux_transfer_request_requested_length = next_packet -> nx_packet_length; + transfer_request -> ux_transfer_request_data_pointer = asix -> ux_host_class_asix_xmit_buffer; + + /* Restore packet status. */ + next_packet -> nx_packet_length -= sizeof(USHORT) * 2; + next_packet -> nx_packet_prepend_ptr += sizeof(USHORT) * 2; + } + else +#endif + { + + /* Prepare the values for this new transmission. */ + transfer_request -> ux_transfer_request_data_pointer = packet_header; + transfer_request -> ux_transfer_request_requested_length = next_packet -> nx_packet_length + (ULONG)sizeof(USHORT) * 2; + } /* Store the packet that owns this transaction. */ transfer_request -> ux_transfer_request_user_specific = next_packet; diff --git a/common/usbx_host_classes/src/ux_host_class_asix_write.c b/common/usbx_host_classes/src/ux_host_class_asix_write.c index d30bf62c..175e9b6f 100644 --- a/common/usbx_host_classes/src/ux_host_class_asix_write.c +++ b/common/usbx_host_classes/src/ux_host_class_asix_write.c @@ -35,7 +35,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_host_class_asix_write PORTABLE C */ -/* 6.1.11 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -77,6 +77,11 @@ /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */ /* fixed standalone compile, */ /* resulting in version 6.1.11 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* supported NX packet chain, */ +/* added queue modify protect, */ +/* improved error check, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_host_class_asix_write(VOID *asix_class, NX_PACKET *packet) @@ -87,12 +92,17 @@ UINT _ux_host_class_asix_write(VOID *asix_class, NX_PACKET *packet) return(UX_FUNCTION_NOT_SUPPORTED); #else +UX_INTERRUPT_SAVE_AREA UX_TRANSFER *transfer_request; UINT status; NX_PACKET *current_packet; NX_PACKET *next_packet; UCHAR *packet_header; UX_HOST_CLASS_ASIX *asix; +ULONG adjusted_length; +#ifdef UX_HOST_CLASS_ASIX_PACKET_CHAIN_SUPPORT +ULONG copied; +#endif /* Proper class casting. */ asix = (UX_HOST_CLASS_ASIX *) asix_class; @@ -100,6 +110,9 @@ UX_HOST_CLASS_ASIX *asix; /* If trace is enabled, insert this event into the trace buffer. */ UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_ASIX_WRITE, asix, 0, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0) + /* Critical enter. */ + UX_DISABLE + /* Ensure the instance is valid. */ if (asix -> ux_host_class_asix_state != UX_HOST_CLASS_INSTANCE_LIVE) { @@ -110,9 +123,28 @@ UX_HOST_CLASS_ASIX *asix; /* If trace is enabled, insert this event into the trace buffer. */ UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_INSTANCE_UNKNOWN, asix, 0, 0, UX_TRACE_ERRORS, 0, 0) + /* Critical exit. */ + UX_RESTORE; return(UX_HOST_CLASS_INSTANCE_UNKNOWN); } + /* Ensure link state is OK. */ + if (asix -> ux_host_class_asix_link_state != UX_HOST_CLASS_ASIX_LINK_STATE_UP) + { + + /* Critical exit. */ + UX_RESTORE; + + /* Release the packet. */ + packet -> nx_packet_prepend_ptr = packet -> nx_packet_prepend_ptr + NX_ETHERNET_SIZE; + packet -> nx_packet_length = packet -> nx_packet_length - NX_ETHERNET_SIZE; + nx_packet_transmit_release(packet); + + /* Report error to application. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CLASS_ETH_LINK_STATE_DOWN_ERROR); + return(UX_CLASS_ETH_LINK_STATE_DOWN_ERROR); + } + /* Load the address of the current packet header at the physical header. */ packet_header = packet -> nx_packet_prepend_ptr; @@ -120,16 +152,38 @@ UX_HOST_CLASS_ASIX *asix; packet_header -= sizeof(USHORT) * 2; #if defined(UX_HOST_CLASS_ASIX_HEADER_CHECK_ENABLE) + /* Check packet compatibility to avoid writing to unexpected area. */ if (packet_header < packet -> nx_packet_data_start) { /* Error trap. */ _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_MEMORY_ERROR); + + UX_RESTORE; return(UX_HOST_CLASS_MEMORY_ERROR); } #endif + /* Packet length validation. */ + if (UX_OVERFLOW_CHECK_ADD_ULONG(packet -> nx_packet_length, sizeof(USHORT) * 2)) + { + + /* Error trap. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_MATH_OVERFLOW); + UX_RESTORE + return(UX_MATH_OVERFLOW); + } + adjusted_length = packet -> nx_packet_length + sizeof(USHORT) * 2; + if (adjusted_length > UX_HOST_CLASS_ASIX_TRANSMIT_BUFFER_SIZE) + { + + /* Error trap. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CLASS_ETH_SIZE_ERROR); + UX_RESTORE + return(UX_CLASS_ETH_SIZE_ERROR); + } + /* Store the length of the payload in the first USHORT. */ _ux_utility_short_put(packet_header, (USHORT)(packet -> nx_packet_length)); @@ -140,14 +194,57 @@ UX_HOST_CLASS_ASIX *asix; if (asix -> ux_host_class_asix_xmit_queue == UX_NULL) { + /* Reset the queue pointer of this packet. */ + packet -> nx_packet_queue_next = UX_NULL; + + /* Memorize this packet at the beginning of the queue. */ + asix -> ux_host_class_asix_xmit_queue = packet; + + UX_RESTORE + /* Nothing is in the queue. We need to arm this transfer. */ /* Get the pointer to the bulk out endpoint transfer request. */ transfer_request = &asix -> ux_host_class_asix_bulk_out_endpoint -> ux_endpoint_transfer_request; - /* Setup the transaction parameters. */ - transfer_request -> ux_transfer_request_data_pointer = packet_header; - transfer_request -> ux_transfer_request_requested_length = packet -> nx_packet_length + (ULONG)sizeof(USHORT) * 2; - +#ifdef UX_HOST_CLASS_ASIX_PACKET_CHAIN_SUPPORT + + /* Check if the packets are chained. */ + if (packet -> nx_packet_next) + { + + /* Create buffer. */ + if (asix -> ux_host_class_asix_xmit_buffer == UX_NULL) + { + asix -> ux_host_class_asix_xmit_buffer = _ux_utility_memory_allocate(UX_NO_ALIGN, + UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_ASIX_TRANSMIT_BUFFER_SIZE); + if (asix -> ux_host_class_asix_xmit_buffer == UX_NULL) + { + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_MEMORY_INSUFFICIENT); + return(UX_MEMORY_INSUFFICIENT); + } + } + + packet -> nx_packet_length = adjusted_length; + packet -> nx_packet_prepend_ptr -= sizeof(USHORT) * 2; + nx_packet_data_extract_offset(packet, 0, asix -> ux_host_class_asix_xmit_buffer, packet -> nx_packet_length, &copied); + + /* Setup the transaction parameters. */ + transfer_request -> ux_transfer_request_requested_length = packet -> nx_packet_length; + transfer_request -> ux_transfer_request_data_pointer = asix -> ux_host_class_asix_xmit_buffer; + + /* Restore packet status. */ + packet -> nx_packet_length -= sizeof(USHORT) * 2; + packet -> nx_packet_prepend_ptr += sizeof(USHORT) * 2; + } + else +#endif + { + + /* Setup the transaction parameters. */ + transfer_request -> ux_transfer_request_data_pointer = packet_header; + transfer_request -> ux_transfer_request_requested_length = adjusted_length; + } + /* Store the packet that owns this transaction. */ transfer_request -> ux_transfer_request_user_specific = packet; @@ -155,22 +252,13 @@ UX_HOST_CLASS_ASIX *asix; status = _ux_host_stack_transfer_request(transfer_request); /* Check if the transaction was armed successfully. We do not wait for the packet to be sent here. */ - if (status == UX_SUCCESS) + if (status != UX_SUCCESS) { - - /* Memorize this packet at the beginning of the queue. */ - asix -> ux_host_class_asix_xmit_queue = packet; - - /* Reset the queue pointer of this packet. */ - packet -> nx_packet_queue_next = UX_NULL; - - } - - else /* Could not arm this transfer. */ + asix -> ux_host_class_asix_xmit_queue = UX_NULL; return(UX_ERROR); - + } } else @@ -199,6 +287,8 @@ UX_HOST_CLASS_ASIX *asix; /* The packet to be sent is the last in the chain. */ packet -> nx_packet_queue_next = NX_NULL; + + UX_RESTORE } /* We are done here. */ diff --git a/common/usbx_host_classes/src/ux_host_class_cdc_ecm_activate.c b/common/usbx_host_classes/src/ux_host_class_cdc_ecm_activate.c index 3d1dfde8..f2613314 100644 --- a/common/usbx_host_classes/src/ux_host_class_cdc_ecm_activate.c +++ b/common/usbx_host_classes/src/ux_host_class_cdc_ecm_activate.c @@ -37,7 +37,7 @@ UX_HOST_CLASS_CDC_ECM_NX_ETHERNET_POOL_ALLOCSIZE_ASSERT /* FUNCTION RELEASE */ /* */ /* _ux_host_class_cdc_ecm_activate PORTABLE C */ -/* 6.1.12 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -100,6 +100,10 @@ UX_HOST_CLASS_CDC_ECM_NX_ETHERNET_POOL_ALLOCSIZE_ASSERT /* fixed parameter/variable */ /* names conflict C++ keyword, */ /* resulting in version 6.1.12 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* deprecated ECM pool option, */ +/* supported NX packet chain, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_host_class_cdc_ecm_activate(UX_HOST_CLASS_COMMAND *command) @@ -208,19 +212,7 @@ UX_INTERFACE *cur_interface; if (cdc_ecm -> ux_host_class_cdc_ecm_thread_stack == UX_NULL) status = UX_MEMORY_INSUFFICIENT; } -#ifndef UX_HOST_CLASS_CDC_ECM_USE_PACKET_POOL_FROM_NETX - if (status == UX_SUCCESS) - { - /* Allocate some packet pool for reception. - * UX_HOST_CLASS_CDC_ECM_NX_ETHERNET_POOL_ALLOCSIZE overflow has been checked by - * UX_HOST_CLASS_CDC_ECM_NX_ETHERNET_POOL_ALLOCSIZE_ASSERT outside of function. - */ - cdc_ecm -> ux_host_class_cdc_ecm_pool_memory = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_CDC_ECM_NX_ETHERNET_POOL_ALLOCSIZE); - if (cdc_ecm -> ux_host_class_cdc_ecm_pool_memory == UX_NULL) - status = UX_MEMORY_INSUFFICIENT; - } -#endif if (status == UX_SUCCESS) { @@ -240,126 +232,110 @@ UX_INTERFACE *cur_interface; status = _ux_host_semaphore_create(&cdc_ecm -> ux_host_class_cdc_ecm_interrupt_notification_semaphore, "host CDC-ECM interrupt notification semaphore", 0); if (status == UX_SUCCESS) { -#ifndef UX_HOST_CLASS_CDC_ECM_USE_PACKET_POOL_FROM_NETX - /* Create a packet pool. */ - status = nx_packet_pool_create(&cdc_ecm -> ux_host_class_cdc_ecm_packet_pool, "host CDC-ECM packet pool", - UX_HOST_CLASS_CDC_ECM_NX_PAYLOAD_SIZE, cdc_ecm -> ux_host_class_cdc_ecm_pool_memory, UX_HOST_CLASS_CDC_ECM_NX_ETHERNET_POOL_ALLOCSIZE); + + /* Create the cdc_ecm class thread. We do not start it yet. */ + status = _ux_utility_thread_create(&cdc_ecm -> ux_host_class_cdc_ecm_thread, + "ux_host_cdc_ecm_thread", _ux_host_class_cdc_ecm_thread, + (ULONG) (ALIGN_TYPE) cdc_ecm, + cdc_ecm -> ux_host_class_cdc_ecm_thread_stack, + UX_THREAD_STACK_SIZE, + UX_THREAD_PRIORITY_CLASS, + UX_THREAD_PRIORITY_CLASS, + UX_NO_TIME_SLICE, UX_DONT_START); if (status == UX_SUCCESS) { -#endif - /* Create the cdc_ecm class thread. We do not start it yet. */ - status = _ux_utility_thread_create(&cdc_ecm -> ux_host_class_cdc_ecm_thread, - "ux_host_cdc_ecm_thread", _ux_host_class_cdc_ecm_thread, - (ULONG) (ALIGN_TYPE) cdc_ecm, - cdc_ecm -> ux_host_class_cdc_ecm_thread_stack, - UX_THREAD_STACK_SIZE, - UX_THREAD_PRIORITY_CLASS, - UX_THREAD_PRIORITY_CLASS, - UX_NO_TIME_SLICE, UX_DONT_START); + + UX_THREAD_EXTENSION_PTR_SET(&(cdc_ecm -> ux_host_class_cdc_ecm_thread), cdc_ecm) + + /* We now need to retrieve the MAC address of the node which is embedded in the ECM descriptor. + We will parse the entire configuration descriptor of the device and look for the ECM Ethernet Networking Functional Descriptor. */ + status = _ux_host_class_cdc_ecm_mac_address_get(cdc_ecm); + if (status == UX_SUCCESS) { - UX_THREAD_EXTENSION_PTR_SET(&(cdc_ecm -> ux_host_class_cdc_ecm_thread), cdc_ecm) + /* Setup the physical address of this IP instance. */ + physical_address_msw = (ULONG)((cdc_ecm -> ux_host_class_cdc_ecm_node_id[0] << 8) | (cdc_ecm -> ux_host_class_cdc_ecm_node_id[1])); + physical_address_lsw = (ULONG)((cdc_ecm -> ux_host_class_cdc_ecm_node_id[2] << 24) | (cdc_ecm -> ux_host_class_cdc_ecm_node_id[3] << 16) | + (cdc_ecm -> ux_host_class_cdc_ecm_node_id[4] << 8) | (cdc_ecm -> ux_host_class_cdc_ecm_node_id[5])); - /* We now need to retrieve the MAC address of the node which is embedded in the ECM descriptor. - We will parse the entire configuration descriptor of the device and look for the ECM Ethernet Networking Functional Descriptor. */ - status = _ux_host_class_cdc_ecm_mac_address_get(cdc_ecm); + /* The ethernet link is down by default. */ + cdc_ecm -> ux_host_class_cdc_ecm_link_state = UX_HOST_CLASS_CDC_ECM_LINK_STATE_DOWN; + } - if (status == UX_SUCCESS) - { + if (status == UX_SUCCESS) + { - /* Setup the physical address of this IP instance. */ - physical_address_msw = (ULONG)((cdc_ecm -> ux_host_class_cdc_ecm_node_id[0] << 8) | (cdc_ecm -> ux_host_class_cdc_ecm_node_id[1])); - physical_address_lsw = (ULONG)((cdc_ecm -> ux_host_class_cdc_ecm_node_id[2] << 24) | (cdc_ecm -> ux_host_class_cdc_ecm_node_id[3] << 16) | - (cdc_ecm -> ux_host_class_cdc_ecm_node_id[4] << 8) | (cdc_ecm -> ux_host_class_cdc_ecm_node_id[5])); + /* Register this interface to the NetX USB interface broker. */ + status = _ux_network_driver_activate((VOID *) cdc_ecm, _ux_host_class_cdc_ecm_write, + &cdc_ecm -> ux_host_class_cdc_ecm_network_handle, + physical_address_msw, physical_address_lsw); + } - /* The ethernet link is down by default. */ - cdc_ecm -> ux_host_class_cdc_ecm_link_state = UX_HOST_CLASS_CDC_ECM_LINK_STATE_DOWN; - } + if (status == UX_SUCCESS) + { - if (status == UX_SUCCESS) + /* Mark the cdc_ecm data instance as live now. */ + cdc_ecm -> ux_host_class_cdc_ecm_state = UX_HOST_CLASS_INSTANCE_LIVE; + + /* This instance of the device must also be stored in the interface container. */ + interface_ptr -> ux_interface_class_instance = (VOID *) cdc_ecm; + + /* Create this class instance. */ + _ux_host_stack_class_instance_create(cdc_ecm -> ux_host_class_cdc_ecm_class, (VOID *) cdc_ecm); + + /* Start the interrupt pipe now if it exists. */ + if (cdc_ecm -> ux_host_class_cdc_ecm_interrupt_endpoint != UX_NULL) { - /* Register this interface to the NetX USB interface broker. */ - status = _ux_network_driver_activate((VOID *) cdc_ecm, _ux_host_class_cdc_ecm_write, - &cdc_ecm -> ux_host_class_cdc_ecm_network_handle, - physical_address_msw, physical_address_lsw); + /* Obtain the transfer request from the interrupt endpoint. */ + transfer_request = &cdc_ecm -> ux_host_class_cdc_ecm_interrupt_endpoint -> ux_endpoint_transfer_request; + status = _ux_host_stack_transfer_request(transfer_request); } if (status == UX_SUCCESS) { - /* Mark the cdc_ecm data instance as live now. */ - cdc_ecm -> ux_host_class_cdc_ecm_state = UX_HOST_CLASS_INSTANCE_LIVE; + /* Activation is complete. */ - /* This instance of the device must also be stored in the interface container. */ - interface_ptr -> ux_interface_class_instance = (VOID *) cdc_ecm; + /* Now we can start the CDC-ECM thread. */ + _ux_utility_thread_resume(&cdc_ecm -> ux_host_class_cdc_ecm_thread); - /* Create this class instance. */ - _ux_host_stack_class_instance_create(cdc_ecm -> ux_host_class_cdc_ecm_class, (VOID *) cdc_ecm); - - /* Start the interrupt pipe now if it exists. */ - if (cdc_ecm -> ux_host_class_cdc_ecm_interrupt_endpoint != UX_NULL) + /* We need to inform the application if a function has been programmed + in the system structure. */ + if (_ux_system_host -> ux_system_host_change_function != UX_NULL) { - - /* Obtain the transfer request from the interrupt endpoint. */ - transfer_request = &cdc_ecm -> ux_host_class_cdc_ecm_interrupt_endpoint -> ux_endpoint_transfer_request; - status = _ux_host_stack_transfer_request(transfer_request); + + /* Call system change function. Note that the application should + wait until the link state is up until using this instance. The + link state is changed to up by the CDC-ECM thread, which isn't + started until after the data interface has been processed. */ + _ux_system_host -> ux_system_host_change_function(UX_DEVICE_INSERTION, cdc_ecm -> ux_host_class_cdc_ecm_class, (VOID *) cdc_ecm); } + + /* If trace is enabled, insert this event into the trace buffer. */ + UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_CDC_ECM_ACTIVATE, cdc_ecm, 0, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0) - if (status == UX_SUCCESS) - { - - /* Activation is complete. */ - - /* Now we can start the CDC-ECM thread. */ - _ux_utility_thread_resume(&cdc_ecm -> ux_host_class_cdc_ecm_thread); - - /* We need to inform the application if a function has been programmed - in the system structure. */ - if (_ux_system_host -> ux_system_host_change_function != UX_NULL) - { - - /* Call system change function. Note that the application should - wait until the link state is up until using this instance. The - link state is changed to up by the CDC-ECM thread, which isn't - started until after the data interface has been processed. */ - _ux_system_host -> ux_system_host_change_function(UX_DEVICE_INSERTION, cdc_ecm -> ux_host_class_cdc_ecm_class, (VOID *) cdc_ecm); - } - - /* If trace is enabled, insert this event into the trace buffer. */ - UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_CDC_ECM_ACTIVATE, cdc_ecm, 0, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0) - - /* If trace is enabled, register this object. */ - UX_TRACE_OBJECT_REGISTER(UX_TRACE_HOST_OBJECT_TYPE_INTERFACE, cdc_ecm, 0, 0, 0) - - /* Activation was successful. */ - return(UX_SUCCESS); - } + /* If trace is enabled, register this object. */ + UX_TRACE_OBJECT_REGISTER(UX_TRACE_HOST_OBJECT_TYPE_INTERFACE, cdc_ecm, 0, 0, 0) - /* Error starting interrupt endpoint. */ + /* Activation was successful. */ + return(UX_SUCCESS); + } - /* Destroy this class instance. */ - _ux_host_stack_class_instance_destroy(cdc_ecm -> ux_host_class_cdc_ecm_class, (VOID *) cdc_ecm); + /* Error starting interrupt endpoint. */ - /* Unmount instance. */ - interface_ptr -> ux_interface_class_instance = UX_NULL; - } + /* Destroy this class instance. */ + _ux_host_stack_class_instance_destroy(cdc_ecm -> ux_host_class_cdc_ecm_class, (VOID *) cdc_ecm); - /* Delete CDC-ECM thread. */ - _ux_utility_thread_delete(&cdc_ecm -> ux_host_class_cdc_ecm_thread); + /* Unmount instance. */ + interface_ptr -> ux_interface_class_instance = UX_NULL; } -#ifndef UX_HOST_CLASS_CDC_ECM_USE_PACKET_POOL_FROM_NETX - /* Delete packet pool. */ - nx_packet_pool_delete(&cdc_ecm -> ux_host_class_cdc_ecm_packet_pool); - } - else - { - /* Packet pool creation failed. Notify application. */ - _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ENUMERATOR, status); + /* Delete CDC-ECM thread. */ + _ux_utility_thread_delete(&cdc_ecm -> ux_host_class_cdc_ecm_thread); } -#endif + /* Delete interrupt notification semaphore. */ _ux_host_semaphore_delete(&cdc_ecm -> ux_host_class_cdc_ecm_interrupt_notification_semaphore); } @@ -378,10 +354,7 @@ UX_INTERFACE *cur_interface; if (cdc_ecm -> ux_host_class_cdc_ecm_interrupt_endpoint != UX_NULL && cdc_ecm -> ux_host_class_cdc_ecm_interrupt_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_data_pointer != UX_NULL) _ux_utility_memory_free(cdc_ecm -> ux_host_class_cdc_ecm_interrupt_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_data_pointer); -#ifndef UX_HOST_CLASS_CDC_ECM_USE_PACKET_POOL_FROM_NETX - if (cdc_ecm -> ux_host_class_cdc_ecm_pool_memory != UX_NULL) - _ux_utility_memory_free(cdc_ecm -> ux_host_class_cdc_ecm_pool_memory); -#endif + if (cdc_ecm -> ux_host_class_cdc_ecm_thread_stack != UX_NULL) _ux_utility_memory_free(cdc_ecm -> ux_host_class_cdc_ecm_thread_stack); diff --git a/common/usbx_host_classes/src/ux_host_class_cdc_ecm_deactivate.c b/common/usbx_host_classes/src/ux_host_class_cdc_ecm_deactivate.c index ec561e9e..3273259f 100644 --- a/common/usbx_host_classes/src/ux_host_class_cdc_ecm_deactivate.c +++ b/common/usbx_host_classes/src/ux_host_class_cdc_ecm_deactivate.c @@ -36,7 +36,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_host_class_cdc_ecm_deactivate PORTABLE C */ -/* 6.1.11 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -89,6 +89,10 @@ /* internal clean up, */ /* fixed standalone compile, */ /* resulting in version 6.1.11 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* deprecated ECM pool option, */ +/* supported NX packet chain, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_host_class_cdc_ecm_deactivate(UX_HOST_CLASS_COMMAND *command) @@ -191,13 +195,16 @@ UX_TRANSFER *transfer_request; /* Destroy the notification semaphore. */ _ux_host_semaphore_delete(&cdc_ecm -> ux_host_class_cdc_ecm_interrupt_notification_semaphore); -#ifndef UX_HOST_CLASS_CDC_ECM_USE_PACKET_POOL_FROM_NETX - /* Delete the packet pool. */ - nx_packet_pool_delete(&cdc_ecm -> ux_host_class_cdc_ecm_packet_pool); - /* Free this pool of packets. */ - _ux_utility_memory_free(cdc_ecm -> ux_host_class_cdc_ecm_pool_memory); +#ifdef UX_HOST_CLASS_CDC_ECM_PACKET_CHAIN_SUPPORT + + /* Free packet transmission memories. */ + if (cdc_ecm -> ux_host_class_cdc_ecm_receive_buffer) + _ux_utility_memory_free(cdc_ecm -> ux_host_class_cdc_ecm_receive_buffer); + if (cdc_ecm -> ux_host_class_cdc_ecm_xmit_buffer) + _ux_utility_memory_free(cdc_ecm -> ux_host_class_cdc_ecm_xmit_buffer); #endif + /* Before we free the device resources, we need to inform the application that the device is removed. */ if (_ux_system_host -> ux_system_host_change_function != UX_NULL) diff --git a/common/usbx_host_classes/src/ux_host_class_cdc_ecm_mac_address_get.c b/common/usbx_host_classes/src/ux_host_class_cdc_ecm_mac_address_get.c index 6a65d57d..ea9f968d 100644 --- a/common/usbx_host_classes/src/ux_host_class_cdc_ecm_mac_address_get.c +++ b/common/usbx_host_classes/src/ux_host_class_cdc_ecm_mac_address_get.c @@ -35,7 +35,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_host_class_cdc_ecm_mac_address_get PORTABLE C */ -/* 6.1.12 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -74,6 +74,9 @@ /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */ /* checked MAC string length, */ /* resulting in version 6.1.12 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* checked descriptor length, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_host_class_cdc_ecm_mac_address_get(UX_HOST_CLASS_CDC_ECM *cdc_ecm) @@ -168,6 +171,20 @@ UCHAR element_hexa_lower; descriptor_length = *descriptor; descriptor_type = *(descriptor + 1); descriptor_subtype = *(descriptor + 2); + + /* Descriptor length validation. */ + if (descriptor_length < 3 || descriptor_length > total_configuration_length) + { + + /* Error trap. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED); + + /* Free descriptor memory. */ + _ux_utility_memory_free(start_descriptor); + + /* Return error. */ + return(UX_DESCRIPTOR_CORRUPTED); + } /* Check the type for an interface descriptor and the subtype for a ECM functional descriptor. */ if ((descriptor_type == UX_HOST_CLASS_CDC_ECM_CS_INTERFACE) && (descriptor_subtype == UX_HOST_CLASS_CDC_ECM_FUNCTIONAL_DESCRIPTOR)) diff --git a/common/usbx_host_classes/src/ux_host_class_cdc_ecm_thread.c b/common/usbx_host_classes/src/ux_host_class_cdc_ecm_thread.c index 24a36e86..fbed5829 100644 --- a/common/usbx_host_classes/src/ux_host_class_cdc_ecm_thread.c +++ b/common/usbx_host_classes/src/ux_host_class_cdc_ecm_thread.c @@ -36,7 +36,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_host_class_cdc_ecm_thread PORTABLE C */ -/* 6.1.11 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -94,6 +94,11 @@ /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */ /* fixed standalone compile, */ /* resulting in version 6.1.11 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* no length from IP header, */ +/* deprecated ECM pool option, */ +/* supported NX packet chain, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ VOID _ux_host_class_cdc_ecm_thread(ULONG parameter) @@ -102,11 +107,10 @@ VOID _ux_host_class_cdc_ecm_thread(ULONG parameter) UX_HOST_CLASS_CDC_ECM *cdc_ecm; UX_TRANSFER *transfer_request; NX_PACKET *packet; -ULONG ip_given_length; UINT status; -#ifdef UX_HOST_CLASS_CDC_ECM_USE_PACKET_POOL_FROM_NETX USB_NETWORK_DEVICE_TYPE *usb_network_device_ptr; -#endif +ULONG packet_buffer_size; + /* Cast the parameter passed in the thread into the cdc_ecm pointer. */ UX_THREAD_EXTENSION_PTR_GET(cdc_ecm, UX_HOST_CLASS_CDC_ECM, parameter) @@ -132,7 +136,6 @@ USB_NETWORK_DEVICE_TYPE *usb_network_device_ptr; while ((cdc_ecm -> ux_host_class_cdc_ecm_link_state == UX_HOST_CLASS_CDC_ECM_LINK_STATE_UP) && (cdc_ecm -> ux_host_class_cdc_ecm_device -> ux_device_state == UX_DEVICE_CONFIGURED)) { -#ifdef UX_HOST_CLASS_CDC_ECM_USE_PACKET_POOL_FROM_NETX /* Check if we have packet pool available. */ if (cdc_ecm -> ux_host_class_cdc_ecm_packet_pool == UX_NULL) @@ -152,7 +155,7 @@ USB_NETWORK_DEVICE_TYPE *usb_network_device_ptr; { /* IP instance is not available, wait for application to attach the interface. */ - _ux_utility_delay_ms(UX_HOST_CLASS_CDC_ECM_PACKET_POOL_INSTANCE_WAIT); + _ux_utility_delay_ms(UX_MS_TO_TICK(UX_HOST_CLASS_CDC_ECM_PACKET_POOL_INSTANCE_WAIT)); } continue; } @@ -160,13 +163,7 @@ USB_NETWORK_DEVICE_TYPE *usb_network_device_ptr; /* We can accept reception. Get a NX Packet. */ status = nx_packet_allocate(cdc_ecm -> ux_host_class_cdc_ecm_packet_pool, &packet, NX_RECEIVE_PACKET, UX_MS_TO_TICK(UX_HOST_CLASS_CDC_ECM_PACKET_POOL_WAIT)); -#else - - /* We can accept reception. Get a NX Packet. */ - status = nx_packet_allocate(&cdc_ecm -> ux_host_class_cdc_ecm_packet_pool, &packet, - NX_RECEIVE_PACKET, UX_MS_TO_TICK(UX_HOST_CLASS_CDC_ECM_PACKET_POOL_WAIT)); -#endif if (status == NX_SUCCESS) { @@ -175,10 +172,46 @@ USB_NETWORK_DEVICE_TYPE *usb_network_device_ptr; /* We have a packet. Link this packet to the reception transfer request on the bulk in endpoint. */ transfer_request = &cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_endpoint -> ux_endpoint_transfer_request; - - /* Set the data pointer. */ - transfer_request -> ux_transfer_request_data_pointer = packet -> nx_packet_prepend_ptr; - + +#ifdef UX_HOST_CLASS_CDC_ECM_PACKET_CHAIN_SUPPORT + + /* Check packet buffer size, if too small chain is used. */ + packet_buffer_size = (ULONG)(packet -> nx_packet_data_end - packet -> nx_packet_prepend_ptr); + if (packet_buffer_size < UX_HOST_CLASS_CDC_ECM_NX_PAYLOAD_SIZE) + { + if (cdc_ecm -> ux_host_class_cdc_ecm_receive_buffer == UX_NULL) + { + cdc_ecm -> ux_host_class_cdc_ecm_receive_buffer = + _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, + UX_HOST_CLASS_CDC_ECM_NX_PAYLOAD_SIZE); + if (cdc_ecm -> ux_host_class_cdc_ecm_receive_buffer == UX_NULL) + { + + /* Memory allocation fail. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_MEMORY_INSUFFICIENT); + + /* Release packet. */ + nx_packet_release(packet); + + /* Delay to let other threads to run. */ + _ux_utility_delay_ms(1); + continue; + } + + } + + /* Set the data pointer. */ + transfer_request -> ux_transfer_request_data_pointer = cdc_ecm -> ux_host_class_cdc_ecm_receive_buffer; + } + else +#endif + { + + /* Set the data pointer. */ + transfer_request -> ux_transfer_request_data_pointer = packet -> nx_packet_prepend_ptr; + + } + /* And length. */ transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_CDC_ECM_NX_PAYLOAD_SIZE; transfer_request -> ux_transfer_request_actual_length = 0; @@ -216,21 +249,43 @@ USB_NETWORK_DEVICE_TYPE *usb_network_device_ptr; if (transfer_request -> ux_transfer_request_completion_code == UX_SUCCESS) { - /* Get the packet length. */ - packet -> nx_packet_length = transfer_request -> ux_transfer_request_actual_length; - - /* Adjust the prepend, length, and append fields. */ - packet -> nx_packet_append_ptr = - packet->nx_packet_prepend_ptr + transfer_request -> ux_transfer_request_actual_length; - - /* Calculate the accurate packet length from ip header */ - if ((*(packet -> nx_packet_prepend_ptr + 12) == 0x08) && - (*(packet -> nx_packet_prepend_ptr + 13) == 0)) +#ifdef UX_HOST_CLASS_CDC_ECM_PACKET_CHAIN_SUPPORT + + /* Check if transfer buffer is used. */ + if (packet -> nx_packet_prepend_ptr != + transfer_request -> ux_transfer_request_data_pointer) + { + + /* Adjust append_ptr for copy. */ + packet -> nx_packet_append_ptr = packet -> nx_packet_prepend_ptr; + + /* Append data to packet. */ + status = nx_packet_data_append(packet, + transfer_request -> ux_transfer_request_data_pointer, + transfer_request -> ux_transfer_request_actual_length, + cdc_ecm -> ux_host_class_cdc_ecm_packet_pool, + UX_MS_TO_TICK(UX_HOST_CLASS_CDC_ECM_PACKET_POOL_WAIT)); + if (status != NX_SUCCESS) + { + + /* Release packet. */ + nx_packet_release(packet); + + /* Error trap. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CLASS_ETH_PACKET_ERROR); + continue; + } + } + else +#endif { - ip_given_length = _ux_utility_short_get_big_endian(packet -> nx_packet_prepend_ptr + 16) + UX_HOST_CLASS_CDC_ECM_ETHERNET_SIZE; - packet->nx_packet_length = ip_given_length ; - packet->nx_packet_append_ptr = packet->nx_packet_prepend_ptr + ip_given_length; + /* Get the packet length. */ + packet -> nx_packet_length = transfer_request -> ux_transfer_request_actual_length; + + /* Adjust the prepend, length, and append fields. */ + packet -> nx_packet_append_ptr = + packet->nx_packet_prepend_ptr + transfer_request -> ux_transfer_request_actual_length; } /* Send that packet to the NetX USB broker. */ diff --git a/common/usbx_host_classes/src/ux_host_class_cdc_ecm_transmission_callback.c b/common/usbx_host_classes/src/ux_host_class_cdc_ecm_transmission_callback.c index 506097e8..157f95d1 100644 --- a/common/usbx_host_classes/src/ux_host_class_cdc_ecm_transmission_callback.c +++ b/common/usbx_host_classes/src/ux_host_class_cdc_ecm_transmission_callback.c @@ -35,7 +35,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_host_class_cdc_ecm_transmission_callback PORTABLE C */ -/* 6.1.11 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -80,6 +80,9 @@ /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */ /* fixed standalone compile, */ /* resulting in version 6.1.11 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* supported NX packet chain, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ VOID _ux_host_class_cdc_ecm_transmission_callback(UX_TRANSFER *transfer_request) @@ -92,6 +95,9 @@ UX_HOST_CLASS_CDC_ECM *cdc_ecm; NX_PACKET *current_packet; NX_PACKET *next_packet; UCHAR *packet_header; +#ifdef UX_HOST_CLASS_CDC_ECM_PACKET_CHAIN_SUPPORT +ULONG copied; +#endif /* Get the data and control class instances for this transfer request. */ cdc_ecm = (UX_HOST_CLASS_CDC_ECM *) transfer_request -> ux_transfer_request_class_instance; @@ -150,8 +156,22 @@ UCHAR *packet_header; if (next_packet != UX_NULL) { - /* Load the address of the current packet header at the physical header. */ - packet_header = next_packet -> nx_packet_prepend_ptr; +#ifdef UX_HOST_CLASS_CDC_ECM_PACKET_CHAIN_SUPPORT + + if (next_packet -> nx_packet_next != UX_NULL) + { + + /* Put packet to continuous buffer to transfer. */ + packet_header = cdc_ecm -> ux_host_class_cdc_ecm_xmit_buffer; + nx_packet_data_extract_offset(next_packet, 0, packet_header, next_packet -> nx_packet_length, &copied); + } + else +#endif + { + + /* Load the address of the current packet header at the physical header. */ + packet_header = next_packet -> nx_packet_prepend_ptr; + } /* Prepare the values for this new transmission. */ transfer_request -> ux_transfer_request_data_pointer = packet_header; diff --git a/common/usbx_host_classes/src/ux_host_class_cdc_ecm_write.c b/common/usbx_host_classes/src/ux_host_class_cdc_ecm_write.c index f88878e3..76667e10 100644 --- a/common/usbx_host_classes/src/ux_host_class_cdc_ecm_write.c +++ b/common/usbx_host_classes/src/ux_host_class_cdc_ecm_write.c @@ -36,7 +36,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_host_class_cdc_ecm_write PORTABLE C */ -/* 6.1.11 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -81,6 +81,9 @@ /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */ /* fixed standalone compile, */ /* resulting in version 6.1.11 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* supported NX packet chain, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_host_class_cdc_ecm_write(VOID *cdc_ecm_class, NX_PACKET *packet) @@ -92,6 +95,9 @@ UX_TRANSFER *transfer_request; UINT status; UCHAR *packet_header; UX_HOST_CLASS_CDC_ECM *cdc_ecm; +#ifdef UX_HOST_CLASS_CDC_ECM_PACKET_CHAIN_SUPPORT +ULONG copied; +#endif /* Get the instance. */ cdc_ecm = (UX_HOST_CLASS_CDC_ECM *) cdc_ecm_class; @@ -124,6 +130,22 @@ UX_HOST_CLASS_CDC_ECM *cdc_ecm; return(UX_HOST_CLASS_INSTANCE_UNKNOWN); } + /* Validate packet length. */ + if (packet -> nx_packet_length > UX_HOST_CLASS_CDC_ECM_NX_PAYLOAD_SIZE) + { + + /* Restore interrupts. */ + UX_RESTORE + + /* Error trap. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CLASS_ETH_SIZE_ERROR); + + /* If trace is enabled, insert this event into the trace buffer. */ + UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_CLASS_ETH_SIZE_ERROR, cdc_ecm, packet -> nx_packet_length, 0, UX_TRACE_ERRORS, 0, 0) + + return(UX_CLASS_ETH_SIZE_ERROR); + } + /* Are we in a valid state? */ if (cdc_ecm -> ux_host_class_cdc_ecm_link_state == UX_HOST_CLASS_CDC_ECM_LINK_STATE_UP) { @@ -147,8 +169,35 @@ UX_HOST_CLASS_CDC_ECM *cdc_ecm; /* Get the pointer to the bulk out endpoint transfer request. */ transfer_request = &cdc_ecm -> ux_host_class_cdc_ecm_bulk_out_endpoint -> ux_endpoint_transfer_request; - /* Load the address of the current packet header at the physical header. */ - packet_header = packet -> nx_packet_prepend_ptr; +#ifdef UX_HOST_CLASS_CDC_ECM_PACKET_CHAIN_SUPPORT + + if (packet -> nx_packet_next != UX_NULL) + { + + /* Create buffer. */ + if (cdc_ecm -> ux_host_class_cdc_ecm_xmit_buffer == UX_NULL) + { + cdc_ecm -> ux_host_class_cdc_ecm_xmit_buffer = _ux_utility_memory_allocate(UX_NO_ALIGN, + UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_CDC_ECM_NX_PAYLOAD_SIZE); + if (cdc_ecm -> ux_host_class_cdc_ecm_xmit_buffer == UX_NULL) + { + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_MEMORY_INSUFFICIENT); + return(UX_MEMORY_INSUFFICIENT); + } + } + + /* Put packet to continuous buffer to transfer. */ + packet_header = cdc_ecm -> ux_host_class_cdc_ecm_xmit_buffer; + nx_packet_data_extract_offset(packet, 0, packet_header, packet -> nx_packet_length, &copied); + } + else +#endif + { + + /* Load the address of the current packet header at the physical header. */ + packet_header = packet -> nx_packet_prepend_ptr; + + } /* Setup the transaction parameters. */ transfer_request -> ux_transfer_request_data_pointer = packet_header; diff --git a/common/usbx_host_classes/src/ux_host_class_hid_keyboard_tasks_run.c b/common/usbx_host_classes/src/ux_host_class_hid_keyboard_tasks_run.c index 37aa1e7f..3fdd9d16 100644 --- a/common/usbx_host_classes/src/ux_host_class_hid_keyboard_tasks_run.c +++ b/common/usbx_host_classes/src/ux_host_class_hid_keyboard_tasks_run.c @@ -37,7 +37,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_host_class_hid_keyboard_tasks_run PORTABLE C */ -/* 6.1.10 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -71,6 +71,10 @@ /* DATE NAME DESCRIPTION */ /* */ /* 01-31-2022 Chaoqiong Xiao Initial Version 6.1.10 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* improved HID OUTPUT report */ +/* handling in standalone mode,*/ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ VOID _ux_host_class_hid_keyboard_tasks_run(UX_HOST_CLASS_HID_CLIENT *client) @@ -108,12 +112,22 @@ UINT status; UX_HID_KEYBOARD_STATE_MASK_LOCK; /* We need to find the OUTPUT report for the keyboard LEDs. */ - report_id.ux_host_class_hid_report_get_report = UX_NULL; - report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_OUTPUT; - status = _ux_host_class_hid_report_id_get(hid, &report_id); + if (keyboard -> ux_host_class_hid_keyboard_out_report == UX_NULL) + { + + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_OUTPUT; + status = _ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + keyboard -> ux_host_class_hid_keyboard_status = status; + return; + } + keyboard -> ux_host_class_hid_keyboard_out_report = report_id.ux_host_class_hid_report_get_report; + } /* Build a RAW client report. */ - client_report.ux_host_class_hid_client_report = report_id.ux_host_class_hid_report_get_report; + client_report.ux_host_class_hid_client_report = keyboard -> ux_host_class_hid_keyboard_out_report; client_report.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_RAW; client_report.ux_host_class_hid_client_report_length = 1; client_report.ux_host_class_hid_client_report_buffer = &keyboard -> ux_host_class_hid_keyboard_led_mask; diff --git a/common/usbx_host_classes/src/ux_host_class_hub_entry.c b/common/usbx_host_classes/src/ux_host_class_hub_entry.c index abc47704..9a968d85 100644 --- a/common/usbx_host_classes/src/ux_host_class_hub_entry.c +++ b/common/usbx_host_classes/src/ux_host_class_hub_entry.c @@ -41,7 +41,7 @@ static inline UINT _ux_host_class_hub_activate_wait(UX_HOST_CLASS_COMMAND *comma /* FUNCTION RELEASE */ /* */ /* _ux_host_class_hub_entry PORTABLE C */ -/* 6.1.12 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -80,7 +80,10 @@ static inline UINT _ux_host_class_hub_activate_wait(UX_HOST_CLASS_COMMAND *comma /* resulting in version 6.1 */ /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */ /* added standalone support, */ -/* resulting in version 6.1 */ +/* resulting in version 6.1.12 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* fixed power on delay calc, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_host_class_hub_entry(UX_HOST_CLASS_COMMAND *command) @@ -356,7 +359,7 @@ ULONG current_ms, elapsed_ms; /* Delay a while (as described by hub descriptor). */ hub -> ux_host_class_hub_wait_start = _ux_utility_time_get(); - hub -> ux_host_class_hub_wait_ms = hub -> ux_host_class_hub_descriptor.bPwrOn2PwrGood; + hub -> ux_host_class_hub_wait_ms = UX_MS_TO_TICK_NON_ZERO(hub -> ux_host_class_hub_descriptor.bPwrOn2PwrGood << 1); hub -> ux_host_class_hub_enum_state = UX_HOST_CLASS_HUB_ENUM_TRANS_WAIT; hub -> ux_host_class_hub_next_state = UX_HOST_CLASS_HUB_ENUM_PORT_POWER_ON; diff --git a/common/usbx_host_classes/src/ux_host_class_hub_tasks_run.c b/common/usbx_host_classes/src/ux_host_class_hub_tasks_run.c index c0363f33..2702c39b 100644 --- a/common/usbx_host_classes/src/ux_host_class_hub_tasks_run.c +++ b/common/usbx_host_classes/src/ux_host_class_hub_tasks_run.c @@ -40,7 +40,7 @@ static inline VOID _ux_host_class_hub_inst_tasks_run(UX_HOST_CLASS_HUB *hub); /* FUNCTION RELEASE */ /* */ /* _ux_host_class_hub_tasks_run PORTABLE C */ -/* 6.1.12 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -87,6 +87,9 @@ static inline VOID _ux_host_class_hub_inst_tasks_run(UX_HOST_CLASS_HUB *hub); /* DATE NAME DESCRIPTION */ /* */ /* 07-29-2022 Chaoqiong Xiao Initial Version 6.1.12 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* fixed reset speed handling, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_host_class_hub_tasks_run(UX_HOST_CLASS *hub_class) @@ -209,9 +212,11 @@ USHORT port_change = hub -> ux_host_class_hub_run_port_change; } static inline VOID _ux_host_class_hub_inst_tasks_run(UX_HOST_CLASS_HUB *hub) { +UX_HCD *hcd; UX_DEVICE *device; UX_DEVICE *hub_device = hub -> ux_host_class_hub_device; UX_ENDPOINT *ep0 = &hub_device -> ux_device_control_endpoint; +UX_ENDPOINT *dev_ep0; UX_TRANSFER *trans0 = &ep0 -> ux_endpoint_transfer_request; UINT status; @@ -385,16 +390,41 @@ UINT status; /* Save status and speed. */ device -> ux_device_enum_port_status = (UCHAR)hub -> ux_host_class_hub_run_port_status; + /* Append speed information. */ + switch(hub -> ux_host_class_hub_run_port_status & + (UX_HOST_CLASS_HUB_PORT_STATUS_LOW_SPEED | UX_HOST_CLASS_HUB_PORT_STATUS_HIGH_SPEED)) + { + case 0: /* It's Full speed. */ + device -> ux_device_enum_port_status |= UX_PS_DS_FS; + device -> ux_device_speed = UX_FULL_SPEED_DEVICE; + break; + + case UX_HOST_CLASS_HUB_PORT_STATUS_HIGH_SPEED: /* It's high speed. */ + device -> ux_device_enum_port_status |= UX_PS_DS_HS; + device -> ux_device_speed = UX_HIGH_SPEED_DEVICE; + break; + + default: /* It's Low speed. */ + device -> ux_device_speed = UX_LOW_SPEED_DEVICE; + break; + } + /* Return device address to 0. */ + hcd = UX_DEVICE_HCD_GET(device); if (device -> ux_device_address) { /* Free the address. */ - UX_DEVICE_HCD_GET(device) -> - ux_hcd_address[(device -> ux_device_address-1) >> 3] &= + hcd -> ux_hcd_address[(device -> ux_device_address-1) >> 3] &= (UCHAR)(1u << ((device -> ux_device_address-1) & 7u)); + } + /* Assume speed change, re-create EP0 at the HCD level. */ + dev_ep0 = &device -> ux_device_control_endpoint; + hcd -> ux_hcd_entry_function(hcd, UX_HCD_DESTROY_ENDPOINT, (VOID *)dev_ep0); + hcd -> ux_hcd_entry_function(hcd, UX_HCD_CREATE_ENDPOINT, (VOID *)dev_ep0); + /* Wait a while and set address. */ device -> ux_device_enum_next_state = UX_HOST_STACK_ENUM_DEVICE_ADDR_SET; device -> ux_device_enum_state = UX_HOST_STACK_ENUM_WAIT; diff --git a/common/usbx_host_classes/src/ux_host_class_storage_entry.c b/common/usbx_host_classes/src/ux_host_class_storage_entry.c old mode 100755 new mode 100644 diff --git a/common/usbx_host_classes/src/ux_host_class_storage_media_open.c b/common/usbx_host_classes/src/ux_host_class_storage_media_open.c index 3da94807..71243767 100644 --- a/common/usbx_host_classes/src/ux_host_class_storage_media_open.c +++ b/common/usbx_host_classes/src/ux_host_class_storage_media_open.c @@ -35,7 +35,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_host_class_storage_media_open PORTABLE C */ -/* 6.1 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -81,6 +81,9 @@ /* class specific structured */ /* data, */ /* resulting in version 6.1 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* added buffer size check, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_host_class_storage_media_open(UX_HOST_CLASS_STORAGE *storage, ULONG hidden_sectors) @@ -127,6 +130,16 @@ UX_HOST_CLASS *class_inst; /* Save the Sector size in the storage media instance. */ storage_media -> ux_host_class_storage_media_sector_size = storage -> ux_host_class_storage_sector_size; + /* Check if media setting can support the sector size. */ + if (storage -> ux_host_class_storage_sector_size > UX_HOST_CLASS_STORAGE_MEMORY_BUFFER_SIZE) + { + /* Error trap. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_MEMORY_ERROR); + + /* Required memory is over system setting. */ + return(UX_HOST_CLASS_MEMORY_ERROR); + } + /* Save the storage media instance in the user reserved area in the UX_MEDIA structure. */ ux_media_reserved_for_user_set(media, storage_media); diff --git a/common/usbx_host_classes/src/ux_host_class_storage_partition_read.c b/common/usbx_host_classes/src/ux_host_class_storage_partition_read.c old mode 100755 new mode 100644 diff --git a/common/usbx_host_classes/src/ux_host_class_storage_tasks_run.c b/common/usbx_host_classes/src/ux_host_class_storage_tasks_run.c index 80fe330f..ca0c6bff 100644 --- a/common/usbx_host_classes/src/ux_host_class_storage_tasks_run.c +++ b/common/usbx_host_classes/src/ux_host_class_storage_tasks_run.c @@ -53,7 +53,7 @@ static inline UINT _ux_host_class_storage_transport_sense_check(UX_HOST_CLASS_ST /* FUNCTION RELEASE */ /* */ /* _ux_host_class_storage_tasks_run PORTABLE C */ -/* 6.1.12 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -99,6 +99,9 @@ static inline UINT _ux_host_class_storage_transport_sense_check(UX_HOST_CLASS_ST /* fixed parameter/variable */ /* names conflict C++ keyword, */ /* resulting in version 6.1.12 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* improved internal logic, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_host_class_storage_tasks_run(UX_HOST_CLASS *storage_class) @@ -132,6 +135,7 @@ ULONG tick_now, tick_elapsed; UINT status; UX_TRANSFER *trans; UX_INTERFACE *interface_ptr; +INT immediate_state; /* If storage not live, start initialize. */ if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_MOUNTING) @@ -187,7 +191,8 @@ UX_INTERFACE *interface_ptr; } /* Handle main states. */ - while(1) + immediate_state = UX_TRUE; + while(immediate_state) { /* Get current state. */ @@ -498,11 +503,15 @@ UX_INTERFACE *interface_ptr; } UX_RESTORE - case UX_STATE_RESET: + /* Fall through. */ + + case UX_STATE_RESET: /* Fall through. */ default: break; } - break; + + /* Break the loop. */ + immediate_state = UX_FALSE; } } @@ -730,30 +739,31 @@ INT media_index; { /* Skip used storage media slots. */ - if (storage_media -> ux_host_class_storage_media_status == UX_USED) - continue; + if (storage_media -> ux_host_class_storage_media_status != UX_USED) + { - /* Use this free storage media slot. */ - storage_media -> ux_host_class_storage_media_status = UX_USED; - storage_media -> ux_host_class_storage_media_storage = storage; + /* Use this free storage media slot. */ + storage_media -> ux_host_class_storage_media_status = UX_USED; + storage_media -> ux_host_class_storage_media_storage = storage; - /* Save media information. */ - storage_media -> ux_host_class_storage_media_lun = (UCHAR)storage -> ux_host_class_storage_lun; - storage_media -> ux_host_class_storage_media_sector_size = (USHORT)storage -> ux_host_class_storage_sector_size; - storage_media -> ux_host_class_storage_media_number_sectors = storage -> ux_host_class_storage_last_sector_number + 1; + /* Save media information. */ + storage_media -> ux_host_class_storage_media_lun = (UCHAR)storage -> ux_host_class_storage_lun; + storage_media -> ux_host_class_storage_media_sector_size = (USHORT)storage -> ux_host_class_storage_sector_size; + storage_media -> ux_host_class_storage_media_number_sectors = storage -> ux_host_class_storage_last_sector_number + 1; - /* Invoke callback for media insertion. */ - if (_ux_system_host -> ux_system_host_change_function != UX_NULL) - { + /* Invoke callback for media insertion. */ + if (_ux_system_host -> ux_system_host_change_function != UX_NULL) + { - /* Call system change function. */ - /* In standalone mode, no state running (read/write) expected in callback. */ - _ux_system_host -> ux_system_host_change_function(UX_STORAGE_MEDIA_INSERTION, - storage -> ux_host_class_storage_class, (VOID *) storage_media); - } + /* Call system change function. */ + /* In standalone mode, no state running (read/write) expected in callback. */ + _ux_system_host -> ux_system_host_change_function(UX_STORAGE_MEDIA_INSERTION, + storage -> ux_host_class_storage_class, (VOID *) storage_media); + } - /* Media saved OK. */ - return; + /* Media saved OK. */ + return; + } } /* No free slot. */ diff --git a/common/usbx_host_classes/src/ux_host_class_storage_transport_run.c b/common/usbx_host_classes/src/ux_host_class_storage_transport_run.c index 26a09ee8..90cd2b91 100644 --- a/common/usbx_host_classes/src/ux_host_class_storage_transport_run.c +++ b/common/usbx_host_classes/src/ux_host_class_storage_transport_run.c @@ -63,7 +63,7 @@ static inline VOID _ux_host_class_storage_transport_ep_reset(UX_HOST_CLASS_STORA /* FUNCTION RELEASE */ /* */ /* _ux_host_class_storage_transport_run PORTABLE C */ -/* 6.1.12 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -101,13 +101,18 @@ static inline VOID _ux_host_class_storage_transport_ep_reset(UX_HOST_CLASS_STORA /* fixed parameter/variable */ /* names conflict C++ keyword, */ /* resulting in version 6.1.12 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* improved internal logic, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_host_class_storage_transport_run(UX_HOST_CLASS_STORAGE *storage) { UINT status; UCHAR state; - while(1) +INT immediate_state = UX_TRUE; + + while(immediate_state) { state = storage -> ux_host_class_storage_trans_state; switch(state) @@ -192,7 +197,9 @@ UCHAR state; default: break; } - break; + + /* Invalid unhandled state, break the loop. */ + immediate_state = UX_FALSE; } /* Unexpected state, fatal error. */ diff --git a/common/usbx_host_classes/src/ux_host_class_video_activate.c b/common/usbx_host_classes/src/ux_host_class_video_activate.c index 66e5aff8..66343245 100644 --- a/common/usbx_host_classes/src/ux_host_class_video_activate.c +++ b/common/usbx_host_classes/src/ux_host_class_video_activate.c @@ -87,6 +87,13 @@ UCHAR *baInterfaceNr; /* Check if this the VC interface is expected. */ bInCollection = packed_entity_descriptor[11]; baInterfaceNr = packed_entity_descriptor + 12; + + /* Validation: + * baInterfaceNr not exceeding current descriptor. + */ + if (packed_entity_descriptor[0] + packed_entity_descriptor < baInterfaceNr + bInCollection) + return(1); + while(bInCollection) { @@ -97,6 +104,10 @@ UCHAR *baInterfaceNr; parser -> parsed_flags |= UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER_VC_HEADER; return(0); } + + /* Next interface number in descriptor. */ + baInterfaceNr ++; + bInCollection --; } } @@ -159,7 +170,7 @@ UCHAR *baInterfaceNr; /* FUNCTION RELEASE */ /* */ /* _ux_host_class_video_activate PORTABLE C */ -/* 6.1.12 */ +/* 6.2.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -217,6 +228,9 @@ UCHAR *baInterfaceNr; /* fixed parameter/variable */ /* names conflict C++ keyword, */ /* resulting in version 6.1.12 */ +/* 10-31-2022 Chaoqiong Xiao Modified comment(s), */ +/* improved VC header check, */ +/* resulting in version 6.2.0 */ /* */ /**************************************************************************/ UINT _ux_host_class_video_activate(UX_HOST_CLASS_COMMAND *command) diff --git a/common/usbx_host_classes/src/ux_host_class_video_frame_interval_get.c b/common/usbx_host_classes/src/ux_host_class_video_frame_interval_get.c old mode 100755 new mode 100644 diff --git a/common/usbx_host_controllers/inc/ux_hcd_ehci.h b/common/usbx_host_controllers/inc/ux_hcd_ehci.h old mode 100755 new mode 100644 diff --git a/common/usbx_host_controllers/inc/ux_hcd_ohci.h b/common/usbx_host_controllers/inc/ux_hcd_ohci.h old mode 100755 new mode 100644 diff --git a/common/usbx_host_controllers/src/ux_hcd_ehci_asynchronous_endpoint_create.c b/common/usbx_host_controllers/src/ux_hcd_ehci_asynchronous_endpoint_create.c old mode 100755 new mode 100644 diff --git a/common/usbx_host_controllers/src/ux_hcd_ehci_done_queue_process.c b/common/usbx_host_controllers/src/ux_hcd_ehci_done_queue_process.c old mode 100755 new mode 100644 diff --git a/common/usbx_host_controllers/src/ux_hcd_ehci_hsisochronous_tds_process.c b/common/usbx_host_controllers/src/ux_hcd_ehci_hsisochronous_tds_process.c old mode 100755 new mode 100644 diff --git a/common/usbx_host_controllers/src/ux_hcd_ehci_interrupt_endpoint_create.c b/common/usbx_host_controllers/src/ux_hcd_ehci_interrupt_endpoint_create.c old mode 100755 new mode 100644 diff --git a/common/usbx_host_controllers/src/ux_hcd_ehci_interrupt_endpoint_destroy.c b/common/usbx_host_controllers/src/ux_hcd_ehci_interrupt_endpoint_destroy.c old mode 100755 new mode 100644 diff --git a/common/usbx_host_controllers/src/ux_hcd_ehci_isochronous_endpoint_create.c b/common/usbx_host_controllers/src/ux_hcd_ehci_isochronous_endpoint_create.c old mode 100755 new mode 100644 diff --git a/common/usbx_host_controllers/src/ux_hcd_ehci_isochronous_endpoint_destroy.c b/common/usbx_host_controllers/src/ux_hcd_ehci_isochronous_endpoint_destroy.c old mode 100755 new mode 100644 diff --git a/common/usbx_host_controllers/src/ux_hcd_ehci_least_traffic_list_get.c b/common/usbx_host_controllers/src/ux_hcd_ehci_least_traffic_list_get.c old mode 100755 new mode 100644 diff --git a/common/usbx_host_controllers/src/ux_hcd_ehci_periodic_tree_create.c b/common/usbx_host_controllers/src/ux_hcd_ehci_periodic_tree_create.c old mode 100755 new mode 100644 diff --git a/common/usbx_host_controllers/src/ux_hcd_ehci_poll_rate_entry_get.c b/common/usbx_host_controllers/src/ux_hcd_ehci_poll_rate_entry_get.c old mode 100755 new mode 100644 diff --git a/common/usbx_host_controllers/src/ux_hcd_ehci_request_control_transfer.c b/common/usbx_host_controllers/src/ux_hcd_ehci_request_control_transfer.c old mode 100755 new mode 100644 diff --git a/common/usbx_host_controllers/src/ux_hcd_ehci_transfer_abort.c b/common/usbx_host_controllers/src/ux_hcd_ehci_transfer_abort.c old mode 100755 new mode 100644 diff --git a/common/usbx_host_controllers/src/ux_hcd_ohci_endpoint_error_clear.c b/common/usbx_host_controllers/src/ux_hcd_ohci_endpoint_error_clear.c old mode 100755 new mode 100644 diff --git a/common/usbx_host_controllers/src/ux_hcd_ohci_endpoint_reset.c b/common/usbx_host_controllers/src/ux_hcd_ohci_endpoint_reset.c old mode 100755 new mode 100644 diff --git a/common/usbx_host_controllers/src/ux_hcd_ohci_periodic_endpoint_destroy.c b/common/usbx_host_controllers/src/ux_hcd_ohci_periodic_endpoint_destroy.c old mode 100755 new mode 100644 diff --git a/common/usbx_host_controllers/src/ux_hcd_ohci_port_resume.c b/common/usbx_host_controllers/src/ux_hcd_ohci_port_resume.c old mode 100755 new mode 100644 diff --git a/common/usbx_host_controllers/src/ux_hcd_ohci_port_suspend.c b/common/usbx_host_controllers/src/ux_hcd_ohci_port_suspend.c old mode 100755 new mode 100644 diff --git a/common/usbx_host_controllers/src/ux_hcd_ohci_power_down_port.c b/common/usbx_host_controllers/src/ux_hcd_ohci_power_down_port.c old mode 100755 new mode 100644 diff --git a/common/usbx_host_controllers/src/ux_hcd_ohci_power_on_port.c b/common/usbx_host_controllers/src/ux_hcd_ohci_power_on_port.c old mode 100755 new mode 100644 diff --git a/common/usbx_host_controllers/src/ux_hcd_ohci_power_root_hubs.c b/common/usbx_host_controllers/src/ux_hcd_ohci_power_root_hubs.c old mode 100755 new mode 100644 diff --git a/common/usbx_host_controllers/src/ux_hcd_ohci_request_control_transfer.c b/common/usbx_host_controllers/src/ux_hcd_ohci_request_control_transfer.c old mode 100755 new mode 100644 diff --git a/common/usbx_host_controllers/src/ux_hcd_ohci_transfer_abort.c b/common/usbx_host_controllers/src/ux_hcd_ohci_transfer_abort.c old mode 100755 new mode 100644 diff --git a/docs/usbx-features.png b/docs/usbx-features.png new file mode 100644 index 0000000000000000000000000000000000000000..de5edef8bae43a029bf40da5e228bdc28e04112d GIT binary patch literal 317752 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

E#4{Ew^U{AKnbl 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

ci@Hu%)ArHqdYM3O*>_)Az5hIO0V@Tc^wE|(u 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 literal 0 HcmV?d00001 diff --git a/ports/arm9/gnu/inc/ux_port.h b/ports/arm9/gnu/inc/ux_port.h index 28c881bc..180adbf7 100644 --- a/ports/arm9/gnu/inc/ux_port.h +++ b/ports/arm9/gnu/inc/ux_port.h @@ -239,7 +239,7 @@ VOID outpl(ULONG,ULONG); #ifdef UX_SYSTEM_INIT CHAR _ux_version_id[] = - "Copyright (c) Microsoft Corporation. All rights reserved. * USBX ARM9/GNU Version 6.1.12 *"; + "Copyright (c) Microsoft Corporation. All rights reserved. * USBX ARM9/GNU Version 6.2.0 *"; #else extern CHAR _ux_version_id[]; #endif diff --git a/ports/arm9/iar/inc/ux_port.h b/ports/arm9/iar/inc/ux_port.h index 2a5e11e6..b9fd63f3 100644 --- a/ports/arm9/iar/inc/ux_port.h +++ b/ports/arm9/iar/inc/ux_port.h @@ -246,7 +246,7 @@ VOID outpl(ULONG,ULONG); #ifdef UX_SYSTEM_INIT CHAR _ux_version_id[] = - "Copyright (c) Microsoft Corporation. All rights reserved. * USBX ARM9/IAR Version 6.1.12 *"; + "Copyright (c) Microsoft Corporation. All rights reserved. * USBX ARM9/IAR Version 6.2.0 *"; #else extern CHAR _ux_version_id[]; #endif diff --git a/ports/cortex_a15/gnu/inc/ux_port.h b/ports/cortex_a15/gnu/inc/ux_port.h index d9ea85a9..058f5095 100644 --- a/ports/cortex_a15/gnu/inc/ux_port.h +++ b/ports/cortex_a15/gnu/inc/ux_port.h @@ -235,7 +235,7 @@ VOID outpl(ULONG,ULONG); #ifdef UX_SYSTEM_INIT CHAR _ux_version_id[] = - "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-A15/GNU Version 6.1.12 *"; + "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-A15/GNU Version 6.2.0 *"; #else extern CHAR _ux_version_id[]; #endif diff --git a/ports/cortex_a5/gnu/inc/ux_port.h b/ports/cortex_a5/gnu/inc/ux_port.h index 742ad9bf..46babf40 100644 --- a/ports/cortex_a5/gnu/inc/ux_port.h +++ b/ports/cortex_a5/gnu/inc/ux_port.h @@ -242,7 +242,7 @@ VOID outpl(ULONG,ULONG); #ifdef UX_SYSTEM_INIT CHAR _ux_version_id[] = - "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-A5/GNU Version 6.1.12 *"; + "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-A5/GNU Version 6.2.0 *"; #else extern CHAR _ux_version_id[]; #endif diff --git a/ports/cortex_a5/iar/inc/ux_port.h b/ports/cortex_a5/iar/inc/ux_port.h index 54c8d5cb..d1b61185 100644 --- a/ports/cortex_a5/iar/inc/ux_port.h +++ b/ports/cortex_a5/iar/inc/ux_port.h @@ -242,7 +242,7 @@ VOID outpl(ULONG,ULONG); #ifdef UX_SYSTEM_INIT CHAR _ux_version_id[] = - "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-A5/IAR Version 6.1.12 *"; + "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-A5/IAR Version 6.2.0 *"; #else extern CHAR _ux_version_id[]; #endif diff --git a/ports/cortex_a5x/ac6/inc/ux_port.h b/ports/cortex_a5x/ac6/inc/ux_port.h index 1c677a54..887c2b04 100644 --- a/ports/cortex_a5x/ac6/inc/ux_port.h +++ b/ports/cortex_a5x/ac6/inc/ux_port.h @@ -259,7 +259,7 @@ VOID outpl(ULONG,ULONG); #ifdef UX_SYSTEM_INIT CHAR _ux_version_id[] = - "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-A5x/AC6 Version 6.1.12 *"; + "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-A5x/AC6 Version 6.2.0 *"; #else extern CHAR _ux_version_id[]; #endif diff --git a/ports/cortex_a7/gnu/inc/ux_port.h b/ports/cortex_a7/gnu/inc/ux_port.h index c937a33a..86edca69 100644 --- a/ports/cortex_a7/gnu/inc/ux_port.h +++ b/ports/cortex_a7/gnu/inc/ux_port.h @@ -246,7 +246,7 @@ VOID outpl(ULONG,ULONG); #ifdef UX_SYSTEM_INIT CHAR _ux_version_id[] = - "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-A7/GNU Version 6.1.12 *"; + "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-A7/GNU Version 6.2.0 *"; #else extern CHAR _ux_version_id[]; #endif diff --git a/ports/cortex_a7/iar/inc/ux_port.h b/ports/cortex_a7/iar/inc/ux_port.h index 3ef6d481..dd01a952 100644 --- a/ports/cortex_a7/iar/inc/ux_port.h +++ b/ports/cortex_a7/iar/inc/ux_port.h @@ -246,7 +246,7 @@ VOID outpl(ULONG,ULONG); #ifdef UX_SYSTEM_INIT CHAR _ux_version_id[] = - "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-A7/IAR Version 6.1.12 *"; + "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-A7/IAR Version 6.2.0 *"; #else extern CHAR _ux_version_id[]; #endif diff --git a/ports/cortex_a8/gnu/inc/ux_port.h b/ports/cortex_a8/gnu/inc/ux_port.h index 9453e58a..5cda0b87 100644 --- a/ports/cortex_a8/gnu/inc/ux_port.h +++ b/ports/cortex_a8/gnu/inc/ux_port.h @@ -242,7 +242,7 @@ VOID outpl(ULONG,ULONG); #ifdef UX_SYSTEM_INIT CHAR _ux_version_id[] = - "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-A8/GNU Version 6.1.12 *"; + "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-A8/GNU Version 6.2.0 *"; #else extern CHAR _ux_version_id[]; #endif diff --git a/ports/cortex_a8/iar/inc/ux_port.h b/ports/cortex_a8/iar/inc/ux_port.h index 7a0ee0d8..30249c4e 100644 --- a/ports/cortex_a8/iar/inc/ux_port.h +++ b/ports/cortex_a8/iar/inc/ux_port.h @@ -242,7 +242,7 @@ VOID outpl(ULONG,ULONG); #ifdef UX_SYSTEM_INIT CHAR _ux_version_id[] = - "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-A8/IAR Version 6.1.12 *"; + "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-A8/IAR Version 6.2.0 *"; #else extern CHAR _ux_version_id[]; #endif diff --git a/ports/cortex_a9/gnu/inc/ux_port.h b/ports/cortex_a9/gnu/inc/ux_port.h index 7af6f395..e2c45f7c 100644 --- a/ports/cortex_a9/gnu/inc/ux_port.h +++ b/ports/cortex_a9/gnu/inc/ux_port.h @@ -242,7 +242,7 @@ VOID outpl(ULONG,ULONG); #ifdef UX_SYSTEM_INIT CHAR _ux_version_id[] = - "Copyright (c) Microsoft Corporation. All rights reserved. * USBX ARM9/GNU Version 6.1.12 *"; + "Copyright (c) Microsoft Corporation. All rights reserved. * USBX ARM9/GNU Version 6.2.0 *"; #else extern CHAR _ux_version_id[]; #endif diff --git a/ports/cortex_a9/iar/inc/ux_port.h b/ports/cortex_a9/iar/inc/ux_port.h index 2564a8ac..7cbff016 100644 --- a/ports/cortex_a9/iar/inc/ux_port.h +++ b/ports/cortex_a9/iar/inc/ux_port.h @@ -242,7 +242,7 @@ VOID outpl(ULONG,ULONG); #ifdef UX_SYSTEM_INIT CHAR _ux_version_id[] = - "Copyright (c) Microsoft Corporation. All rights reserved. * USBX ARM9/IAR Version 6.1.12 *"; + "Copyright (c) Microsoft Corporation. All rights reserved. * USBX ARM9/IAR Version 6.2.0 *"; #else extern CHAR _ux_version_id[]; #endif diff --git a/ports/cortex_m0/gnu/inc/ux_port.h b/ports/cortex_m0/gnu/inc/ux_port.h index b22c35bf..a015ba1c 100644 --- a/ports/cortex_m0/gnu/inc/ux_port.h +++ b/ports/cortex_m0/gnu/inc/ux_port.h @@ -240,7 +240,7 @@ VOID outpl(ULONG,ULONG); #ifdef UX_SYSTEM_INIT CHAR _ux_version_id[] = - "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-M0/GNU Version 6.1.12 *"; + "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-M0/GNU Version 6.2.0 *"; #else extern CHAR _ux_version_id[]; #endif diff --git a/ports/cortex_m0/iar/inc/ux_port.h b/ports/cortex_m0/iar/inc/ux_port.h index b1d10d56..8c6241a8 100644 --- a/ports/cortex_m0/iar/inc/ux_port.h +++ b/ports/cortex_m0/iar/inc/ux_port.h @@ -242,7 +242,7 @@ VOID outpl(ULONG,ULONG); #ifdef UX_SYSTEM_INIT CHAR _ux_version_id[] = - "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-M0/IAR Version 6.1.12 *"; + "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-M0/IAR Version 6.2.0 *"; #else extern CHAR _ux_version_id[]; #endif diff --git a/ports/cortex_m3/gnu/inc/ux_port.h b/ports/cortex_m3/gnu/inc/ux_port.h index 11ddb422..a26b679a 100644 --- a/ports/cortex_m3/gnu/inc/ux_port.h +++ b/ports/cortex_m3/gnu/inc/ux_port.h @@ -240,7 +240,7 @@ VOID outpl(ULONG,ULONG); #ifdef UX_SYSTEM_INIT CHAR _ux_version_id[] = - "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-M3/GNU Version 6.1.12 *"; + "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-M3/GNU Version 6.2.0 *"; #else extern CHAR _ux_version_id[]; #endif diff --git a/ports/cortex_m3/iar/inc/ux_port.h b/ports/cortex_m3/iar/inc/ux_port.h index d3807aee..a32cb282 100644 --- a/ports/cortex_m3/iar/inc/ux_port.h +++ b/ports/cortex_m3/iar/inc/ux_port.h @@ -242,7 +242,7 @@ VOID outpl(ULONG,ULONG); #ifdef UX_SYSTEM_INIT CHAR _ux_version_id[] = - "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-M3/IAR Version 6.1.12 *"; + "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-M3/IAR Version 6.2.0 *"; #else extern CHAR _ux_version_id[]; #endif diff --git a/ports/cortex_m4/gnu/inc/ux_port.h b/ports/cortex_m4/gnu/inc/ux_port.h index 7113f32d..c1eb4ac4 100644 --- a/ports/cortex_m4/gnu/inc/ux_port.h +++ b/ports/cortex_m4/gnu/inc/ux_port.h @@ -240,7 +240,7 @@ VOID outpl(ULONG,ULONG); #ifdef UX_SYSTEM_INIT CHAR _ux_version_id[] = - "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-M4/GNU Version 6.1.12 *"; + "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-M4/GNU Version 6.2.0 *"; #else extern CHAR _ux_version_id[]; #endif diff --git a/ports/cortex_m4/iar/inc/ux_port.h b/ports/cortex_m4/iar/inc/ux_port.h index 28f56e76..22f42501 100644 --- a/ports/cortex_m4/iar/inc/ux_port.h +++ b/ports/cortex_m4/iar/inc/ux_port.h @@ -242,7 +242,7 @@ VOID outpl(ULONG,ULONG); #ifdef UX_SYSTEM_INIT CHAR _ux_version_id[] = - "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-M4/IAR Version 6.1.12 *"; + "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-M4/IAR Version 6.2.0 *"; #else extern CHAR _ux_version_id[]; #endif diff --git a/ports/cortex_m7/gnu/inc/ux_port.h b/ports/cortex_m7/gnu/inc/ux_port.h index 62e95678..a8e50f6d 100644 --- a/ports/cortex_m7/gnu/inc/ux_port.h +++ b/ports/cortex_m7/gnu/inc/ux_port.h @@ -240,7 +240,7 @@ VOID outpl(ULONG,ULONG); #ifdef UX_SYSTEM_INIT CHAR _ux_version_id[] = - "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-M7/GNU Version 6.1.12 *"; + "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-M7/GNU Version 6.2.0 *"; #else extern CHAR _ux_version_id[]; #endif diff --git a/ports/cortex_m7/iar/inc/ux_port.h b/ports/cortex_m7/iar/inc/ux_port.h index dd8f8925..813bd4e2 100644 --- a/ports/cortex_m7/iar/inc/ux_port.h +++ b/ports/cortex_m7/iar/inc/ux_port.h @@ -242,7 +242,7 @@ VOID outpl(ULONG,ULONG); #ifdef UX_SYSTEM_INIT CHAR _ux_version_id[] = - "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-M7/IAR Version 6.1.12 *"; + "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-M7/IAR Version 6.2.0 *"; #else extern CHAR _ux_version_id[]; #endif diff --git a/ports/cortex_r4/gnu/inc/ux_port.h b/ports/cortex_r4/gnu/inc/ux_port.h index 09c11308..ba0a5cff 100644 --- a/ports/cortex_r4/gnu/inc/ux_port.h +++ b/ports/cortex_r4/gnu/inc/ux_port.h @@ -238,7 +238,7 @@ VOID outpl(ULONG,ULONG); #ifdef UX_SYSTEM_INIT CHAR _ux_version_id[] = - "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-R4/GNU Version 6.1.12 *"; + "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-R4/GNU Version 6.2.0 *"; #else extern CHAR _ux_version_id[]; #endif diff --git a/ports/cortex_r4/iar/inc/ux_port.h b/ports/cortex_r4/iar/inc/ux_port.h index 932e71a6..2d5dc12a 100644 --- a/ports/cortex_r4/iar/inc/ux_port.h +++ b/ports/cortex_r4/iar/inc/ux_port.h @@ -242,7 +242,7 @@ VOID outpl(ULONG,ULONG); #ifdef UX_SYSTEM_INIT CHAR _ux_version_id[] = - "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-R4/IAR Version 6.1.12 *"; + "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-R4/IAR Version 6.2.0 *"; #else extern CHAR _ux_version_id[]; #endif diff --git a/ports/cortex_r5/gnu/inc/ux_port.h b/ports/cortex_r5/gnu/inc/ux_port.h index 6654a7b4..940d7291 100644 --- a/ports/cortex_r5/gnu/inc/ux_port.h +++ b/ports/cortex_r5/gnu/inc/ux_port.h @@ -242,7 +242,7 @@ VOID outpl(ULONG,ULONG); #ifdef UX_SYSTEM_INIT CHAR _ux_version_id[] = - "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-R5/GNU Version 6.1.12 *"; + "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-R5/GNU Version 6.2.0 *"; #else extern CHAR _ux_version_id[]; #endif diff --git a/ports/cortex_r5/iar/inc/ux_port.h b/ports/cortex_r5/iar/inc/ux_port.h index 03829ebb..c8a1bbf0 100644 --- a/ports/cortex_r5/iar/inc/ux_port.h +++ b/ports/cortex_r5/iar/inc/ux_port.h @@ -242,7 +242,7 @@ VOID outpl(ULONG,ULONG); #ifdef UX_SYSTEM_INIT CHAR _ux_version_id[] = - "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-R5/IAR Version 6.1.12 *"; + "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Cortex-R5/IAR Version 6.2.0 *"; #else extern CHAR _ux_version_id[]; #endif diff --git a/ports/generic/inc/ux_port.h b/ports/generic/inc/ux_port.h index 4973c2a2..8ac0137f 100644 --- a/ports/generic/inc/ux_port.h +++ b/ports/generic/inc/ux_port.h @@ -242,7 +242,7 @@ VOID outpl(ULONG,ULONG); #ifdef UX_SYSTEM_INIT CHAR _ux_version_id[] = - "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Generic Version 6.1.12 *"; + "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Generic Version 6.2.0 *"; #else extern CHAR _ux_version_id[]; #endif diff --git a/ports/linux/gnu/inc/ux_port.h b/ports/linux/gnu/inc/ux_port.h index 0ebd9239..57954352 100644 --- a/ports/linux/gnu/inc/ux_port.h +++ b/ports/linux/gnu/inc/ux_port.h @@ -244,7 +244,7 @@ ULONG outpl(ULONG,ULONG); #ifdef UX_SYSTEM_INIT CHAR _ux_version_id[] = - "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Linux/GNU Version 6.1.12 *"; + "Copyright (c) Microsoft Corporation. All rights reserved. * USBX Linux/GNU Version 6.2.0 *"; #else extern CHAR _ux_version_id[]; #endif