diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
new file mode 100644
index 000000000..6f523602d
--- /dev/null
+++ b/.git-blame-ignore-revs
@@ -0,0 +1,26 @@
+# Commits that changed file headers, copyright lines or version constants across
+# the whole tree. They carry no behavioural change, so `git blame` should look
+# through them to the commit that last touched the code itself.
+#
+# GitHub applies this file automatically. To use it locally, run once:
+#
+# git config blame.ignoreRevsFile .git-blame-ignore-revs
+#
+# Add a commit here only when it is mechanical and repository-wide. A commit
+# that changes behaviour does not belong in this file, however large it is.
+
+# 2024-01-29 Update copyright.
+# 986 files
+a6087c2efa17d10f67b450392218b68571a68d16
+
+# 2026-03-05 Updated copyright headers and removed trailing whitespace
+# 1128 files
+ea36a88e9fee4136b56e0b8faf94b9acf4c21761
+
+# 2026-03-05 Removed misplaced copyright headers and updated port version strings
+# 31 files
+b20e7effea2140ded769c19184bc533480b04b8d
+
+# 2026-06-06 Added copyright headers to files missing them
+# 544 files
+d0d46fd2418f3c1f9a29aeb8b3e3af53cb773dbf
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 000000000..29a1c5fbe
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,10 @@
+version: 2
+updates:
+ - package-ecosystem: github-actions
+ directory: /
+ target-branch: dev
+ schedule:
+ interval: weekly
+ ignore:
+ # The cross-repository bootstrap and workflow are reviewed together.
+ - dependency-name: eclipse-threadx/threadx/.github/workflows/regression_template.yml
diff --git a/.github/workflows/regression_test.yml b/.github/workflows/regression_test.yml
index 5576b211c..e2d39acd2 100644
--- a/.github/workflows/regression_test.yml
+++ b/.github/workflows/regression_test.yml
@@ -1,29 +1,27 @@
name: USBX Regression Test
-# Controls when the action will run. Triggers the workflow on push or pull request
-# events but only for the master branch
on:
workflow_dispatch:
inputs:
tests_to_run:
- description: 'all, single or multiple of default_build_coverage error_check_build_full_coverage tracex_enable_build device_buffer_owner_build device_zero_copy_build nofx_build_coverage optimized_build standalone_device_build_coverage standalone_device_buffer_owner_build standalone_device_zero_copy_build standalone_host_build_coverage standalone_build_coverage generic_build otg_support_build memory_management_build_coverage msrc_rtos_build msrc_standalone_build'
- required: false
+ description: 'all, or space-separated profiles from test/cmake/usbx/CMakeLists.txt'
+ required: true
default: 'all'
+ type: string
skip_coverage:
required: false
type: boolean
default: false
- coverage_name:
- required: false
- default: 'default_build_coverage'
push:
- branches: [ master ]
+ branches: [dev, master]
pull_request:
- branches: [ master ]
+ branches: [dev, master]
-# A workflow run is made up of one or more jobs that can run sequentially or in parallel
-jobs:
+concurrency:
+ group: usbx-regression-${{ github.event.pull_request.number || github.ref }}
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
+jobs:
manual_tests:
if: github.event_name == 'workflow_dispatch'
permissions:
@@ -31,16 +29,19 @@ jobs:
issues: read
checks: write
pull-requests: write
+ # GitHub validates deployment permissions even when that job is skipped.
+ # The called test job narrows its own token scope.
pages: write
id-token: write
-
- uses: eclipse-threadx/threadx/.github/workflows/regression_template.yml@master
+ uses: eclipse-threadx/threadx/.github/workflows/regression_template.yml@b37cd4a81a1cb8c2ebefc438220ab7f009e13362
with:
cmake_path: ./test/cmake/usbx
- build_script: ./scripts/build.sh ${{ inputs.tests_to_run }}
- test_script: ./scripts/test.sh ${{ inputs.tests_to_run }}
- coverage_name: ${{ inputs.coverage_name }}
- skip_coverage: ${{ !!inputs.skip_coverage }}
+ build_script: ./scripts/build.sh --manual
+ test_script: ./scripts/test.sh --manual
+ coverage_name: ${{ inputs.tests_to_run == 'all' && 'merged' || 'subset' }}
+ coverage_thresholds: '0 100'
+ skip_coverage: ${{ inputs.skip_coverage }}
+ skip_deploy: ${{ github.ref != 'refs/heads/master' || inputs.tests_to_run != 'all' }}
auto_tests:
if: github.event_name != 'workflow_dispatch'
@@ -49,13 +50,15 @@ jobs:
issues: read
checks: write
pull-requests: write
+ # The reusable workflow declares a separate deployment job.
pages: write
id-token: write
-
- uses: eclipse-threadx/threadx/.github/workflows/regression_template.yml@master
+ uses: eclipse-threadx/threadx/.github/workflows/regression_template.yml@b37cd4a81a1cb8c2ebefc438220ab7f009e13362
with:
cmake_path: ./test/cmake/usbx
build_script: ./scripts/build.sh all
test_script: ./scripts/test.sh all
- coverage_name: default_build_coverage
+ coverage_name: merged
+ coverage_thresholds: '66 100'
skip_coverage: false
+ skip_deploy: ${{ github.event_name != 'push' || github.ref != 'refs/heads/master' }}
diff --git a/.github/workflows/repo_checks.yml b/.github/workflows/repo_checks.yml
new file mode 100644
index 000000000..955e6ddd1
--- /dev/null
+++ b/.github/workflows/repo_checks.yml
@@ -0,0 +1,63 @@
+###############################################################################
+# Copyright (c) 2026 Eclipse ThreadX contributors
+#
+# This program and the accompanying materials are made available under the
+# terms of the MIT License which is available at
+# https://opensource.org/licenses/MIT.
+#
+# AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5).
+# The AI-generated portions may be considered public domain (CC0-1.0)
+# and not subject to the project's licence. The human contributor has
+# reviewed and verified that the code is correct.
+#
+# SPDX-License-Identifier: MIT and CC0-1.0
+###############################################################################
+
+name: repo_checks
+
+# Repository-wide text checks.
+#
+# THIS LIVES IN ITS OWN WORKFLOW BECAUSE IT MUST NOT BE PATH-FILTERED, and a
+# path filter is a property of a workflow rather than of a job. The check
+# selects its input with `git ls-files` and scans every tracked file, so any
+# file at all can carry a finding.
+#
+# That is not hypothetical here. The pass that introduced the fixed
+# disclosure line covered source files only, and the drift it was meant to end
+# survived for months afterwards in CMake files, toolchain files, shell and
+# PowerShell scripts, a GDB script and a Visual Studio manifest -- precisely
+# the files a source-path filter would have skipped. A workflow that gates no
+# pull request anybody opens is worse than no workflow, because it looks like
+# coverage.
+#
+# Cheap enough that running it on everything costs nothing worth measuring: it
+# is grep over a repository this size, with no toolchain, no build and no
+# cache.
+
+on:
+ # No `paths:` on either trigger, deliberately. See above.
+ push:
+ branches: [ dev, master ]
+ pull_request:
+ branches: [ dev, master ]
+
+# A second push to the same branch makes the first answer irrelevant.
+concurrency:
+ group: repo-checks-${{ github.ref }}
+ cancel-in-progress: true
+
+permissions:
+ contents: read
+
+jobs:
+ checks:
+ runs-on: ubuntu-24.04
+ steps:
+ # Actions are pinned to a commit SHA with the version in the trailing
+ # comment. A tag can be moved; a SHA cannot, which is what makes "which
+ # code ran in our CI" answerable from the repository.
+ - name: Check out the repository
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+
+ - name: Check the AI disclosure comments
+ run: scripts/check_ai_disclosure.sh
diff --git a/.gitignore b/.gitignore
index f187e2a32..c42604ed1 100755
--- a/.gitignore
+++ b/.gitignore
@@ -13,3 +13,8 @@ compile_commands.json
CTestTestfile.cmake
coverage_report/
+
+/test/externals/
+/test/cmake/usbx/.run.sh
+/test/cmake/usbx/libs/
+__pycache__/
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index a327a0bc9..481fedda8 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,72 +1,361 @@
-# Contributing to Eclipse ThreadX
+# Contributing to Eclipse ThreadX USBX
Thanks for your interest in this project.
## Project description
-Eclipse ThreadX provides a vendor-neutral, open source, safety certified OS for
-real-time applications published on under a permissive license. The Eclipse
-ThreadX suite encompasses:
-* ThreadX - advanced real-time operating system (RTOS) designed specifically for deeply embedded applications
-* NetX Duo - advanced, industrial-grade TCP/IP network stack designed specifically for deeply embedded real-time and IoT applications
-* FileX - high-performance, FAT-compatible file system that’s fully integrated with ThreadX kernel
-* GUIX - provides a complete, embedded graphical user interface (GUI) library
-* USBX - high-performance USB host, device, and on-the-go (OTG) embedded stack, that is fully integrated with ThreadX kernel
-* LevelX - Flash Wear Leveling for FileX and stand-alone purposes
-* GuiX Studio - design environment, facilitating the creation and maintenance of all graphical elements for GUIX
-* TraceX - analysis tool that provides a graphical view of real-time system events to better understand the behavior of real-time systems
+USBX is the Eclipse ThreadX USB host, device, and on-the-go stack for deeply embedded systems. This repository contains the USB core, class drivers, controller support, and processor ports. It is designed for a small footprint and high performance, and integrates with ThreadX. The repository's CMake target also links the FileX and NetX Duo component targets.
-Project site: https://projects.eclipse.org/projects/iot.threadx
+Eclipse ThreadX provides a vendor-neutral, open source, safety-certified OS for real-time applications, published under a permissive license. The Eclipse ThreadX suite encompasses:
+
+* **ThreadX** - advanced real-time operating system (RTOS) designed specifically for deeply embedded applications
+* **NetX Duo** - advanced, industrial-grade TCP/IP network stack designed specifically for deeply embedded real-time and IoT applications
+* **FileX** - high-performance, FAT-compatible file system that is fully integrated with the ThreadX kernel
+* **GUIX** - complete, embedded graphical user interface (GUI) library
+* **GUIX Studio** - design environment, facilitating the creation and maintenance of all graphical elements for GUIX
+* **USBX** - high-performance USB host, device, and on-the-go (OTG) embedded stack, fully integrated with the ThreadX kernel
+* **LevelX** - flash wear levelling for FileX and stand-alone purposes
+* **TraceX** - analysis tool that provides a graphical view of real-time system events to better understand the behaviour of real-time systems
+* **ZoneX** - deterministic partitioning hypervisor for mixed-criticality embedded systems
+* **SampleX** - samples and demos for the components above
+
+Project websites:
+
+* https://threadx.io
+* https://projects.eclipse.org/projects/iot.threadx
+
+This file describes how to contribute to **USBX**. General contribution conventions are shared across the Eclipse ThreadX repositories; build and test instructions differ by component.
## Terms of Use
-This repository is subject to the Terms of Use of the Eclipse Foundation
-https://www.eclipse.org/legal/termsofuse.php
+This repository is subject to the Terms of Use of the Eclipse Foundation: https://www.eclipse.org/legal/termsofuse.php
-## Developer resources
+## New contributors
-Information regarding source code management, builds, coding standards, and more.
-https://projects.eclipse.org/projects/iot.threadx/developer
+Welcome. Here is the shortest path from zero to a merged pull request.
-The project maintains the following source code repositories
+1. **Create an Eclipse Foundation account.** https://accounts.eclipse.org/user/register
-* https://github.com/eclipse-threadx/.github
-* https://github.com/eclipse-threadx/cmsis-packs
-* https://github.com/eclipse-threadx/filex
-* https://github.com/eclipse-threadx/getting-started
-* https://github.com/eclipse-threadx/guix
-* https://github.com/eclipse-threadx/levelx
-* https://github.com/eclipse-threadx/netxduo
-* https://github.com/eclipse-threadx/rtos-docs
-* https://github.com/eclipse-threadx/samples
-* https://github.com/eclipse-threadx/threadx
-* https://github.com/eclipse-threadx/threadx-learn-samples
-* https://github.com/eclipse-threadx/tracex
-* https://github.com/eclipse-threadx/usbx
+ The email address on that account matters: it must be the same address you use as the `Author` of your Git commits. If the two do not match, the ECA check on your pull request will fail.
+
+2. **Sign the Eclipse Contributor Agreement (ECA).** See the section below. This is a one-time step and covers every Eclipse Foundation project.
+
+
+
+3. **Configure Git accordingly.**
+
+ ```
+ git config user.name "Your Name"
+ git config user.email "the-address-on-your-eclipse-account@example.org"
+ ```
+
+4. **Pick something to work on.** Open issues are fair game, including ones nobody has assigned. Please leave a comment on the issue saying you intend to work on it, so two people do not solve the same problem twice. If an issue carries a `good first issue` label, it is a reasonable starting point.
+
+5. **Have an idea for a new feature? Discuss it first.** Open a thread in [GitHub Discussions](https://github.com/orgs/eclipse-threadx/discussions) or raise it on the [developer mailing list](https://accounts.eclipse.org/mailing-list/threadx-dev) before writing code. USB host, device, class, and controller changes can affect many applications, so discuss the shape of a feature before submitting a finished implementation.
+
+Bug fixes and documentation corrections need no prior discussion. Send them straight in.
## Eclipse Development Process
-This Eclipse Foundation open project is governed by the Eclipse Foundation
-Development Process and operates under the terms of the Eclipse IP Policy.
+This Eclipse Foundation open project is governed by the Eclipse Foundation Development Process and operates under the terms of the Eclipse IP Policy.
* https://eclipse.org/projects/dev_process
* https://www.eclipse.org/org/documents/Eclipse_IP_Policy.pdf
## Eclipse Contributor Agreement
-In order to be able to contribute to Eclipse Foundation projects you must electronically sign the Eclipse Contributor Agreement (ECA).
-https://www.eclipse.org/legal/ECA.php
+In order to be able to contribute to Eclipse Foundation projects you must electronically sign the Eclipse Contributor Agreement (ECA): https://www.eclipse.org/legal/ECA.php
+
+The ECA provides the Eclipse Foundation with a permanent record that you agree that each of your contributions will comply with the commitments documented in the Developer Certificate of Origin (DCO). Having an ECA on file associated with the email address matching the "Author" field of your contribution's Git commits fulfills the DCO's requirement that you sign-off on your contributions.
+
+For more information, please see the Eclipse Committer Handbook: https://www.eclipse.org/projects/handbook/#resources-commit
+
+## Required tooling
+
+Build and test USBX with CMake and Ninja. The root project and regression project require CMake 3.13 or later. The project reference compiler on Linux is GCC 14 with matching gcov. The regression installer, `scripts/install.sh`, sets up Ubuntu host tools and pins `gcovr` 8.6 in a Python virtual environment; activate that environment before collecting coverage locally. The Windows simulator has `win32` and `win64` ports and uses MSVC from the Visual Studio Build Tools; the Visual Studio IDE is not required. Embedded ports use the compiler and toolchain files for their target; the repository has GNU, IAR, and Arm Compiler ports. Use GCC syntax for assembly built with GNU toolchains.
+
+USBX code must be C99-compatible. The regression project's CMake options include `-std=c99`.
+
+The regression test setup uses ThreadX, NetX Duo, and FileX. The Linux runner fetches their pinned revisions under `test/externals/` and checks existing checkouts against those pins; the Windows build script accepts their source checkouts as arguments. An embedded application must supply the component targets required by the USBX CMake build.
+
+## Building and testing
+
+The host regression suite lives under `test/cmake/usbx/`. Run its build script before its test script:
+
+```sh
+CC=gcc-14 GCOV=gcov-14 TX_COVERAGE=ON scripts/build.sh all
+CC=gcc-14 GCOV=gcov-14 TX_COVERAGE=ON scripts/test.sh all
+```
+
+The scripts also accept one or more configuration names instead of `all`. For a focused run, use the same configurations in both commands:
+
+```sh
+scripts/build.sh default_build_coverage standalone_device_build_coverage
+scripts/test.sh default_build_coverage standalone_device_build_coverage
+```
+
+The CMake test project defines configurations for the normal RTOS build, error checking, TraceX integration, device buffer ownership and zero copy, builds without FileX, optimized and generic builds, OTG support, memory management, mass storage, and standalone host and device modes. Select the configurations affected by your change; run `all` before asking for review when feasible.
+
+On Windows, use the PowerShell scripts with the Visual Studio Build Tools available. Supply the three component source checkouts explicitly:
+
+```powershell
+scripts/build_usbx.ps1 -Arch win64 -Configuration default_build_coverage -ThreadXDir 'path/to/threadx' -FilexDir 'path/to/filex' -NetxduoDir 'path/to/netxduo'
+scripts/test_usbx.ps1 -Arch win64 -Configuration default_build_coverage
+```
+
+Use `-Arch win32` for the 32-bit simulator. Both scripts accept `-Configuration all` or selected configuration names. The Windows test script runs CTest serially because concurrent simulator tests can interfere with timing. Report the architecture and configurations that exercised the change.
+
+On Linux, `TX_COVERAGE=ON` instruments every selected configuration and produces per-configuration and merged reports under `test/cmake/usbx/coverage_report/`. The merged report includes compiled USBX C sources across the configurations without profile-specific exclusions. The full-suite CI gate requires at least 66% line and 54.5% branch coverage; these floors do not replace the project's 100% coverage goal. The MSVC Windows runs do not collect coverage. Add or update regression tests for new behaviour, explain relevant gaps, and test port changes on the affected USB hardware or controller when available.
+
+## Continuous integration
+
+`regression_test.yml` runs on pushes and pull requests to `dev` and `master`, and by manual dispatch. Automatic Linux runs build and test all 17 USBX configurations through the pinned ThreadX reusable regression workflow, then merge their coverage. Manual runs can select configurations and skip coverage.
+
+The workflow does not run the Windows simulator or USB hardware tests. Run those where relevant and report their results separately. Do not describe an unrun configuration or hardware target as verified.
+
+## Pull request acceptance criteria
+
+**Pull requests must target the `dev` branch.** `master` holds the latest release; see [Release model and support](#release-model-and-support) below. A pull request opened against `master` will be asked to retarget.
+
+Before requesting a review, check your contribution against this list.
+
+**Process**
+
+* The branch is a feature branch based on `dev`. Never commit directly to `master` or `dev`.
+* Your ECA is signed and the commit `Author` email matches your Eclipse account.
+* The pull request is one logical change. Unrelated fixes belong in separate pull requests.
+* Commit subject lines start with a past-tense verb, for example `Fixed the memory allocator`.
+* The pull request explains what changed and why, and how you verified it.
+
+**Code**
+
+* The code is C99-compatible.
+* It follows the coding style of the surrounding code.
+* New functions and structures are documented in comments, as in existing code.
+* MISRA C rules are followed as closely as practical, taking MISRA C 2004, 2012 and 2023 into account. Any deviation is explicit, names the rule being circumvented, and justifies it in a comment.
+* `goto` is not used.
+* Do not add new external dependencies. This is a hard rule. The existing ThreadX, FileX, and NetX Duo component relationships are part of the current build.
+* When implementing an industry standard, code is not copied from an existing implementation. Existing implementations may inform your work, but you must identify those sources clearly.
+* Code is written with the suite's priorities in mind: runtime speed and small code size.
+* New C and assembly files, and edited C and assembly files, carry the appropriate header and attribution (see below).
+
+**Verification**
+
+* All applicable CI checks are green, including the full Linux regression workflow on a pull request to `dev`.
+* The change builds without new warnings on the reference toolchains.
+* Regression tests covering the change are added or updated. The project targets 100% test coverage; a pull request that lowers coverage needs a stated reason. State which USBX configurations ran and any relevant coverage gap.
+* API or behaviour changes come with a matching documentation pull request against [rtos-docs-asciidoc](https://github.com/eclipse-threadx/rtos-docs-asciidoc).
+
+**Security**
+
+If you discover a security issue while working on a change, do not describe it in a public pull request. Follow [SECURITY.md](SECURITY.md) instead.
+
+## AI-assisted contributions
+
+**AI-assisted contributions are welcome**, provided they are attributed.
+
+Two things are non-negotiable:
+
+1. **Attribution.** Mark AI-assisted C and assembly files as described below, and identify the tool and model in the commit message.
+2. **Human responsibility.** The human contributor submitting the pull request is responsible for the contribution - technically and legally. Signing the ECA means *you* certify the contribution's provenance. An AI tool cannot sign the ECA and cannot hold that responsibility. Review what the tool produced, understand it, and verify that it is correct and that you have the right to contribute it. "The model wrote it" is not a defence.
+
+This is consistent with the Eclipse Foundation's [Generative AI Usage Guidelines](https://www.eclipse.org/projects/guidelines/genai/) and the [Eclipse Project Handbook](https://www.eclipse.org/projects/handbook/#genai). Please read them before submitting AI-assisted work.
+
+### Using a coding agent
+
+Give a coding agent this contribution guide and the build instructions for the area it changes. Review its output against the same acceptance criteria as any other contribution. In particular, check C99 compatibility, surrounding style, test coverage, and the relevant USB mode, class, or controller for runtime verification.
+
+### Header for new files
+
+Add this header when creating a new C or assembly (`.S`) file:
+
+```c
+/***************************************************************************
+ * Copyright (c) Eclipse ThreadX contributors
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the MIT License which is available at
+ * https://opensource.org/licenses/MIT.
+ *
+ * AI Disclosure: This file was largely AI-generated by ().
+ * The AI-generated portions may be considered public domain (CC0-1.0)
+ * and not subject to the project's licence. The human contributor has
+ * reviewed and verified that the code is correct.
+ *
+ * SPDX-License-Identifier: MIT and CC0-1.0
+ **************************************************************************/
+```
+
+Substitute the current year, product name, and model and version. If a file was written without AI assistance, omit the AI Disclosure paragraph and use `SPDX-License-Identifier: MIT`.
+
+### Header for existing files
+
+When editing an existing C or assembly file whose copyright is from 2025 or earlier, and which does not already mention Eclipse ThreadX contributors, add this line to the header:
+
+```c
+ * Copyright (c) Eclipse ThreadX contributors
+```
+
+It goes *below* the older copyright. All copyright lines must stay in chronological order. For example:
+
+```c
+/***************************************************************************
+ * Copyright (c) 2024 Microsoft Corporation
+ * Copyright (c) 2026 Eclipse ThreadX contributors
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the MIT License which is available at
+ * https://opensource.org/licenses/MIT.
+ *
+ * SPDX-License-Identifier: MIT
+ **************************************************************************/
+```
+
+If the edit was AI-assisted and the file does not already carry an AI disclosure line, add this line just under the header:
-The ECA provides the Eclipse Foundation with a permanent record that you agree
-that each of your contributions will comply with the commitments documented in
-the Developer Certificate of Origin (DCO). Having an ECA on file associated with
-the email address matching the "Author" field of your contribution's Git commits
-fulfills the DCO's requirement that you sign-off on your contributions.
+```c
+// Portions of this file were generated with AI assistance.
+```
-For more information, please see the Eclipse Committer Handbook:
-https://www.eclipse.org/projects/handbook/#resources-commit
+Use the comment marker already used by the file. Keep an existing disclosure line unchanged and never add a second one. If you copy an existing file to get started on a new one, treat the result as a new file: use the new-file header, do not carry the old one over.
+
+### Commit attribution
+
+Attribute AI assistance with an `Assisted-by` trailer in each commit that contains AI-assisted changes:
+
+```text
+Fixed the USB device transfer status
+
+A completed transfer could report an out-of-date status to the caller.
+
+The transfer path now returns the status set by the completed operation.
+
+The affected USBX regression configurations passed all tests.
+
+Assisted-by: ()
+```
+
+Use the product's accepted name (`Claude Code`, `Copilot`, `Codex`, or `Gemini`) and the model string reported by the tool. Do not use `Co-Authored-By` for AI attribution. Commit subjects and pull request titles start with a past-tense verb and stay within 72 characters. The message body states the cause, fix, and test result in that order; wrap commit bodies at 88 characters. Pull request descriptions use one line per paragraph.
+
+## Release model and support
+
+This section summarises the project's [Release Model and Support Policy](https://github.com/eclipse-threadx/rtos-docs-asciidoc/blob/main/rtos-docs/home/modules/ROOT/pages/releases-and-support.adoc), which is the authoritative version.
+
+### Version numbers
+
+Eclipse ThreadX releases generally follow [Semantic Versioning](https://semver.org/). Given a version number **X.Y.Z.Bh**, for example `6.5.0.202601a`:
+
+* **X** increases for a *milestone release*. Components currently stay at version 6.
+* **Y** increases for a *feature release* adding a major feature.
+* **Z** increases for a *maintenance release* of minor fixes and improvements.
+* **B** is a *build number* identifying the quarter of publication - `202601` is Q1 2026.
+* **h** denotes a *hotfix release*, identified by a letter. Hotfix releases are component-specific.
+
+### Release cadence
+
+The project adopted a predictable quarterly release model in September 2025 and has published a release every quarter since.
+
+Quarterly releases ship new versions of every component, whether or not that component saw code changes, so that version numbers do not drift apart between components. A release shipping no code changes for a component says so in its release notes.
+
+Urgent fixes between quarterly releases ship as *hotfix* releases. Those contain only security fixes, or fixes for serious problems that prevent building or testing applications.
+
+### Branches
+
+The project runs a time-based release train on trunk-based development. There are no long-term support branches and no backports to older releases.
+
+* `master` always contains the latest quarterly or hotfix release.
+* `dev` is the integration branch. Pull requests are merged there during the quarter. Track `dev` if you want to test new features and fixes ahead of a release.
+* A quarterly release is performed by merging `dev` into `master`.
+
+### Support policy
+
+Issues in the codebase are fixed on a best-effort basis, and pull requests fixing existing or new issues are gladly accepted.
+
+Security vulnerabilities disclosed confidentially are handled under the [Eclipse Foundation's security policy](https://www.eclipse.org/security/policy/). Once a candidate vulnerability is confirmed, the team works to deliver a fix as soon as possible, shipping it in the next quarterly release or as a hotfix depending on timing. Resolved vulnerabilities are disclosed immediately after a release containing the fix becomes available. The team aims to resolve newly confirmed vulnerabilities within three months; that period may be extended by the Project Leadership Chain together with the Eclipse Foundation Security team where appropriate.
+
+See [SECURITY.md](SECURITY.md) for how to report a vulnerability.
+
+### Roadmap
+
+The project team plans its work on a [public GitHub project board](https://github.com/orgs/eclipse-threadx/projects/2/views/2).
+
+### A note on older releases
+
+Microsoft contributed only the Azure RTOS codebase v6.x to the Eclipse Foundation. Older ThreadX releases (v5.x and lower) sold by Express Logic were never made open source, and Microsoft has discontinued sales and support for them. Users of ThreadX 5.x and lower should upgrade to the latest release of Eclipse ThreadX as soon as possible.
+
+## Documentation
+
+The documentation is published at **https://threadx.io**. PDF manuals for every component, in A4 and US Letter formats, are attached as assets to each GitHub release.
+
+### The stack
+
+Documentation is written in [AsciiDoc](https://asciidoc.org/) and built with [Antora](https://antora.org/). PDF manuals are produced by the [Antora Assembler](https://docs.antora.org/assembler/latest/) with `asciidoctor-pdf`.
+
+### The workflow
+
+1. The single source of truth is [rtos-docs-asciidoc](https://github.com/eclipse-threadx/rtos-docs-asciidoc). All documentation changes are made there, as pull requests, following the same branch rules as the code repositories.
+2. At release time the site is generated from that source into [rtos-docs-html](https://github.com/eclipse-threadx/rtos-docs-html), which holds the rendered HTML and exists solely for website integration. Do not edit it by hand - your changes will be overwritten by the next build.
+3. The website then serves the generated content from `rtos-docs-html`.
+
+The older `rtos-docs` repository, which held the documentation in Markdown, is archived and superseded by `rtos-docs-asciidoc`. Do not send changes there.
+
+If your contribution adds or changes an API or a feature, open a matching pull request against `rtos-docs-asciidoc`.
+
+## Developer resources
+
+Information regarding source code management, builds, coding standards, and more: https://projects.eclipse.org/projects/iot.threadx/developer
+
+The project maintains the following repositories:
+
+**Components**
+
+* https://github.com/eclipse-threadx/threadx
+* https://github.com/eclipse-threadx/netxduo
+* https://github.com/eclipse-threadx/filex
+* https://github.com/eclipse-threadx/guix
+* https://github.com/eclipse-threadx/usbx
+* https://github.com/eclipse-threadx/levelx
+* https://github.com/eclipse-threadx/tracex
+* https://github.com/eclipse-threadx/zonex
+
+**Samples and platforms**
+
+* https://github.com/eclipse-threadx/samplex
+* https://github.com/eclipse-threadx/supported-platforms
+
+**Documentation**
+
+* https://github.com/eclipse-threadx/rtos-docs-asciidoc
+* https://github.com/eclipse-threadx/rtos-docs-html
+
+**Community and process**
+
+* https://github.com/eclipse-threadx/discussions
+* https://github.com/eclipse-threadx/trustedx
+* https://github.com/eclipse-threadx/.github
## Contact
-Contact the project developers via the project's "dev" list.
+### GitHub Discussions
+
+https://github.com/orgs/eclipse-threadx/discussions
+
+Q&A, feedback, and announcements. Decisions taken by the project team are documented here as well. This is usually the fastest way to reach both the team and other users.
+
+### Main ThreadX mailing list
+
+https://accounts.eclipse.org/mailing-list/threadx
+
+News and updates about the ThreadX project and the ThreadX Alliance.
+
+### Developer mailing list
+
https://accounts.eclipse.org/mailing-list/threadx-dev
+
+Project team conversations. Feel free to jump in and ask non-technical questions there.
+
+### User mailing list
+
+https://accounts.eclipse.org/mailing-list/threadx-users
+
+Ask your technical questions and discuss issues here.
diff --git a/README.md b/README.md
index 2c8ad7c89..9db3bab5c 100755
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@ Eclipse ThreadX USBX as part of Eclipse ThreadX has been integrated to the semic
We also provide [samples](https://github.com/azure-rtos/samples) using hero development boards from semiconductors you can build and test with.
-See [Overview of Eclipse ThreadX USBX](https://github.com/eclipse-threadx/rtos-docs/blob/main/rtos-docs/usbx/overview-usbx.md) for the high-level overview.
+See [Overview of Eclipse ThreadX USBX](https://threadx.io/releases/6.5.2/usbx/main/overview-usbx.html) for the high-level overview.
## Repository Structure and Usage
@@ -130,7 +130,7 @@ License terms for using Eclipse ThreadX are defined in the LICENSE.txt file of t
The following are references to additional Eclipse ThreadX resources:
-- **Product introduction**: https://github.com/eclipse-threadx/rtos-docs
+- **Product introduction**: https://threadx.io/releases/latest
- **Product issues and bugs, or feature requests**: https://github.com/eclipse-threadx/usbx/issues
- **TraceX Installer**: https://aka.ms/azrtos-tracex-installer
diff --git a/common/core/inc/ux_api.h b/common/core/inc/ux_api.h
index ed26f727f..e2fa35778 100644
--- a/common/core/inc/ux_api.h
+++ b/common/core/inc/ux_api.h
@@ -8,6 +8,7 @@
*
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
/**************************************************************************/
@@ -239,8 +240,8 @@ typedef signed char SCHAR;
#define AZURE_RTOS_USBX
#define USBX_MAJOR_VERSION 6
#define USBX_MINOR_VERSION 5
-#define USBX_PATCH_VERSION 1
-#define USBX_BUILD_VERSION 202602
+#define USBX_PATCH_VERSION 2
+#define USBX_BUILD_VERSION 202603
#define USBX_HOTFIX_VERSION ' '
/* Macros for concatenating tokens, where UX_CONCATn concatenates n tokens. */
@@ -1168,7 +1169,9 @@ VOID _ux_trace_event_update(TX_TRACE_BUFFER_ENTRY *event, ULONG timestamp, UL
#define UX_NON_CONTROL_TRANSFER_TIMEOUT 50000
#endif
#define UX_PORT_ENABLE_WAIT 50
+#ifndef UX_DEVICE_ADDRESS_SET_WAIT
#define UX_DEVICE_ADDRESS_SET_WAIT 50
+#endif
#define UX_HIGH_SPEED_DETECTION_HANDSHAKE_SUSPEND_WAIT 200
#define UX_ENUMERATION_THREAD_WAIT 200
@@ -1543,8 +1546,16 @@ VOID _ux_trace_event_update(TX_TRACE_BUFFER_ENTRY *event, ULONG timestamp, UL
/* Define USBX root HUB constants. */
+#ifndef UX_RH_ENUMERATION_RETRY
#define UX_RH_ENUMERATION_RETRY 3
+#endif
+#ifndef UX_RH_ENUMERATION_RETRY_DELAY
#define UX_RH_ENUMERATION_RETRY_DELAY 100
+#endif
+/* USB spec minimum debounce interval (ms) on device attach. */
+#ifndef UX_HOST_STACK_DEVICE_ATTACH_DEBOUNCE_DELAY
+#define UX_HOST_STACK_DEVICE_ATTACH_DEBOUNCE_DELAY 100
+#endif
/* Define USBX PCI driver constants. */
@@ -2856,4 +2867,3 @@ UINT ux_device_stack_transfer_run(UX_SLAVE_TRANSFER *transfer_request, ULONG
#endif
-
diff --git a/common/core/src/ux_device_stack_interface_get.c b/common/core/src/ux_device_stack_interface_get.c
index 5dc6c5fbd..f056ea41e 100644
--- a/common/core/src/ux_device_stack_interface_get.c
+++ b/common/core/src/ux_device_stack_interface_get.c
@@ -29,6 +29,19 @@
#include "ux_device_stack.h"
+/* DEPRECATION NOTICE
+ * _ux_device_stack_interface_get() is deprecated. Do not use it in new code.
+ *
+ * WHY: this function was renamed to _ux_device_stack_alternate_setting_get()
+ * to better reflect its semantics (it retrieves the current alternate setting
+ * for an interface, not the interface itself). The core stack uses the new
+ * name exclusively.
+ *
+ * WHAT TO DO: replace calls with ux_device_stack_alternate_setting_get().
+ */
+#pragma message("_ux_device_stack_interface_get() is deprecated. " \
+ "Use ux_device_stack_alternate_setting_get() instead.")
+
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
@@ -41,10 +54,8 @@
/* */
/* DESCRIPTION */
/* */
-/* This function is deprecated, ux_device_stack_alternate_setting_get */
-/* does the same thing and used by the core stack. */
-/* */
-/* This function gets the current alternate setting for an interface. */
+/* DEPRECATED. Use _ux_device_stack_alternate_setting_get() instead. */
+/* This function was renamed; the two are functionally identical. */
/* */
/* INPUT */
/* */
diff --git a/common/core/src/ux_host_stack_rh_device_insertion.c b/common/core/src/ux_host_stack_rh_device_insertion.c
index d00e52633..06216a0a7 100644
--- a/common/core/src/ux_host_stack_rh_device_insertion.c
+++ b/common/core/src/ux_host_stack_rh_device_insertion.c
@@ -8,6 +8,7 @@
*
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
/**************************************************************************/
@@ -112,7 +113,7 @@ UINT status;
return(port_status);
/* A debounce interval with a minimum duration of 100 ms on attach. */
- _ux_utility_delay_ms(100);
+ _ux_utility_delay_ms(UX_HOST_STACK_DEVICE_ATTACH_DEBOUNCE_DELAY);
/* The first attempts to do a device enumeration may fail.
Typically, after the port is reset and the first command is sent to
diff --git a/common/core/src/ux_utility_memory_free_block_best_get.c b/common/core/src/ux_utility_memory_free_block_best_get.c
index 331746117..46524f34d 100644
--- a/common/core/src/ux_utility_memory_free_block_best_get.c
+++ b/common/core/src/ux_utility_memory_free_block_best_get.c
@@ -40,9 +40,10 @@
/* */
/* DESCRIPTION */
/* */
-/* This function returns the best free memory block. */
-/* */
-/* It's deprecated. */
+/* DEPRECATED. This function is already disabled (compiled out via */
+/* #if 0) and exists only as a reference. The allocator implementation */
+/* it served has been superseded by the current USBX memory */
+/* management layer. Do not re-enable or reference this function. */
/* */
/* INPUT */
/* */
diff --git a/common/core/src/ux_utility_string_length_get.c b/common/core/src/ux_utility_string_length_get.c
index 3c34c8e23..41d6546cd 100644
--- a/common/core/src/ux_utility_string_length_get.c
+++ b/common/core/src/ux_utility_string_length_get.c
@@ -28,6 +28,19 @@
#include "ux_api.h"
+/* DEPRECATION NOTICE
+ * _ux_utility_string_length_get() is deprecated. Do not use it in new code.
+ *
+ * WHY: this function scans the string until it finds a NUL byte with no
+ * upper bound on the search. If the buffer is not properly NUL-terminated,
+ * the scan reads past the end of the buffer, which is undefined behaviour.
+ *
+ * WHAT TO DO: replace calls with _ux_utility_string_length_check(), passing
+ * the maximum buffer length as an additional argument.
+ */
+#pragma message("_ux_utility_string_length_get() is deprecated. " \
+ "Use _ux_utility_string_length_check() and pass the buffer length.")
+
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
@@ -40,13 +53,9 @@
/* */
/* DESCRIPTION */
/* */
-/* This function derives the length of a NULL-terminated string. */
-/* */
-/* This function is deprecated, for the possible issue of operating on */
-/* a buffer that is not NULL-terminated. As a replacement, */
-/* _ux_utility_string_length_check should be used, where the length of */
-/* the buffer is introduced to validate the string by checking for the */
-/* NULL-terminator within the buffer length. */
+/* DEPRECATED. Use _ux_utility_string_length_check() instead, passing */
+/* the maximum buffer length. This function scans without an upper */
+/* bound; a non-NUL-terminated buffer causes an overread. */
/* */
/* INPUT */
/* */
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 0badadd9f..e52b0e1ad 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
@@ -130,6 +130,14 @@ ULONG actual_length;
/* Get actual transfer length. */
actual_length = transfer -> ux_slave_transfer_request_actual_length;
+ /* A zero length packet carries no audio. Logging it would leave a
+ frame whose length is zero, which is what marks a slot free, and
+ the transfer position would still advance past it. */
+ if (actual_length == 0)
+ {
+ continue;
+ }
+
/* 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;
diff --git a/common/usbx_host_classes/inc/ux_host_class_cdc_acm.h b/common/usbx_host_classes/inc/ux_host_class_cdc_acm.h
index b8c392f48..36d3a1810 100644
--- a/common/usbx_host_classes/inc/ux_host_class_cdc_acm.h
+++ b/common/usbx_host_classes/inc/ux_host_class_cdc_acm.h
@@ -8,6 +8,7 @@
*
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
/**************************************************************************/
@@ -61,7 +62,9 @@ extern "C" {
/* Define CDC ACM Class constants. */
+#ifndef UX_HOST_CLASS_CDC_ACM_DEVICE_INIT_DELAY
#define UX_HOST_CLASS_CDC_ACM_DEVICE_INIT_DELAY 1000
+#endif
#define UX_HOST_CLASS_CDC_ACM_CLASS_TRANSFER_TIMEOUT 300000
#define UX_HOST_CLASS_CDC_DATA_CLASS 0x0A
#define UX_HOST_CLASS_CDC_CONTROL_CLASS 0x02
diff --git a/common/usbx_host_classes/inc/ux_host_class_pima.h b/common/usbx_host_classes/inc/ux_host_class_pima.h
index 2ed48d0e0..e7a6ca9d1 100644
--- a/common/usbx_host_classes/inc/ux_host_class_pima.h
+++ b/common/usbx_host_classes/inc/ux_host_class_pima.h
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
diff --git a/common/usbx_host_classes/inc/ux_host_class_storage.h b/common/usbx_host_classes/inc/ux_host_class_storage.h
index f9a5a59b1..769b3e6c9 100644
--- a/common/usbx_host_classes/inc/ux_host_class_storage.h
+++ b/common/usbx_host_classes/inc/ux_host_class_storage.h
@@ -8,6 +8,7 @@
*
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
/**************************************************************************/
@@ -131,8 +132,12 @@ extern "C" {
/* Define Storage Class constants. */
+#ifndef UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY
#define UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY (200)
+#endif
+#ifndef UX_HOST_CLASS_STORAGE_THREAD_SLEEP_TIME
#define UX_HOST_CLASS_STORAGE_THREAD_SLEEP_TIME (2000)
+#endif
#define UX_HOST_CLASS_STORAGE_INSTANCE_SHUTDOWN_TIMER (10)
#define UX_HOST_CLASS_STORAGE_THREAD_PRIORITY_CLASS 20
#define UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT 10000
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 bc808fdfa..72233f0fb 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
@@ -42,11 +42,9 @@
/* */
/* DESCRIPTION */
/* */
-/* This function is the callback from the USBX transfer functions, */
-/* 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. */
+/* DEPRECATED. The ASIX host class reception path has been redesigned; */
+/* this callback is no longer registered or invoked by the driver. */
+/* Do not call this function directly. */
/* */
/* INPUT */
/* */
diff --git a/common/usbx_host_classes/src/ux_host_class_hid_entry.c b/common/usbx_host_classes/src/ux_host_class_hid_entry.c
index d58b58e30..1027f91d5 100644
--- a/common/usbx_host_classes/src/ux_host_class_hid_entry.c
+++ b/common/usbx_host_classes/src/ux_host_class_hid_entry.c
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -358,7 +360,20 @@ UINT status = UX_SUCCESS;
{
/* Get one item from the report and analyze it. */
- _ux_host_class_hid_report_item_analyse(descriptor, length, &item);
+ status = _ux_host_class_hid_report_item_analyse(descriptor, length, &item);
+ if (status != UX_SUCCESS)
+ {
+
+ /* Error trap. */
+ _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
+
+ /* If trace is enabled, insert this event into the trace buffer. */
+ UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
+
+ /* Return error status. */
+ status = (UX_DESCRIPTOR_CORRUPTED);
+ break;
+ }
/* Point the descriptor right after the item identifier. */
descriptor += item.ux_host_class_hid_item_report_format;
@@ -406,8 +421,10 @@ UINT status = UX_SUCCESS;
/* Jump to the next item. */
descriptor += item.ux_host_class_hid_item_report_length;
- /* Verify that the report descriptor is not corrupted. */
- if (length < item.ux_host_class_hid_item_report_length)
+ /* Verify that the report descriptor is not corrupted. The header counts
+ as well as the data, or the subtraction below runs past zero. */
+ if (length < (ULONG)(item.ux_host_class_hid_item_report_length +
+ item.ux_host_class_hid_item_report_format))
{
/* Return error status. */
diff --git a/common/usbx_host_classes/src/ux_host_class_hid_report_descriptor_get.c b/common/usbx_host_classes/src/ux_host_class_hid_report_descriptor_get.c
index 5f383fbc7..f470a82fb 100644
--- a/common/usbx_host_classes/src/ux_host_class_hid_report_descriptor_get.c
+++ b/common/usbx_host_classes/src/ux_host_class_hid_report_descriptor_get.c
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -122,6 +124,7 @@ UINT status;
/* Return error status. */
status = (UX_DESCRIPTOR_CORRUPTED);
+ break;
}
/* Point the descriptor right after the item identifier. */
diff --git a/common/usbx_host_classes/src/ux_host_class_hid_report_item_analyse.c b/common/usbx_host_classes/src/ux_host_class_hid_report_item_analyse.c
index 8d60189ea..934959471 100644
--- a/common/usbx_host_classes/src/ux_host_class_hid_report_item_analyse.c
+++ b/common/usbx_host_classes/src/ux_host_class_hid_report_item_analyse.c
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -83,8 +85,9 @@ UINT result = UX_SUCCESS;
if ((item_byte & UX_HOST_CLASS_HID_ITEM_TAG_MASK) == UX_HOST_CLASS_HID_ITEM_TAG_LONG)
{
- /* We have a long item, mark its format. */
- item -> ux_host_class_hid_item_report_format = UX_HOST_CLASS_HID_ITEM_TAG_LONG;
+ /* We have a long item. Its header is the prefix, the data size and the
+ tag, and the format is what the walks advance by to clear it. */
+ item -> ux_host_class_hid_item_report_format = 3;
/* Set the type. */
item -> ux_host_class_hid_item_report_type = (item_byte >> 2) & 3;
@@ -135,6 +138,13 @@ UINT result = UX_SUCCESS;
}
+ /* Verify that the item header and its declared data fit within the remaining descriptor. */
+ if (length < ((ULONG) item -> ux_host_class_hid_item_report_length +
+ item -> ux_host_class_hid_item_report_format))
+ {
+ result = UX_DESCRIPTOR_CORRUPTED;
+ }
+
/* Return result. */
return(result);
}
diff --git a/common/usbx_host_classes/src/ux_host_class_pima_device_info_get.c b/common/usbx_host_classes/src/ux_host_class_pima_device_info_get.c
index b90429acd..945adbffd 100644
--- a/common/usbx_host_classes/src/ux_host_class_pima_device_info_get.c
+++ b/common/usbx_host_classes/src/ux_host_class_pima_device_info_get.c
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -74,6 +76,7 @@ UINT _ux_host_class_pima_device_info_get(UX_HOST_CLASS_PIMA *pima,
UX_HOST_CLASS_PIMA_COMMAND command;
UCHAR *device_buffer;
+UCHAR *device_buffer_end;
UCHAR *device_pointer;
ULONG unicode_string_length;
ULONG array_length = 0;
@@ -108,6 +111,9 @@ UINT status;
if (status == UX_SUCCESS)
{
+ /* Bound the source cursor against the buffer actually allocated/received. */
+ device_buffer_end = device_buffer + UX_HOST_CLASS_PIMA_DEVICE_MAX_LENGTH;
+
/* Read and store the Standard Version field (2). */
pima_device -> ux_host_class_pima_device_standard_version = _ux_utility_short_get(device_buffer +
UX_HOST_CLASS_PIMA_DEVICE_STANDARD_VERSION);
@@ -126,8 +132,9 @@ UINT status;
/* Get the unicode string length in chars. */
unicode_string_length = (ULONG) *device_pointer;
- /* Check if the string can fit in our buffer. */
- if (unicode_string_length > UX_HOST_CLASS_PIMA_UNICODE_MAX_LENGTH / 2)
+ /* Check if the string can fit in our buffer and in what was actually received. */
+ if ((unicode_string_length > UX_HOST_CLASS_PIMA_UNICODE_MAX_LENGTH / 2) ||
+ ((unicode_string_length << 1) + 1 > (ULONG) (device_buffer_end - device_pointer)))
/* Return error. */
status = UX_MEMORY_INSUFFICIENT;
@@ -142,6 +149,15 @@ UINT status;
/* Point to the next field. */
device_pointer += 1 + (unicode_string_length << 1);
+ /* Ensure the buffer still holds the Functional Mode (2) and next array length prefix (4). */
+ if ((ULONG) (device_buffer_end - device_pointer) < sizeof(USHORT) + sizeof(ULONG))
+ status = UX_MEMORY_INSUFFICIENT;
+ }
+
+ /* Is there enough space? */
+ if (status == UX_SUCCESS)
+ {
+
/* Read and store the Functional Mode (2). */
pima_device -> ux_host_class_pima_device_functional_mode = _ux_utility_short_get(device_pointer);
@@ -151,7 +167,8 @@ UINT status;
/* Get the number of elements in array and compute total length. */
array_length = _ux_utility_long_get(device_pointer);
- if (array_length > (UX_HOST_CLASS_PIMA_ARRAY_MAX_LENGTH - sizeof(ULONG)) / 2)
+ if ((array_length > (UX_HOST_CLASS_PIMA_ARRAY_MAX_LENGTH - sizeof(ULONG)) / 2) ||
+ ((array_length << 1) + sizeof(ULONG) > (ULONG) (device_buffer_end - device_pointer)))
status = UX_MEMORY_INSUFFICIENT;
else
{
@@ -170,14 +187,22 @@ UINT status;
/* Point to the next field (EventsSupported EventCode Array of 16-bit). */
device_pointer += array_length;
- /* Get the number of elements in array and compute total length. */
- array_length = _ux_utility_long_get(device_pointer);
- if (array_length > (UX_HOST_CLASS_PIMA_ARRAY_MAX_LENGTH - sizeof(ULONG)) / 2)
+ /* Ensure the buffer still holds the next array length prefix (4). */
+ if ((ULONG) (device_buffer_end - device_pointer) < sizeof(ULONG))
status = UX_MEMORY_INSUFFICIENT;
else
{
- array_length <<= 1;
- array_length += (ULONG)sizeof(ULONG);
+
+ /* Get the number of elements in array and compute total length. */
+ array_length = _ux_utility_long_get(device_pointer);
+ if ((array_length > (UX_HOST_CLASS_PIMA_ARRAY_MAX_LENGTH - sizeof(ULONG)) / 2) ||
+ ((array_length << 1) + sizeof(ULONG) > (ULONG) (device_buffer_end - device_pointer)))
+ status = UX_MEMORY_INSUFFICIENT;
+ else
+ {
+ array_length <<= 1;
+ array_length += (ULONG)sizeof(ULONG);
+ }
}
}
@@ -191,14 +216,22 @@ UINT status;
/* Point to the next field (DevicePropertiesSupported DevicePropCode Array of 16-bit). */
device_pointer += array_length;
- /* Get the number of elements in array and compute total length. */
- array_length = _ux_utility_long_get(device_pointer);
- if (array_length > (UX_HOST_CLASS_PIMA_ARRAY_MAX_LENGTH - sizeof(ULONG)) / 2)
+ /* Ensure the buffer still holds the next array length prefix (4). */
+ if ((ULONG) (device_buffer_end - device_pointer) < sizeof(ULONG))
status = UX_MEMORY_INSUFFICIENT;
else
{
- array_length <<= 1;
- array_length += (ULONG)sizeof(ULONG);
+
+ /* Get the number of elements in array and compute total length. */
+ array_length = _ux_utility_long_get(device_pointer);
+ if ((array_length > (UX_HOST_CLASS_PIMA_ARRAY_MAX_LENGTH - sizeof(ULONG)) / 2) ||
+ ((array_length << 1) + sizeof(ULONG) > (ULONG) (device_buffer_end - device_pointer)))
+ status = UX_MEMORY_INSUFFICIENT;
+ else
+ {
+ array_length <<= 1;
+ array_length += (ULONG)sizeof(ULONG);
+ }
}
}
@@ -212,14 +245,22 @@ UINT status;
/* Point to the next field (CaptureFormats ObjectFormatCode Array of 16-bit). */
device_pointer += array_length;
- /* Get the number of elements in array and compute total length. */
- array_length = _ux_utility_long_get(device_pointer);
- if (array_length > (UX_HOST_CLASS_PIMA_ARRAY_MAX_LENGTH - sizeof(ULONG)) / 2)
+ /* Ensure the buffer still holds the next array length prefix (4). */
+ if ((ULONG) (device_buffer_end - device_pointer) < sizeof(ULONG))
status = UX_MEMORY_INSUFFICIENT;
else
{
- array_length <<= 1;
- array_length += (ULONG)sizeof(ULONG);
+
+ /* Get the number of elements in array and compute total length. */
+ array_length = _ux_utility_long_get(device_pointer);
+ if ((array_length > (UX_HOST_CLASS_PIMA_ARRAY_MAX_LENGTH - sizeof(ULONG)) / 2) ||
+ ((array_length << 1) + sizeof(ULONG) > (ULONG) (device_buffer_end - device_pointer)))
+ status = UX_MEMORY_INSUFFICIENT;
+ else
+ {
+ array_length <<= 1;
+ array_length += (ULONG)sizeof(ULONG);
+ }
}
}
@@ -233,14 +274,22 @@ UINT status;
/* Point to the next field (ImageFormats ObjectFormatCode Array of 16-bit). */
device_pointer += array_length;
- /* Get the number of elements in array and compute total length. */
- array_length = _ux_utility_long_get(device_pointer);
- if (array_length > (UX_HOST_CLASS_PIMA_ARRAY_MAX_LENGTH - sizeof(ULONG)) / 2)
+ /* Ensure the buffer still holds the next array length prefix (4). */
+ if ((ULONG) (device_buffer_end - device_pointer) < sizeof(ULONG))
status = UX_MEMORY_INSUFFICIENT;
else
{
- array_length <<= 1;
- array_length += (ULONG)sizeof(ULONG);
+
+ /* Get the number of elements in array and compute total length. */
+ array_length = _ux_utility_long_get(device_pointer);
+ if ((array_length > (UX_HOST_CLASS_PIMA_ARRAY_MAX_LENGTH - sizeof(ULONG)) / 2) ||
+ ((array_length << 1) + sizeof(ULONG) > (ULONG) (device_buffer_end - device_pointer)))
+ status = UX_MEMORY_INSUFFICIENT;
+ else
+ {
+ array_length <<= 1;
+ array_length += (ULONG)sizeof(ULONG);
+ }
}
}
@@ -254,14 +303,22 @@ UINT status;
/* Point to the next field (Manufacturer String). */
device_pointer += array_length;
- /* Get the unicode string length. */
- unicode_string_length = (ULONG) *device_pointer;
+ /* Ensure the buffer still holds the next string length prefix (1). */
+ if ((ULONG) (device_buffer_end - device_pointer) < 1)
+ status = UX_MEMORY_INSUFFICIENT;
+ else
+ {
+
+ /* Get the unicode string length. */
+ unicode_string_length = (ULONG) *device_pointer;
- /* Ensure the string can fit in our buffer. */
- if (unicode_string_length > UX_HOST_CLASS_PIMA_UNICODE_MAX_LENGTH / 2)
+ /* Ensure the string can fit in our buffer and in what was actually received. */
+ if ((unicode_string_length > UX_HOST_CLASS_PIMA_UNICODE_MAX_LENGTH / 2) ||
+ ((unicode_string_length << 1) + 1 > (ULONG) (device_buffer_end - device_pointer)))
- /* Return overflow error. */
- status = UX_MEMORY_INSUFFICIENT;
+ /* Return overflow error. */
+ status = UX_MEMORY_INSUFFICIENT;
+ }
}
/* Is there enough space? */
@@ -274,14 +331,22 @@ UINT status;
/* Point to the next field (Model String). */
device_pointer += (unicode_string_length << 1) + 1;
- /* Get the unicode string length. */
- unicode_string_length = (ULONG) *device_pointer ;
+ /* Ensure the buffer still holds the next string length prefix (1). */
+ if ((ULONG) (device_buffer_end - device_pointer) < 1)
+ status = UX_MEMORY_INSUFFICIENT;
+ else
+ {
+
+ /* Get the unicode string length. */
+ unicode_string_length = (ULONG) *device_pointer ;
- /* Ensure the string can fit in our buffer. */
- if (unicode_string_length > UX_HOST_CLASS_PIMA_DATE_TIME_STRING_MAX_LENGTH / 2)
+ /* Ensure the string can fit in our buffer and in what was actually received. */
+ if ((unicode_string_length > UX_HOST_CLASS_PIMA_DATE_TIME_STRING_MAX_LENGTH / 2) ||
+ ((unicode_string_length << 1) + 1 > (ULONG) (device_buffer_end - device_pointer)))
- /* Return overflow error. */
- status = UX_MEMORY_INSUFFICIENT;
+ /* Return overflow error. */
+ status = UX_MEMORY_INSUFFICIENT;
+ }
}
/* Is there enough space? */
@@ -294,14 +359,22 @@ UINT status;
/* Point to the next field (DeviceVersion String). */
device_pointer += (unicode_string_length << 1) + 1;
- /* Get the unicode string length. */
- unicode_string_length = (ULONG) *device_pointer ;
+ /* Ensure the buffer still holds the next string length prefix (1). */
+ if ((ULONG) (device_buffer_end - device_pointer) < 1)
+ status = UX_MEMORY_INSUFFICIENT;
+ else
+ {
+
+ /* Get the unicode string length. */
+ unicode_string_length = (ULONG) *device_pointer ;
- /* Ensure the string can fit in our buffer. */
- if (unicode_string_length > UX_HOST_CLASS_PIMA_DATE_TIME_STRING_MAX_LENGTH / 2)
+ /* Ensure the string can fit in our buffer and in what was actually received. */
+ if ((unicode_string_length > UX_HOST_CLASS_PIMA_DATE_TIME_STRING_MAX_LENGTH / 2) ||
+ ((unicode_string_length << 1) + 1 > (ULONG) (device_buffer_end - device_pointer)))
- /* Return overflow error. */
- status = UX_MEMORY_INSUFFICIENT;
+ /* Return overflow error. */
+ status = UX_MEMORY_INSUFFICIENT;
+ }
}
/* Is there enough space? */
@@ -314,14 +387,22 @@ UINT status;
/* Point to the next field (SerialNumber String). */
device_pointer += (unicode_string_length << 1) + 1;
- /* Get the unicode string length. */
- unicode_string_length = (ULONG) *device_pointer ;
+ /* Ensure the buffer still holds the next string length prefix (1). */
+ if ((ULONG) (device_buffer_end - device_pointer) < 1)
+ status = UX_MEMORY_INSUFFICIENT;
+ else
+ {
+
+ /* Get the unicode string length. */
+ unicode_string_length = (ULONG) *device_pointer ;
- /* Ensure the string can fit in our buffer. */
- if (unicode_string_length > UX_HOST_CLASS_PIMA_UNICODE_MAX_LENGTH / 2)
+ /* Ensure the string can fit in our buffer and in what was actually received. */
+ if ((unicode_string_length > UX_HOST_CLASS_PIMA_UNICODE_MAX_LENGTH / 2) ||
+ ((unicode_string_length << 1) + 1 > (ULONG) (device_buffer_end - device_pointer)))
- /* Return overflow error. */
- status = UX_MEMORY_INSUFFICIENT;
+ /* Return overflow error. */
+ status = UX_MEMORY_INSUFFICIENT;
+ }
}
/* Is there enough space? */
diff --git a/common/usbx_host_classes/src/ux_host_class_pima_num_objects_get.c b/common/usbx_host_classes/src/ux_host_class_pima_num_objects_get.c
index f58a0a8c1..b3ffab70f 100644
--- a/common/usbx_host_classes/src/ux_host_class_pima_num_objects_get.c
+++ b/common/usbx_host_classes/src/ux_host_class_pima_num_objects_get.c
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -161,4 +163,4 @@ UINT _uxe_host_class_pima_num_objects_get(UX_HOST_CLASS_PIMA *pima,
/* Call the actual pima num objects get function. */
return(_ux_host_class_pima_num_objects_get(pima, pima_session, storage_id, object_format_code));
-}
\ No newline at end of file
+}
diff --git a/common/usbx_host_classes/src/ux_host_class_pima_object_handles_get.c b/common/usbx_host_classes/src/ux_host_class_pima_object_handles_get.c
index 950c299ab..0b183338d 100644
--- a/common/usbx_host_classes/src/ux_host_class_pima_object_handles_get.c
+++ b/common/usbx_host_classes/src/ux_host_class_pima_object_handles_get.c
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -144,14 +146,19 @@ UINT status;
/* Read the number of Object handles in the returned array. */
nb_object_handles = _ux_utility_long_get(object_handles_array_raw);
- /* Save the number of object handles. */
- pima_session -> ux_host_class_pima_session_nb_objects = nb_object_handles;
-
- /* Check if the user gave us enough memory. */
- if (nb_object_handles > object_handles_length)
+ /* The buffer was sized from the count the session already held, so a device
+ returning more handles than that is reporting handles it never sent. */
+ if (nb_object_handles > ((object_handle_length_raw / (ULONG)sizeof(ULONG)) - 1))
+ {
- /* No, not enough memory to store the array. */
+ /* Not enough memory to store the array. */
+ _ux_utility_memory_free(object_handles_array_raw);
return(UX_MEMORY_INSUFFICIENT);
+ }
+
+ /* Save the number of object handles. The caller's array was already measured
+ against the session count, which now bounds this one, so it holds them all. */
+ pima_session -> ux_host_class_pima_session_nb_objects = nb_object_handles;
/* Unpack all object handles. */
for(count_object_handles = 0; count_object_handles < nb_object_handles; count_object_handles++)
@@ -221,4 +228,4 @@ UINT _uxe_host_class_pima_object_handles_get(UX_HOST_CLASS_PIMA *pima, UX_HOST_
/* Call the actual function. */
return(_ux_host_class_pima_object_handles_get(pima, pima_session, object_handles_array, object_handles_length,
storage_id, object_format_code, object_handle_association));
-}
\ No newline at end of file
+}
diff --git a/common/usbx_host_classes/src/ux_host_class_pima_object_info_get.c b/common/usbx_host_classes/src/ux_host_class_pima_object_info_get.c
index a7610fa40..5f5b3e10d 100644
--- a/common/usbx_host_classes/src/ux_host_class_pima_object_info_get.c
+++ b/common/usbx_host_classes/src/ux_host_class_pima_object_info_get.c
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -75,6 +77,7 @@ UINT _ux_host_class_pima_object_info_get(UX_HOST_CLASS_PIMA *pima,
UX_HOST_CLASS_PIMA_COMMAND command;
UCHAR *object_buffer;
+UCHAR *object_buffer_end;
UCHAR *object_pointer;
ULONG unicode_string_length;
UINT status;
@@ -126,11 +129,15 @@ UINT status;
/* Copy the object filename field. Point to the beginning of the object description string. */
object_pointer = object_buffer + UX_HOST_CLASS_PIMA_OBJECT_VARIABLE_OFFSET;
+ /* Bound the source cursor against the buffer actually allocated/received. */
+ object_buffer_end = object_buffer + UX_HOST_CLASS_PIMA_OBJECT_MAX_LENGTH;
+
/* Get the unicode string length. */
unicode_string_length = ((ULONG) *object_pointer * 2) + 1;
- /* Check if string can fit in our buffer. */
- if (unicode_string_length > UX_HOST_CLASS_PIMA_UNICODE_MAX_LENGTH)
+ /* Check if string can fit in our buffer and in what was actually received. */
+ if ((unicode_string_length > UX_HOST_CLASS_PIMA_UNICODE_MAX_LENGTH) ||
+ (unicode_string_length > (ULONG) (object_buffer_end - object_pointer)))
/* Return error. */
status = UX_MEMORY_INSUFFICIENT;
@@ -145,14 +152,22 @@ UINT status;
/* Point to the next field. */
object_pointer += unicode_string_length;
- /* Get the unicode string length. */
- unicode_string_length = ((ULONG) *object_pointer * 2) + 1;
+ /* Ensure a length prefix byte remains in the received buffer. */
+ if ((ULONG) (object_buffer_end - object_pointer) < 1)
+ status = UX_MEMORY_INSUFFICIENT;
+ else
+ {
+
+ /* Get the unicode string length. */
+ unicode_string_length = ((ULONG) *object_pointer * 2) + 1;
- /* Ensure the string can fit in our buffer. */
- if (unicode_string_length > UX_HOST_CLASS_PIMA_DATE_TIME_STRING_MAX_LENGTH)
+ /* Ensure the string can fit in our buffer and in what was actually received. */
+ if ((unicode_string_length > UX_HOST_CLASS_PIMA_DATE_TIME_STRING_MAX_LENGTH) ||
+ (unicode_string_length > (ULONG) (object_buffer_end - object_pointer)))
- /* Return error. */
- status = UX_MEMORY_INSUFFICIENT;
+ /* Return error. */
+ status = UX_MEMORY_INSUFFICIENT;
+ }
}
/* Is there enough space? */
@@ -165,14 +180,22 @@ UINT status;
/* Point to the next field. */
object_pointer += unicode_string_length;
- /* Get the unicode string length. */
- unicode_string_length = ((ULONG) *object_pointer * 2) + 1;
+ /* Ensure a length prefix byte remains in the received buffer. */
+ if ((ULONG) (object_buffer_end - object_pointer) < 1)
+ status = UX_MEMORY_INSUFFICIENT;
+ else
+ {
- /* Ensure the string can fit in our buffer. */
- if (unicode_string_length > UX_HOST_CLASS_PIMA_DATE_TIME_STRING_MAX_LENGTH)
+ /* Get the unicode string length. */
+ unicode_string_length = ((ULONG) *object_pointer * 2) + 1;
- /* Return error. */
- status = UX_MEMORY_INSUFFICIENT;
+ /* Ensure the string can fit in our buffer and in what was actually received. */
+ if ((unicode_string_length > UX_HOST_CLASS_PIMA_DATE_TIME_STRING_MAX_LENGTH) ||
+ (unicode_string_length > (ULONG) (object_buffer_end - object_pointer)))
+
+ /* Return error. */
+ status = UX_MEMORY_INSUFFICIENT;
+ }
}
/* Is there enough space? */
@@ -185,14 +208,22 @@ UINT status;
/* Point to the next field. */
object_pointer += unicode_string_length;
- /* Get the unicode string length. */
- unicode_string_length = ((ULONG) *object_pointer * 2) + 1;
+ /* Ensure a length prefix byte remains in the received buffer. */
+ if ((ULONG) (object_buffer_end - object_pointer) < 1)
+ status = UX_MEMORY_INSUFFICIENT;
+ else
+ {
+
+ /* Get the unicode string length. */
+ unicode_string_length = ((ULONG) *object_pointer * 2) + 1;
- /* Ensure the string can fit in our buffer. */
- if (unicode_string_length > UX_HOST_CLASS_PIMA_UNICODE_MAX_LENGTH)
+ /* Ensure the string can fit in our buffer and in what was actually received. */
+ if ((unicode_string_length > UX_HOST_CLASS_PIMA_UNICODE_MAX_LENGTH) ||
+ (unicode_string_length > (ULONG) (object_buffer_end - object_pointer)))
- /* Return error. */
- status = UX_MEMORY_INSUFFICIENT;
+ /* Return error. */
+ status = UX_MEMORY_INSUFFICIENT;
+ }
}
/* Is there enough space? */
@@ -271,4 +302,4 @@ UINT _uxe_host_class_pima_object_info_get(UX_HOST_CLASS_PIMA *pima,
/* Call the actual pima object info get function. */
return(_ux_host_class_pima_object_info_get(pima, pima_session, object_handle, object));
-}
\ No newline at end of file
+}
diff --git a/common/usbx_host_classes/src/ux_host_class_pima_storage_info_get.c b/common/usbx_host_classes/src/ux_host_class_pima_storage_info_get.c
index 94620d33f..5c3b389df 100644
--- a/common/usbx_host_classes/src/ux_host_class_pima_storage_info_get.c
+++ b/common/usbx_host_classes/src/ux_host_class_pima_storage_info_get.c
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -76,6 +78,7 @@ UINT _ux_host_class_pima_storage_info_get(UX_HOST_CLASS_PIMA *pima,
UX_HOST_CLASS_PIMA_COMMAND command;
UINT status;
UCHAR *storage_buffer;
+UCHAR *storage_buffer_end;
UCHAR *storage_pointer;
ULONG unicode_string_length, unicode_string_bytes;
@@ -107,7 +110,7 @@ ULONG unicode_string_length, unicode_string_bytes
/* Allocate some DMA safe memory for receiving the storage info block. */
storage_buffer = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_PIMA_STORAGE_MAX_LENGTH);
- if (storage == UX_NULL)
+ if (storage_buffer == UX_NULL)
return(UX_MEMORY_INSUFFICIENT);
/* Issue the command. */
@@ -123,6 +126,9 @@ ULONG unicode_string_length, unicode_string_bytes
UX_HOST_CLASS_PIMA_OBJECT_ENTRIES,
(UCHAR *) storage);
+ /* Bound the source cursor against the buffer actually allocated/received. */
+ storage_buffer_end = storage_buffer + UX_HOST_CLASS_PIMA_STORAGE_MAX_LENGTH;
+
/* Copy the storage description field. Point to the beginning of the storage description string. */
storage_pointer = storage_buffer + UX_HOST_CLASS_PIMA_STORAGE_VARIABLE_OFFSET;
@@ -133,8 +139,9 @@ ULONG unicode_string_length, unicode_string_bytes
unicode_string_length * 2 + 1 will not overflow. */
unicode_string_bytes = (unicode_string_length << 1) + 1;
- /* Check target buffer length. */
- if (unicode_string_bytes > UX_HOST_CLASS_PIMA_UNICODE_MAX_LENGTH)
+ /* Check target buffer length and that the bytes are actually available in what was received. */
+ if ((unicode_string_bytes > UX_HOST_CLASS_PIMA_UNICODE_MAX_LENGTH) ||
+ (unicode_string_bytes > (ULONG) (storage_buffer_end - storage_pointer)))
{
_ux_utility_memory_free(storage_buffer);
return(UX_BUFFER_OVERFLOW);
@@ -148,6 +155,13 @@ ULONG unicode_string_length, unicode_string_bytes
/* Point to the volume label. */
storage_pointer = storage_buffer + UX_HOST_CLASS_PIMA_STORAGE_VARIABLE_OFFSET + unicode_string_bytes;
+ /* Ensure a length prefix byte remains in the received buffer. */
+ if ((ULONG) (storage_buffer_end - storage_pointer) < 1)
+ {
+ _ux_utility_memory_free(storage_buffer);
+ return(UX_BUFFER_OVERFLOW);
+ }
+
/* Get the unicode string length. */
unicode_string_length = (ULONG) *storage_pointer ;
@@ -155,8 +169,9 @@ ULONG unicode_string_length, unicode_string_bytes
unicode_string_length * 2 + 1 will not overflow. */
unicode_string_bytes = (unicode_string_length << 1) + 1;
- /* Check target buffer length. */
- if (unicode_string_bytes > UX_HOST_CLASS_PIMA_UNICODE_MAX_LENGTH)
+ /* Check target buffer length and that the bytes are actually available in what was received. */
+ if ((unicode_string_bytes > UX_HOST_CLASS_PIMA_UNICODE_MAX_LENGTH) ||
+ (unicode_string_bytes > (ULONG) (storage_buffer_end - storage_pointer)))
{
_ux_utility_memory_free(storage_buffer);
return(UX_BUFFER_OVERFLOW);
@@ -222,4 +237,4 @@ UINT _uxe_host_class_pima_storage_info_get(UX_HOST_CLASS_PIMA *pima,
/* Call the actual pima storage info get function. */
return(_ux_host_class_pima_storage_info_get(pima, pima_session, storage_id, storage));
-}
\ No newline at end of file
+}
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 989e0c0c9..8b84a25dd 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
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -154,8 +156,14 @@ UCHAR *baInterfaceNr;
/* Get the number of formats. */
video -> ux_host_class_video_number_formats = packed_entity_descriptor[3];
- /* Get the length of formats. */
+ /* Get the length of formats and verify it fits in the configuration buffer. */
video -> ux_host_class_video_length_formats = _ux_utility_short_get(packed_entity_descriptor + 4);
+ if (video -> ux_host_class_video_length_formats >
+ (ULONG)(video -> ux_host_class_video_configuration_descriptor_length -
+ (ULONG)(packed_entity_descriptor - video -> ux_host_class_video_configuration_descriptor)))
+ {
+ return(UX_DESCRIPTOR_CORRUPTED);
+ }
/* Save the descriptor where the formats reside. */
video -> ux_host_class_video_format_address = packed_entity_descriptor;
@@ -263,7 +271,8 @@ UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER parser;
video -> ux_host_class_video_control_interface_number = 0xFF;
status = _ux_host_class_video_entities_parse(video,
_ux_host_class_video_descriptors_parser, (VOID *)&parser);
- if (parser.parsed_flags != UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER_DONE)
+ if ((status == UX_SUCCESS) &&
+ (parser.parsed_flags != UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER_DONE))
/* Some of expected descriptors not found. */
status = UX_HOST_CLASS_VIDEO_WRONG_TYPE;
diff --git a/common/usbx_host_classes/src/ux_host_class_video_entities_parse.c b/common/usbx_host_classes/src/ux_host_class_video_entities_parse.c
index bf252f39b..fe490d7cd 100644
--- a/common/usbx_host_classes/src/ux_host_class_video_entities_parse.c
+++ b/common/usbx_host_classes/src/ux_host_class_video_entities_parse.c
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -154,9 +156,17 @@ UINT status;
/* Yes, parse the entity descriptor. */
status = parse_function(arg, interface_descriptor, descriptor);
- /* Terminate the parsing if status is not 0. */
+ /* A corrupted descriptor fails the parse; any other non-zero
+ status just stops it early. */
+ if (status == UX_DESCRIPTOR_CORRUPTED)
+ {
+ return(UX_DESCRIPTOR_CORRUPTED);
+ }
+
if (status)
+ {
return(UX_SUCCESS);
+ }
}
break;
}
diff --git a/common/usbx_host_classes/src/ux_host_class_video_format_data_get.c b/common/usbx_host_classes/src/ux_host_class_video_format_data_get.c
index dc6d1174f..e366211a8 100644
--- a/common/usbx_host_classes/src/ux_host_class_video_format_data_get.c
+++ b/common/usbx_host_classes/src/ux_host_class_video_format_data_get.c
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -76,6 +78,13 @@ UCHAR *guid;
/* Get the descriptor to the selected format. */
descriptor = video -> ux_host_class_video_format_address;
total_descriptor_length = video -> ux_host_class_video_length_formats;
+ if (total_descriptor_length > (ULONG)(video -> ux_host_class_video_configuration_descriptor +
+ video -> ux_host_class_video_configuration_descriptor_length - descriptor))
+ {
+ _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
+ UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
+ return(UX_DESCRIPTOR_CORRUPTED);
+ }
/* Descriptors are arranged in order. First FORMAT then FRAME. */
while (total_descriptor_length)
diff --git a/common/usbx_host_classes/src/ux_host_class_video_frame_data_get.c b/common/usbx_host_classes/src/ux_host_class_video_frame_data_get.c
index 97c1f921b..9618a4356 100644
--- a/common/usbx_host_classes/src/ux_host_class_video_frame_data_get.c
+++ b/common/usbx_host_classes/src/ux_host_class_video_frame_data_get.c
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -91,11 +93,41 @@ ULONG descriptor_length;
ULONG descriptor_type;
ULONG descriptor_subtype;
UCHAR *field_offsets;
+ULONG format_offset;
/* Get the descriptor to the selected format. */
descriptor = video -> ux_host_class_video_current_format_address;
- total_descriptor_length = video -> ux_host_class_video_length_formats;
+
+ /* The formats length is counted from the input header, so the walk that starts
+ at the current format only owns what is left of the block behind it. */
+ format_offset = (ULONG)(descriptor - video -> ux_host_class_video_format_address);
+ if (format_offset > video -> ux_host_class_video_length_formats)
+ {
+
+ /* Error trap. */
+ _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
+
+ /* If trace is enabled, insert this event into the trace buffer. */
+ UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
+
+ return(UX_DESCRIPTOR_CORRUPTED);
+ }
+ total_descriptor_length = video -> ux_host_class_video_length_formats - format_offset;
+
+ /* That block is device reported, so hold it to the configuration buffer too. */
+ if (total_descriptor_length > (ULONG)(video -> ux_host_class_video_configuration_descriptor +
+ video -> ux_host_class_video_configuration_descriptor_length - descriptor))
+ {
+
+ /* Error trap. */
+ _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
+
+ /* If trace is enabled, insert this event into the trace buffer. */
+ UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
+
+ return(UX_DESCRIPTOR_CORRUPTED);
+ }
/* Descriptors are arranged in order. First FORMAT then FRAME. */
while (total_descriptor_length)
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
index 21d936a2a..53283063c 100644
--- 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
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -75,10 +77,40 @@ ULONG descriptor_type;
ULONG descriptor_subtype;
ULONG intervals_to_copy;
ULONG i;
+ULONG format_offset;
/* Get the descriptor to the selected format. */
descriptor = video -> ux_host_class_video_current_format_address;
- total_descriptor_length = video -> ux_host_class_video_length_formats;
+
+ /* The formats length is counted from the input header, so the walk that starts
+ at the current format only owns what is left of the block behind it. */
+ format_offset = (ULONG)(descriptor - video -> ux_host_class_video_format_address);
+ if (format_offset > video -> ux_host_class_video_length_formats)
+ {
+
+ /* Error trap. */
+ _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
+
+ /* If trace is enabled, insert this event into the trace buffer. */
+ UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
+
+ return(UX_DESCRIPTOR_CORRUPTED);
+ }
+ total_descriptor_length = video -> ux_host_class_video_length_formats - format_offset;
+
+ /* That block is device reported, so hold it to the configuration buffer too. */
+ if (total_descriptor_length > (ULONG)(video -> ux_host_class_video_configuration_descriptor +
+ video -> ux_host_class_video_configuration_descriptor_length - descriptor))
+ {
+
+ /* Error trap. */
+ _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
+
+ /* If trace is enabled, insert this event into the trace buffer. */
+ UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
+
+ return(UX_DESCRIPTOR_CORRUPTED);
+ }
/* Descriptors are arranged in order. First FORMAT then FRAME. */
while (total_descriptor_length)
diff --git a/common/usbx_host_classes/src/ux_host_class_video_input_format_get.c b/common/usbx_host_classes/src/ux_host_class_video_input_format_get.c
index 7d34f399f..91d7bff90 100644
--- a/common/usbx_host_classes/src/ux_host_class_video_input_format_get.c
+++ b/common/usbx_host_classes/src/ux_host_class_video_input_format_get.c
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -151,8 +153,15 @@ ULONG descriptor_found;
/* Get the number of formats. */
video -> ux_host_class_video_number_formats = input_header_descriptor.bNumFormats;
- /* Get the length of formats. */
+ /* Get the length of formats and verify it fits in the configuration buffer. */
video -> ux_host_class_video_length_formats = input_header_descriptor.wTotalLength;
+ if (video -> ux_host_class_video_length_formats >
+ (ULONG)(video -> ux_host_class_video_configuration_descriptor_length -
+ (ULONG)(descriptor - video -> ux_host_class_video_configuration_descriptor)))
+ {
+ _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
+ return(UX_DESCRIPTOR_CORRUPTED);
+ }
/* Save the descriptor where the formats reside. */
video -> ux_host_class_video_format_address = descriptor;
diff --git a/ports/arm9/gnu/inc/ux_port.h b/ports/arm9/gnu/inc/ux_port.h
index b81411e58..2964e5499 100644
--- a/ports/arm9/gnu/inc/ux_port.h
+++ b/ports/arm9/gnu/inc/ux_port.h
@@ -244,7 +244,7 @@ VOID outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX ARM9/GNU Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX ARM9/GNU Version 6.5.2.202603 *";
#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 8f4e3908a..45654eabc 100644
--- a/ports/arm9/iar/inc/ux_port.h
+++ b/ports/arm9/iar/inc/ux_port.h
@@ -251,7 +251,7 @@ VOID outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX ARM9/IAR Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX ARM9/IAR Version 6.5.2.202603 *";
#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 62d820620..b1de22102 100644
--- a/ports/cortex_a15/gnu/inc/ux_port.h
+++ b/ports/cortex_a15/gnu/inc/ux_port.h
@@ -240,7 +240,7 @@ VOID outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-A15/GNU Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-A15/GNU Version 6.5.2.202603 *";
#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 efb2fae3c..357b56f79 100644
--- a/ports/cortex_a5/gnu/inc/ux_port.h
+++ b/ports/cortex_a5/gnu/inc/ux_port.h
@@ -247,7 +247,7 @@ VOID outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-A5/GNU Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-A5/GNU Version 6.5.2.202603 *";
#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 dbc319278..7199975de 100644
--- a/ports/cortex_a5/iar/inc/ux_port.h
+++ b/ports/cortex_a5/iar/inc/ux_port.h
@@ -247,7 +247,7 @@ VOID outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-A5/IAR Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-A5/IAR Version 6.5.2.202603 *";
#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 ffd35f64f..e307e5b79 100644
--- a/ports/cortex_a5x/ac6/inc/ux_port.h
+++ b/ports/cortex_a5x/ac6/inc/ux_port.h
@@ -264,7 +264,7 @@ VOID outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-A5x/AC6 Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-A5x/AC6 Version 6.5.2.202603 *";
#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 4a5516384..e00417ba9 100644
--- a/ports/cortex_a7/gnu/inc/ux_port.h
+++ b/ports/cortex_a7/gnu/inc/ux_port.h
@@ -251,7 +251,7 @@ VOID outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-A7/GNU Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-A7/GNU Version 6.5.2.202603 *";
#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 1f51308ad..e360ce5f2 100644
--- a/ports/cortex_a7/iar/inc/ux_port.h
+++ b/ports/cortex_a7/iar/inc/ux_port.h
@@ -251,7 +251,7 @@ VOID outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-A7/IAR Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-A7/IAR Version 6.5.2.202603 *";
#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 77cc4dd6d..0435e14ca 100644
--- a/ports/cortex_a8/gnu/inc/ux_port.h
+++ b/ports/cortex_a8/gnu/inc/ux_port.h
@@ -247,7 +247,7 @@ VOID outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-A8/GNU Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-A8/GNU Version 6.5.2.202603 *";
#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 b4b27198f..53b4619a3 100644
--- a/ports/cortex_a8/iar/inc/ux_port.h
+++ b/ports/cortex_a8/iar/inc/ux_port.h
@@ -247,7 +247,7 @@ VOID outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-A8/IAR Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-A8/IAR Version 6.5.2.202603 *";
#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 e58a859c2..e9c633f8a 100644
--- a/ports/cortex_a9/gnu/inc/ux_port.h
+++ b/ports/cortex_a9/gnu/inc/ux_port.h
@@ -247,7 +247,7 @@ VOID outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX ARM9/GNU Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX ARM9/GNU Version 6.5.2.202603 *";
#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 9e0fe2f0a..63e838eb5 100644
--- a/ports/cortex_a9/iar/inc/ux_port.h
+++ b/ports/cortex_a9/iar/inc/ux_port.h
@@ -247,7 +247,7 @@ VOID outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX ARM9/IAR Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX ARM9/IAR Version 6.5.2.202603 *";
#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 d7d6fadc7..0e9f40fa7 100644
--- a/ports/cortex_m0/gnu/inc/ux_port.h
+++ b/ports/cortex_m0/gnu/inc/ux_port.h
@@ -243,7 +243,7 @@ VOID outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-M0/GNU Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-M0/GNU Version 6.5.2.202603 *";
#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 5a404a11f..8c5e70f19 100644
--- a/ports/cortex_m0/iar/inc/ux_port.h
+++ b/ports/cortex_m0/iar/inc/ux_port.h
@@ -247,7 +247,7 @@ VOID outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-M0/IAR Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-M0/IAR Version 6.5.2.202603 *";
#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 61f33e271..7b743a470 100644
--- a/ports/cortex_m3/gnu/inc/ux_port.h
+++ b/ports/cortex_m3/gnu/inc/ux_port.h
@@ -243,7 +243,7 @@ VOID outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-M3/GNU Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-M3/GNU Version 6.5.2.202603 *";
#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 66269b7e6..05c711e4f 100644
--- a/ports/cortex_m3/iar/inc/ux_port.h
+++ b/ports/cortex_m3/iar/inc/ux_port.h
@@ -245,7 +245,7 @@ VOID outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-M3/IAR Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-M3/IAR Version 6.5.2.202603 *";
#else
extern CHAR _ux_version_id[];
#endif
diff --git a/ports/cortex_m33/gnu/inc/ux_port.h b/ports/cortex_m33/gnu/inc/ux_port.h
index 44fc730b1..2cf344f8f 100644
--- a/ports/cortex_m33/gnu/inc/ux_port.h
+++ b/ports/cortex_m33/gnu/inc/ux_port.h
@@ -243,7 +243,7 @@ VOID outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-M33/GNU Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-M33/GNU Version 6.5.2.202603 *";
#else
extern CHAR _ux_version_id[];
#endif
diff --git a/ports/cortex_m33/iar/inc/ux_port.h b/ports/cortex_m33/iar/inc/ux_port.h
index d6a9a1bf3..c05b96c0a 100644
--- a/ports/cortex_m33/iar/inc/ux_port.h
+++ b/ports/cortex_m33/iar/inc/ux_port.h
@@ -247,7 +247,7 @@ VOID outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-M33/IAR Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-M33/IAR Version 6.5.2.202603 *";
#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 812e2a731..2725bdbf8 100644
--- a/ports/cortex_m4/gnu/inc/ux_port.h
+++ b/ports/cortex_m4/gnu/inc/ux_port.h
@@ -243,7 +243,7 @@ VOID outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-M4/GNU Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-M4/GNU Version 6.5.2.202603 *";
#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 7b29625a6..bbda592c2 100644
--- a/ports/cortex_m4/iar/inc/ux_port.h
+++ b/ports/cortex_m4/iar/inc/ux_port.h
@@ -247,7 +247,7 @@ VOID outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-M4/IAR Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-M4/IAR Version 6.5.2.202603 *";
#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 907feafcc..11e2cda24 100644
--- a/ports/cortex_m7/gnu/inc/ux_port.h
+++ b/ports/cortex_m7/gnu/inc/ux_port.h
@@ -243,7 +243,7 @@ VOID outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-M7/GNU Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-M7/GNU Version 6.5.2.202603 *";
#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 426ea2c57..2e891ac0f 100644
--- a/ports/cortex_m7/iar/inc/ux_port.h
+++ b/ports/cortex_m7/iar/inc/ux_port.h
@@ -247,7 +247,7 @@ VOID outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-M7/IAR Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-M7/IAR Version 6.5.2.202603 *";
#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 5f6804a04..4e74f07e2 100644
--- a/ports/cortex_r4/gnu/inc/ux_port.h
+++ b/ports/cortex_r4/gnu/inc/ux_port.h
@@ -244,7 +244,7 @@ VOID outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-R4/GNU Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-R4/GNU Version 6.5.2.202603 *";
#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 49c80aff4..5f626746d 100644
--- a/ports/cortex_r4/iar/inc/ux_port.h
+++ b/ports/cortex_r4/iar/inc/ux_port.h
@@ -247,7 +247,7 @@ VOID outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-R4/IAR Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-R4/IAR Version 6.5.2.202603 *";
#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 c812916f0..28887def3 100644
--- a/ports/cortex_r5/gnu/inc/ux_port.h
+++ b/ports/cortex_r5/gnu/inc/ux_port.h
@@ -246,7 +246,7 @@ VOID outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-R5/GNU Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-R5/GNU Version 6.5.2.202603 *";
#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 9cb3c8fdc..add8bbd12 100644
--- a/ports/cortex_r5/iar/inc/ux_port.h
+++ b/ports/cortex_r5/iar/inc/ux_port.h
@@ -248,7 +248,7 @@ VOID outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-R5/IAR Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Cortex-R5/IAR Version 6.5.2.202603 *";
#else
extern CHAR _ux_version_id[];
#endif
diff --git a/ports/generic/inc/ux_port.h b/ports/generic/inc/ux_port.h
index b5fc50354..9180a6f02 100644
--- a/ports/generic/inc/ux_port.h
+++ b/ports/generic/inc/ux_port.h
@@ -247,7 +247,7 @@ VOID outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Generic Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Generic Version 6.5.2.202603 *";
#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 8045a3116..6b9ee665b 100644
--- a/ports/linux/gnu/inc/ux_port.h
+++ b/ports/linux/gnu/inc/ux_port.h
@@ -249,7 +249,7 @@ ULONG outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Linux/GNU Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX Linux/GNU Version 6.5.2.202603 *";
#else
extern CHAR _ux_version_id[];
#endif
diff --git a/ports/rxv1/gnu/inc/ux_port.h b/ports/rxv1/gnu/inc/ux_port.h
index e6fb74eea..cbc64187a 100644
--- a/ports/rxv1/gnu/inc/ux_port.h
+++ b/ports/rxv1/gnu/inc/ux_port.h
@@ -239,7 +239,7 @@ VOID outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX RXv1/GNU Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX RXv1/GNU Version 6.5.2.202603 *";
#else
extern CHAR _ux_version_id[];
#endif
diff --git a/ports/rxv2/gnu/inc/ux_port.h b/ports/rxv2/gnu/inc/ux_port.h
index 4cfae9900..f5e10d727 100644
--- a/ports/rxv2/gnu/inc/ux_port.h
+++ b/ports/rxv2/gnu/inc/ux_port.h
@@ -239,7 +239,7 @@ VOID outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX RXv2/GNU Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX RXv2/GNU Version 6.5.2.202603 *";
#else
extern CHAR _ux_version_id[];
#endif
diff --git a/ports/rxv3/gnu/inc/ux_port.h b/ports/rxv3/gnu/inc/ux_port.h
index fe8294e2b..5c67aea97 100644
--- a/ports/rxv3/gnu/inc/ux_port.h
+++ b/ports/rxv3/gnu/inc/ux_port.h
@@ -239,7 +239,7 @@ VOID outpl(ULONG,ULONG);
#ifdef UX_SYSTEM_INIT
CHAR _ux_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX RXv3/GNU Version 6.5.1.202602 *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * USBX RXv3/GNU Version 6.5.2.202603 *";
#else
extern CHAR _ux_version_id[];
#endif
diff --git a/ports/win32/vs_2019/CMakeLists.txt b/ports/win32/vs_2019/CMakeLists.txt
new file mode 100644
index 000000000..c729f25df
--- /dev/null
+++ b/ports/win32/vs_2019/CMakeLists.txt
@@ -0,0 +1,10 @@
+# Copyright (C) 2026 Eclipse ThreadX contributors
+#
+# SPDX-License-Identifier: MIT
+#
+# AI Disclosure: This file was largely AI-generated by Copilot (Claude Opus 4.8).
+
+target_include_directories(${PROJECT_NAME} PUBLIC
+ ${CMAKE_CURRENT_LIST_DIR}/inc
+)
+# Portions of this file were generated with AI assistance.
diff --git a/ports/win32/vs_2019/inc/ux_port.h b/ports/win32/vs_2019/inc/ux_port.h
new file mode 100644
index 000000000..7b5f85c48
--- /dev/null
+++ b/ports/win32/vs_2019/inc/ux_port.h
@@ -0,0 +1,271 @@
+/***************************************************************************
+ * Copyright (c) 2024 Microsoft Corporation
+ * Copyright (C) 2026 Eclipse ThreadX contributors
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the MIT License which is available at
+ * https://opensource.org/licenses/MIT.
+ *
+ * SPDX-License-Identifier: MIT
+ **************************************************************************/
+// Portions of this file were generated with AI assistance.
+
+/* AI Disclosure: This file was largely AI-generated by Copilot (Claude Opus 4.8). */
+
+/**************************************************************************/
+/**************************************************************************/
+/** */
+/** USBX Component */
+/** */
+/** Port Specific */
+/** */
+/**************************************************************************/
+/**************************************************************************/
+
+
+/**************************************************************************/
+/* */
+/* PORT SPECIFIC C INFORMATION RELEASE */
+/* */
+/* ux_port.h Win32/VS 2019 */
+/* 6.5.2.202603 */
+/* */
+/* AUTHOR */
+/* */
+/* Frédéric Desbiens */
+/* */
+/* DESCRIPTION */
+/* */
+/* This file contains data type definitions that make USBX function */
+/* identically on a variety of different processor architectures. */
+/* This port targets the Win32 simulation environment (MSVC, 32-bit) */
+/* for use with the USBX regression test suite. It is not intended */
+/* for production use. */
+/* */
+/**************************************************************************/
+
+#ifndef UX_PORT_H
+#define UX_PORT_H
+
+
+/* Determine if the optional USBX user define file should be used. */
+
+#ifdef UX_INCLUDE_USER_DEFINE_FILE
+#include "ux_user.h"
+#endif
+
+
+/* Include required system headers. */
+
+#include
+#include
+#include
+
+
+#if !defined(UX_STANDALONE)
+#include "tx_api.h"
+#else
+
+/* Standalone build: define TX-compatible types when tx_api.h is absent. */
+#if !defined(TX_API_H) && !defined(TX_PORT_H)
+
+#ifndef VOID
+#define VOID void
+typedef char CHAR;
+typedef unsigned char UCHAR;
+typedef int INT;
+typedef unsigned int UINT;
+typedef long LONG;
+typedef unsigned long ULONG;
+typedef short SHORT;
+typedef unsigned short USHORT;
+#endif
+
+#ifndef ULONG64_DEFINED
+typedef uint64_t ULONG64;
+#define ULONG64_DEFINED
+#endif
+
+#ifndef ALIGN_TYPE_DEFINED
+#define ALIGN_TYPE ULONG
+#define ALIGN_TYPE_DEFINED
+#endif
+
+#endif /* !TX_API_H && !TX_PORT_H */
+#endif /* UX_STANDALONE */
+
+
+/* Remap Windows SDK macros that clash with USBX identifiers.
+ These must appear AFTER Windows headers (pulled in by tx_api.h) so that the
+ Windows SDK definition of "interface" (struct __declspec(novtable)) is
+ overridden here. "class" does not need remapping since USBX is compiled
+ as C (not C++), where "class" is a plain identifier. */
+
+#ifdef interface
+#undef interface
+#endif
+#define interface usbx_interface
+
+
+/* CPU definition — no preemptive timer required on x86/x64 simulation. */
+
+#undef THREADX_X86_NO_PTIMER
+
+
+/* Memory-mapped I/O (no IN/OUT instructions on x86). Use UX_USE_IO_INSTRUCTIONS
+ to disable these macros when function implementations are provided (e.g. test
+ utility mocks). */
+
+#ifndef UX_USE_IO_INSTRUCTIONS
+#define inpb(a) (*((UCHAR *)(a)))
+#define inpw(a) (*((USHORT *)(a)))
+#define inpl(a) (*((ULONG *)(a)))
+#define outpb(a,b) (*((UCHAR *)(a)) = (UCHAR )(b))
+#define outpw(a,b) (*((USHORT *)(a)) = (USHORT)(b))
+#define outpl(a,b) (*((ULONG *)(a)) = (ULONG )(b))
+#else
+
+/* Function prototypes when I/O function implementations are provided. */
+
+UCHAR inpb(ULONG);
+ULONG inpl(ULONG);
+
+UCHAR outpb(ULONG,UCHAR);
+ULONG outpl(ULONG,ULONG);
+
+/* MSVC treats inpw/outpw as built-in intrinsics that emit privileged x86 IN/OUT
+ instructions — these fault in user mode. The test utility provides mock
+ implementations named inpw_mok / outpw_mok; redirect all callers to them. */
+#ifdef _MSC_VER
+USHORT inpw_mok(ULONG);
+USHORT outpw_mok(ULONG, USHORT);
+#define inpw(a) inpw_mok(a)
+#define outpw(a, b) outpw_mok((a), (b))
+#else
+USHORT inpw(ULONG);
+USHORT outpw(ULONG, USHORT);
+#endif
+
+#endif
+
+/* Additional generic USBX type. */
+
+#ifndef SLONG_DEFINED
+typedef LONG SLONG;
+#define SLONG_DEFINED
+#endif
+
+
+/* Generic USBX project constants. All are wrapped in #ifndef so they can
+ be overridden from ux_user.h or the command line. */
+
+#ifndef UX_PERIODIC_RATE
+#define UX_PERIODIC_RATE 100
+#endif
+
+#ifndef UX_MAX_CLASS_DRIVER
+#define UX_MAX_CLASS_DRIVER 8
+#endif
+
+#ifndef UX_MAX_SLAVE_CLASS_DRIVER
+#define UX_MAX_SLAVE_CLASS_DRIVER 3
+#endif
+
+#ifndef UX_MAX_HCD
+#define UX_MAX_HCD 2
+#endif
+
+#ifndef UX_MAX_DEVICES
+#define UX_MAX_DEVICES 8
+#endif
+
+#ifndef UX_MAX_ED
+#define UX_MAX_ED 80
+#endif
+
+#ifndef UX_MAX_TD
+#define UX_MAX_TD 32
+#endif
+
+#ifndef UX_MAX_ISO_TD
+#define UX_MAX_ISO_TD 128
+#endif
+
+#ifndef UX_HOST_ENUM_THREAD_STACK_SIZE
+#define UX_HOST_ENUM_THREAD_STACK_SIZE (2*1024)
+#endif
+
+#ifndef UX_THREAD_STACK_SIZE
+#define UX_THREAD_STACK_SIZE (1*1024)
+#endif
+
+#ifndef UX_THREAD_PRIORITY_ENUM
+#define UX_THREAD_PRIORITY_ENUM 20
+#endif
+
+#ifndef UX_THREAD_PRIORITY_CLASS
+#define UX_THREAD_PRIORITY_CLASS 20
+#endif
+
+#ifndef UX_THREAD_PRIORITY_KEYBOARD
+#define UX_THREAD_PRIORITY_KEYBOARD 20
+#endif
+
+#ifndef UX_THREAD_PRIORITY_HCD
+#define UX_THREAD_PRIORITY_HCD 2
+#endif
+
+#ifndef UX_THREAD_PRIORITY_DCD
+#define UX_THREAD_PRIORITY_DCD 2
+#endif
+
+#ifndef UX_NO_TIME_SLICE
+#define UX_NO_TIME_SLICE 0
+#endif
+
+#ifndef UX_MAX_SLAVE_LUN
+#define UX_MAX_SLAVE_LUN 2
+#endif
+
+#ifndef UX_MAX_HOST_LUN
+#define UX_MAX_HOST_LUN 2
+#endif
+
+#ifndef UX_HOST_CLASS_STORAGE_MAX_MEDIA
+#define UX_HOST_CLASS_STORAGE_MAX_MEDIA 2
+#endif
+
+#ifndef UX_HOST_CLASS_STORAGE_MAX_PARTITIONS_COUNT
+#define UX_HOST_CLASS_STORAGE_MAX_PARTITIONS_COUNT 8
+#endif
+
+#ifndef UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH
+#define UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH 256
+#endif
+
+#ifndef UX_SLAVE_REQUEST_DATA_MAX_LENGTH
+#define UX_SLAVE_REQUEST_DATA_MAX_LENGTH 4096
+#endif
+
+
+/* Interrupt lockout constructs used to protect allocation/release that may
+ occur under ISR in the device stack. */
+
+#ifdef TX_API_H
+#define UX_INT_SAVE_AREA unsigned int old_interrupt_posture;
+#define UX_DISABLE_INTS old_interrupt_posture = tx_interrupt_control(TX_INT_DISABLE);
+#define UX_RESTORE_INTS tx_interrupt_control(old_interrupt_posture);
+#endif
+
+
+/* Version ID string. */
+
+#ifdef UX_SYSTEM_INIT
+CHAR _ux_version_id[] =
+ "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors."
+ " * USBX Win32/VS 2019 Version 6.5.2.202603 *";
+#else
+extern CHAR _ux_version_id[];
+#endif
+
+#endif /* UX_PORT_H */
diff --git a/ports/win64/vs_2022/CMakeLists.txt b/ports/win64/vs_2022/CMakeLists.txt
new file mode 100644
index 000000000..526c16efd
--- /dev/null
+++ b/ports/win64/vs_2022/CMakeLists.txt
@@ -0,0 +1,10 @@
+# Copyright (C) 2026 Eclipse ThreadX contributors
+#
+# SPDX-License-Identifier: MIT
+#
+# AI Disclosure: This file was largely AI-generated by Copilot (Claude Sonnet 4.6).
+
+target_include_directories(${PROJECT_NAME} PUBLIC
+ ${CMAKE_CURRENT_LIST_DIR}/inc
+)
+# Portions of this file were generated with AI assistance.
diff --git a/ports/win64/vs_2022/inc/ux_port.h b/ports/win64/vs_2022/inc/ux_port.h
new file mode 100644
index 000000000..48cbdbd7d
--- /dev/null
+++ b/ports/win64/vs_2022/inc/ux_port.h
@@ -0,0 +1,271 @@
+/***************************************************************************
+ * Copyright (c) 2024 Microsoft Corporation
+ * Copyright (C) 2026 Eclipse ThreadX contributors
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the MIT License which is available at
+ * https://opensource.org/licenses/MIT.
+ *
+ * SPDX-License-Identifier: MIT
+ **************************************************************************/
+// Portions of this file were generated with AI assistance.
+
+/* AI Disclosure: This file was largely AI-generated by Copilot (Claude Sonnet 4.6). */
+
+/**************************************************************************/
+/**************************************************************************/
+/** */
+/** USBX Component */
+/** */
+/** Port Specific */
+/** */
+/**************************************************************************/
+/**************************************************************************/
+
+
+/**************************************************************************/
+/* */
+/* PORT SPECIFIC C INFORMATION RELEASE */
+/* */
+/* ux_port.h Win64/VS 2022 */
+/* 6.5.2.202603 */
+/* */
+/* AUTHOR */
+/* */
+/* Frédéric Desbiens */
+/* */
+/* DESCRIPTION */
+/* */
+/* This file contains data type definitions that make USBX function */
+/* identically on a variety of different processor architectures. */
+/* This port targets the Win64 simulation environment (MSVC, 64-bit) */
+/* for use with the USBX regression test suite. It is not intended */
+/* for production use. */
+/* */
+/**************************************************************************/
+
+#ifndef UX_PORT_H
+#define UX_PORT_H
+
+
+/* Determine if the optional USBX user define file should be used. */
+
+#ifdef UX_INCLUDE_USER_DEFINE_FILE
+#include "ux_user.h"
+#endif
+
+
+/* Include required system headers. */
+
+#include
+#include
+#include
+
+
+#if !defined(UX_STANDALONE)
+#include "tx_api.h"
+#else
+
+/* Standalone build: define TX-compatible types when tx_api.h is absent. */
+#if !defined(TX_API_H) && !defined(TX_PORT_H)
+
+#ifndef VOID
+#define VOID void
+typedef char CHAR;
+typedef unsigned char UCHAR;
+typedef int INT;
+typedef unsigned int UINT;
+typedef long LONG;
+typedef unsigned long ULONG;
+typedef short SHORT;
+typedef unsigned short USHORT;
+#endif
+
+#ifndef ULONG64_DEFINED
+typedef uint64_t ULONG64;
+#define ULONG64_DEFINED
+#endif
+
+#ifndef ALIGN_TYPE_DEFINED
+#define ALIGN_TYPE ULONG
+#define ALIGN_TYPE_DEFINED
+#endif
+
+#endif /* !TX_API_H && !TX_PORT_H */
+#endif /* UX_STANDALONE */
+
+
+/* Remap Windows SDK macros that clash with USBX identifiers.
+ These must appear AFTER Windows headers (pulled in by tx_api.h) so that the
+ Windows SDK definition of "interface" (struct __declspec(novtable)) is
+ overridden here. "class" does not need remapping since USBX is compiled
+ as C (not C++), where "class" is a plain identifier. */
+
+#ifdef interface
+#undef interface
+#endif
+#define interface usbx_interface
+
+
+/* CPU definition — no preemptive timer required on x86/x64 simulation. */
+
+#undef THREADX_X86_NO_PTIMER
+
+
+/* Memory-mapped I/O (no IN/OUT instructions on x64). Use UX_USE_IO_INSTRUCTIONS
+ to disable these macros when function implementations are provided (e.g. test
+ utility mocks). */
+
+#ifndef UX_USE_IO_INSTRUCTIONS
+#define inpb(a) (*((UCHAR *)(a)))
+#define inpw(a) (*((USHORT *)(a)))
+#define inpl(a) (*((ULONG *)(a)))
+#define outpb(a,b) (*((UCHAR *)(a)) = (UCHAR )(b))
+#define outpw(a,b) (*((USHORT *)(a)) = (USHORT)(b))
+#define outpl(a,b) (*((ULONG *)(a)) = (ULONG )(b))
+#else
+
+/* Function prototypes when I/O function implementations are provided. */
+
+UCHAR inpb(ULONG);
+ULONG inpl(ULONG);
+
+UCHAR outpb(ULONG,UCHAR);
+ULONG outpl(ULONG,ULONG);
+
+/* MSVC treats inpw/outpw as built-in intrinsics that emit privileged x86 IN/OUT
+ instructions — these fault in user mode on x64. The test utility provides mock
+ implementations named inpw_mok / outpw_mok; redirect all callers to them. */
+#ifdef _MSC_VER
+USHORT inpw_mok(ULONG);
+USHORT outpw_mok(ULONG, USHORT);
+#define inpw(a) inpw_mok(a)
+#define outpw(a, b) outpw_mok((a), (b))
+#else
+USHORT inpw(ULONG);
+USHORT outpw(ULONG, USHORT);
+#endif
+
+#endif
+
+/* Additional generic USBX type. */
+
+#ifndef SLONG_DEFINED
+typedef LONG SLONG;
+#define SLONG_DEFINED
+#endif
+
+
+/* Generic USBX project constants. All are wrapped in #ifndef so they can
+ be overridden from ux_user.h or the command line. */
+
+#ifndef UX_PERIODIC_RATE
+#define UX_PERIODIC_RATE 100
+#endif
+
+#ifndef UX_MAX_CLASS_DRIVER
+#define UX_MAX_CLASS_DRIVER 8
+#endif
+
+#ifndef UX_MAX_SLAVE_CLASS_DRIVER
+#define UX_MAX_SLAVE_CLASS_DRIVER 3
+#endif
+
+#ifndef UX_MAX_HCD
+#define UX_MAX_HCD 2
+#endif
+
+#ifndef UX_MAX_DEVICES
+#define UX_MAX_DEVICES 8
+#endif
+
+#ifndef UX_MAX_ED
+#define UX_MAX_ED 80
+#endif
+
+#ifndef UX_MAX_TD
+#define UX_MAX_TD 32
+#endif
+
+#ifndef UX_MAX_ISO_TD
+#define UX_MAX_ISO_TD 128
+#endif
+
+#ifndef UX_HOST_ENUM_THREAD_STACK_SIZE
+#define UX_HOST_ENUM_THREAD_STACK_SIZE (2*1024)
+#endif
+
+#ifndef UX_THREAD_STACK_SIZE
+#define UX_THREAD_STACK_SIZE (1*1024)
+#endif
+
+#ifndef UX_THREAD_PRIORITY_ENUM
+#define UX_THREAD_PRIORITY_ENUM 20
+#endif
+
+#ifndef UX_THREAD_PRIORITY_CLASS
+#define UX_THREAD_PRIORITY_CLASS 20
+#endif
+
+#ifndef UX_THREAD_PRIORITY_KEYBOARD
+#define UX_THREAD_PRIORITY_KEYBOARD 20
+#endif
+
+#ifndef UX_THREAD_PRIORITY_HCD
+#define UX_THREAD_PRIORITY_HCD 2
+#endif
+
+#ifndef UX_THREAD_PRIORITY_DCD
+#define UX_THREAD_PRIORITY_DCD 2
+#endif
+
+#ifndef UX_NO_TIME_SLICE
+#define UX_NO_TIME_SLICE 0
+#endif
+
+#ifndef UX_MAX_SLAVE_LUN
+#define UX_MAX_SLAVE_LUN 2
+#endif
+
+#ifndef UX_MAX_HOST_LUN
+#define UX_MAX_HOST_LUN 2
+#endif
+
+#ifndef UX_HOST_CLASS_STORAGE_MAX_MEDIA
+#define UX_HOST_CLASS_STORAGE_MAX_MEDIA 2
+#endif
+
+#ifndef UX_HOST_CLASS_STORAGE_MAX_PARTITIONS_COUNT
+#define UX_HOST_CLASS_STORAGE_MAX_PARTITIONS_COUNT 8
+#endif
+
+#ifndef UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH
+#define UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH 256
+#endif
+
+#ifndef UX_SLAVE_REQUEST_DATA_MAX_LENGTH
+#define UX_SLAVE_REQUEST_DATA_MAX_LENGTH 4096
+#endif
+
+
+/* Interrupt lockout constructs used to protect allocation/release that may
+ occur under ISR in the device stack. */
+
+#ifdef TX_API_H
+#define UX_INT_SAVE_AREA unsigned int old_interrupt_posture;
+#define UX_DISABLE_INTS old_interrupt_posture = tx_interrupt_control(TX_INT_DISABLE);
+#define UX_RESTORE_INTS tx_interrupt_control(old_interrupt_posture);
+#endif
+
+
+/* Version ID string. */
+
+#ifdef UX_SYSTEM_INIT
+CHAR _ux_version_id[] =
+ "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors."
+ " * USBX Win64/VS 2022 Version 6.5.2.202603 *";
+#else
+extern CHAR _ux_version_id[];
+#endif
+
+#endif /* UX_PORT_H */
diff --git a/samples/demo_usbx.c b/samples/demo_usbx.c
index 1b4ddaad7..ce7349253 100644
--- a/samples/demo_usbx.c
+++ b/samples/demo_usbx.c
@@ -8,10 +8,12 @@
/* */
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+/* Portions of this file were generated with AI assistance. */
/* This is a small demo of the USBX */
#include "ux_api.h"
+#include "ux_device_stack.h"
#include "ux_system.h"
#include "ux_utility.h"
#include "ux_host_class_dpump.h"
diff --git a/scripts/build.sh b/scripts/build.sh
index 3c73f76a3..242931de1 100755
--- a/scripts/build.sh
+++ b/scripts/build.sh
@@ -10,4 +10,10 @@
# SPDX-License-Identifier: MIT
##############################################################################
-$(dirname `realpath $0`)/../test/cmake/usbx/run.sh build $@
+set -euo pipefail
+export CC=${CC:-gcc-14}
+export GCOV=${GCOV:-gcov-14}
+export CMAKE_BUILD_PARALLEL_LEVEL=${CMAKE_BUILD_PARALLEL_LEVEL:-4}
+"$(dirname "$(realpath "$0")")/../test/cmake/usbx/run.sh" build "$@"
+echo "Checking runner and coverage failure handling in isolated fixtures."
+python3 "$(dirname "$(realpath "$0")")/../test/cmake/usbx/test_runner.py"
diff --git a/scripts/build_usbx.ps1 b/scripts/build_usbx.ps1
new file mode 100644
index 000000000..dbbddffcc
--- /dev/null
+++ b/scripts/build_usbx.ps1
@@ -0,0 +1,103 @@
+# Copyright (C) 2026 Eclipse ThreadX contributors
+#
+# SPDX-License-Identifier: MIT
+#
+# Build script for the USBX Win64/Win32 regression test suite.
+# AI Disclosure: This file was largely AI-generated by Copilot (Claude Sonnet 4.6).
+# Author: Frédéric Desbiens
+#
+# Usage:
+# .\build_usbx.ps1 [-Arch win64] [-Configuration all|] [-ThreadXDir ]
+# [-FilexDir ] [-NetxduoDir ] [-BuildDir ]
+# [-Clean] [-Parallel ]
+
+[CmdletBinding()]
+param(
+ [ValidateSet('win64', 'win32')]
+ [string]$Arch = 'win64',
+
+ [AllowNull()]
+ [object]$Configuration = 'all',
+
+ [int]$Parallel = [Math]::Max(1, [Environment]::ProcessorCount),
+
+ [int]$BuildTimeoutSeconds = 600,
+
+ [string]$BuildDir,
+
+ [string]$ThreadXDir,
+
+ [string]$FilexDir,
+
+ [string]$NetxduoDir,
+
+ [switch]$Clean
+)
+
+$ErrorActionPreference = 'Stop'
+. (Join-Path $PSScriptRoot 'ux_windows_common.ps1')
+
+$repoRoot = Split-Path -Parent $PSScriptRoot
+$settings = Get-PortSettings -SelectedArch $Arch
+
+function Resolve-AbsolutePath([string]$Path) {
+ $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Path)
+}
+
+if (-not $BuildDir) {
+ $BuildDir = Join-Path $repoRoot "build\tests\$Arch"
+}
+
+if (-not $ThreadXDir) {
+ $ThreadXDir = Join-Path (Split-Path -Parent $repoRoot) 'threadx'
+}
+
+if (-not $FilexDir) {
+ $FilexDir = Join-Path (Split-Path -Parent $repoRoot) 'filex'
+}
+
+if (-not $NetxduoDir) {
+ $NetxduoDir = Join-Path (Split-Path -Parent $repoRoot) 'netxduo'
+}
+
+$BuildDir = Resolve-AbsolutePath $BuildDir
+$ThreadXDir = Resolve-AbsolutePath $ThreadXDir
+$FilexDir = Resolve-AbsolutePath $FilexDir
+$NetxduoDir = Resolve-AbsolutePath $NetxduoDir
+
+$selectedConfigurations = Resolve-RegressionConfigurations -RequestedConfigurations $Configuration
+Write-Host "Selected configurations: $($selectedConfigurations -join ', ')"
+
+Enter-VisualStudioDevShell -VsArch $settings.VsArch
+
+foreach ($currentConfiguration in $selectedConfigurations) {
+ $currentBuildDirName = Get-RegressionBuildDirectoryName -ConfigurationName $currentConfiguration
+ $currentBuildDir = Join-Path $BuildDir $currentBuildDirName
+
+ if ($Clean) {
+ Remove-BuildDirectory -Path $currentBuildDir -RepoRoot $repoRoot
+ }
+
+ Remove-NinjaLock -Path $currentBuildDir
+
+ Write-Host "Configuring $Arch / $currentConfiguration"
+ Invoke-NativeCommand -FilePath 'cmake' -Arguments @(
+ '-S', (Join-Path $repoRoot 'test\cmake\usbx'),
+ '-B', $currentBuildDir,
+ '-G', 'Ninja',
+ '-DCMAKE_C_COMPILER_FORCED=TRUE',
+ '-DCMAKE_C_COMPILER_WORKS=TRUE',
+ '-DCMAKE_C_ABI_COMPILED=TRUE',
+ '-DCMAKE_ASM_COMPILER_FORCED=TRUE',
+ '-DCMAKE_ASM_COMPILER_WORKS=TRUE',
+ "-DCMAKE_BUILD_TYPE=$currentConfiguration",
+ "-DTHREADX_ARCH=$($settings.UsbxArch)",
+ "-DTHREADX_TOOLCHAIN=$($settings.UsbxToolchain)",
+ "-DTHREADX_SOURCE_DIR=$ThreadXDir",
+ "-DFILEX_SOURCE_DIR=$FilexDir",
+ "-DNETXDUO_SOURCE_DIR=$NetxduoDir"
+ )
+
+ Write-Host "Building $Arch / $currentConfiguration"
+ Invoke-CMakeBuild -BuildDir $currentBuildDir -Parallel $Parallel -TimeoutSeconds $BuildTimeoutSeconds
+}
diff --git a/scripts/check_ai_disclosure.sh b/scripts/check_ai_disclosure.sh
new file mode 100755
index 000000000..6dc8a2f2e
--- /dev/null
+++ b/scripts/check_ai_disclosure.sh
@@ -0,0 +1,126 @@
+#!/bin/bash
+###############################################################################
+# Copyright (c) 2026 Eclipse ThreadX contributors
+#
+# This program and the accompanying materials are made available under the
+# terms of the MIT License which is available at
+# https://opensource.org/licenses/MIT.
+#
+# AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5).
+# The AI-generated portions may be considered public domain (CC0-1.0)
+# and not subject to the project's licence. The human contributor has
+# reviewed and verified that the code is correct.
+#
+# SPDX-License-Identifier: MIT and CC0-1.0
+###############################################################################
+#
+# Fail the build if a file's AI disclosure comment has drifted from the one
+# accepted form.
+#
+# A file that was edited with AI assistance carries exactly one line:
+#
+# Portions of this file were generated with AI assistance.
+#
+# written with the comment character that file already uses. It names no
+# product, no model and no version, and a file carries at most one of it, ever.
+#
+# The text is fixed for a reason that is easy to miss. An earlier convention
+# named the product and the model -- "Some portions generated by
+# ()" -- and the result was not attribution but accumulation: each tool
+# that touched a file failed to recognise the line another tool had left, and
+# appended its own. Files reached three stacked lines, and one product ended
+# up spelled four different ways across the tree, which made the record
+# unusable for the one question it was meant to answer.
+#
+# Precise attribution lives on the commit instead, where the Assisted-by
+# trailer is dated and attached to the diff it describes:
+#
+# git log --format='%h %(trailers:key=Assisted-by,valueonly)' --
+#
+# A file-level flag answers WHETHER; the history answers WHO. A header line
+# cannot hold the second honestly, because the code it names gets rewritten
+# and the line stays.
+#
+# The AI Disclosure paragraph in a new file's copyright header is different and
+# is not checked here: it keeps its product and model version, because a file
+# is created once and that record cannot grow.
+#
+# This script is excluded from its own scan. It has to spell the rejected
+# forms in order to look for them.
+
+set -euo pipefail
+
+readonly ROOT="$(cd "$(dirname "$(realpath "$0")")/.." && pwd)"
+readonly SELF='scripts/check_ai_disclosure.sh'
+
+# The contribution guide is excluded for the same reason this script is: it has
+# to spell the disclosure text in order to explain it, and it discusses AI
+# assistance in prose besides. Scanning it turns documenting the rule into a
+# violation of it.
+readonly GUIDE='CONTRIBUTING.md'
+readonly FIXED='Portions of this file were generated with AI assistance.'
+
+cd "${ROOT}"
+
+# Tracked files only. A build tree is not this repository's text to police,
+# and scanning one would make the check depend on whether somebody had built.
+mapfile -d '' -t FILES < <(git ls-files -z | grep -zZv "^${SELF}$" | grep -zZv "^${GUIDE}$")
+
+status=0
+
+report() {
+ printf '%s\n\n' "$1" >&2
+ printf '%s\n\n' "$2" >&2
+ status=1
+}
+
+# 1. The superseded per-edit form, which names a product and a model.
+hits="$(grep -nI 'Some portions generated by' -- "${FILES[@]}" 2>/dev/null || true)"
+if [ -n "${hits}" ]; then
+ report "AI disclosure check FAILED: superseded per-edit form.
+
+Replace each of these with the fixed line, keeping the file's comment
+character:
+
+ ${FIXED}" "${hits}"
+fi
+
+# 2. A doubled comment marker, such as '; //' or '@ //'. Assembly dialects
+# differ -- armasm and IAR use ';', GNU as uses '@' or '//' -- and writing
+# both is a symptom of a tool guessing rather than reading the file.
+hits="$(grep -nIE '(//|[;@#])[[:space:]]*//[[:space:]]*Portions of this file were generated' \
+ -- "${FILES[@]}" 2>/dev/null || true)"
+if [ -n "${hits}" ]; then
+ report "AI disclosure check FAILED: doubled comment marker.
+
+Use the single comment character the rest of the file uses." "${hits}"
+fi
+
+# 3. More than one disclosure line in a file. This is the failure the fixed
+# text exists to prevent, so it is worth catching directly rather than
+# inferring it from the form.
+hits="$(grep -cIF "${FIXED}" -- "${FILES[@]}" 2>/dev/null | awk -F: '$NF > 1' || true)"
+if [ -n "${hits}" ]; then
+ report "AI disclosure check FAILED: more than one disclosure line.
+
+A file carries at most one, ever. Keep the first and delete the rest; the
+commit trailer, not the header, records which agents have touched the file." "${hits}"
+fi
+
+# 4. A near miss. A line that is clearly meant to be the disclosure but is
+# not spelled exactly right defeats every deduplication that follows it.
+hits="$(grep -nIF 'AI assistance' -- "${FILES[@]}" 2>/dev/null \
+ | grep -vF "${FIXED}" || true)"
+if [ -n "${hits}" ]; then
+ report "AI disclosure check FAILED: the text is not spelled exactly.
+
+The accepted text, character for character, is:
+
+ ${FIXED}" "${hits}"
+fi
+
+if [ "${status}" -eq 0 ]; then
+ echo "AI disclosure check passed."
+fi
+
+exit "${status}"
diff --git a/scripts/install.sh b/scripts/install.sh
index 5ba1cde68..850cc3c9e 100755
--- a/scripts/install.sh
+++ b/scripts/install.sh
@@ -10,27 +10,50 @@
# SPDX-License-Identifier: MIT
##############################################################################
-#
-# Install necessary softwares for Ubuntu.
-
-sudo apt-get update
-sudo apt-get install -y \
- gcc-multilib \
- git \
- g++ \
- python3-pip \
- ninja-build \
- unifdef \
- p7zip-full \
- tofrodos \
- gawk \
- software-properties-common
-
-wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | sudo apt-key add -
-CODENAME=$(lsb_release -c | cut -f2 -d':' | sed 's/\t//')
-sudo apt-add-repository -y "deb https://apt.kitware.com/ubuntu/ $CODENAME main"
-sudo apt-get -y install cmake
-
-python3 -m pip install --upgrade pip
-pip3 install gcovr==4.1
-pip3 install --upgrade cmake
+set -euo pipefail
+
+retry() {
+ local attempt
+ for attempt in 1 2 3; do
+ if "$@"; then
+ return 0
+ fi
+ if [ "$attempt" -lt 3 ]; then
+ sleep $((attempt * 5))
+ fi
+ done
+ return 1
+}
+
+apt_options=(-o Acquire::Retries=3 -o DPkg::Lock::Timeout=60)
+if ! retry sudo timeout 150 apt-get "${apt_options[@]}" update; then
+ echo "Package index update failed; package installation will verify availability." >&2
+fi
+retry sudo timeout 150 apt-get "${apt_options[@]}" install -y \
+ cmake gcc-14 gcc-14-multilib git ninja-build python3-venv \
+ unifdef p7zip-full tofrodos gawk
+
+venv_dir="${RUNNER_TEMP:-${TMPDIR:-/tmp}}/usbx-ci-venv"
+python3 -m venv "$venv_dir"
+retry timeout 120 "$venv_dir/bin/python" -m pip install \
+ --retries 3 --timeout 30 gcovr==8.6
+
+cc="${CC:-gcc-14}"
+gcov="${GCOV:-gcov-14}"
+cc_version=$("$cc" -dumpfullversion)
+gcov_version=$("$gcov" --version | sed -n '1{s/.* \([0-9][0-9]*\.[0-9][0-9]*\(\.[0-9][0-9]*\)\?\).*/\1/p;}')
+if [ -z "$gcov_version" ] || [ "$cc_version" != "$gcov_version" ]; then
+ echo "Compiler $cc and coverage tool $gcov have different versions." >&2
+ exit 1
+fi
+
+if [ -n "${GITHUB_ENV:-}" ]; then
+ printf 'CC=%s\nGCOV=%s\n' "$cc" "$gcov" >> "$GITHUB_ENV"
+ printf '%s\n' "$venv_dir/bin" >> "$GITHUB_PATH"
+fi
+
+"$venv_dir/bin/gcovr" --version | head -1
+"$cc" --version | head -1
+"$gcov" --version | head -1
+
+printf 'Coverage environment: %s\n' "$venv_dir/bin/activate"
diff --git a/scripts/prepare_release.sh b/scripts/prepare_release.sh
index 5b0260b4b..bba7cdb6e 100755
--- a/scripts/prepare_release.sh
+++ b/scripts/prepare_release.sh
@@ -15,6 +15,7 @@
#
# Copyright (C) 2026 Eclipse ThreadX contributors
# SPDX-License-Identifier: MIT
+# Portions of this file were generated with AI assistance.
set -eu
@@ -120,8 +121,6 @@ sed -i -E "s|(#define USBX_HOTFIX_VERSION[[:space:]]+)'[^']*'|\1${HOTFIX_DEFINE}
git -C "${REPO_ROOT}" add "${API_HEADER}"
git -C "${REPO_ROOT}" commit -F - <<'COMMIT_EOF'
Updated version number constants
-
-Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
COMMIT_EOF
printf "Committed version constant updates.\n"
@@ -146,23 +145,48 @@ PORT_FILES=$(printf "%s" "${PORT_FILES}" | grep -v '^[[:space:]]*$' || true)
if [ -z "${PORT_FILES}" ]; then
printf "Warning: No port header files found. Skipping port version string commit.\n"
else
+ # A port advertises its release in the string the library reports at run time.
+ # The pattern accepts three or four dotted numbers and tolerates a stray
+ # letter before the first one, so a port that writes its version slightly
+ # differently is still reached.
+ VERSION_RE='Version[[:space:]]+[A-Za-z]?[0-9]+(\.[0-9]+)+[a-z]*'
while IFS= read -r port_file; do
- if [ -n "${port_file}" ] && grep -qE "Version [0-9]" "${port_file}" 2>/dev/null; then
- sed -i -E "s/Version [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+[a-z]*/Version ${VERSION}/g" "${port_file}"
+ if [ -n "${port_file}" ] && grep -qE "${VERSION_RE}" "${port_file}" 2>/dev/null; then
+ sed -i -E "s/${VERSION_RE}/Version ${VERSION}/g" "${port_file}"
printf " Updated: %s\n" "${port_file#${REPO_ROOT}/}"
fi
done </dev/null || true)
+ [ -n "${advertised}" ] || continue
+ if ! printf "%s" "${advertised}" | grep -qF "${VERSION}"; then
+ STALE="${STALE} ${port_file#${REPO_ROOT}/}
+"
+ fi
+ done <&2
+ printf "Correct them so the substitution above reaches them, then re-run.\n" >&2
+ exit 1
+ fi
+
git -C "${REPO_ROOT}" add -u
if git -C "${REPO_ROOT}" diff --cached --quiet; then
printf "No port version string changes staged. Skipping commit.\n"
else
git -C "${REPO_ROOT}" commit -F - <<'COMMIT_EOF'
Updated port version strings
-
-Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
COMMIT_EOF
printf "Committed port version string updates.\n"
fi
diff --git a/scripts/test.sh b/scripts/test.sh
index 7a3720cd6..6a591a44c 100755
--- a/scripts/test.sh
+++ b/scripts/test.sh
@@ -10,4 +10,10 @@
# SPDX-License-Identifier: MIT
##############################################################################
-CTEST_PARALLEL_LEVEL=4 $(dirname `realpath $0`)/../test/cmake/usbx/run.sh test $@
+set -euo pipefail
+export CTEST_PARALLEL_LEVEL=${CTEST_PARALLEL_LEVEL:-4}
+export CTEST_REPEAT_FAIL=1
+export CC=${CC:-gcc-14}
+export GCOV=${GCOV:-gcov-14}
+export CMAKE_BUILD_PARALLEL_LEVEL=${CMAKE_BUILD_PARALLEL_LEVEL:-4}
+exec "$(dirname "$(realpath "$0")")/../test/cmake/usbx/run.sh" test "$@"
diff --git a/scripts/test_usbx.ps1 b/scripts/test_usbx.ps1
new file mode 100644
index 000000000..f92926f14
--- /dev/null
+++ b/scripts/test_usbx.ps1
@@ -0,0 +1,122 @@
+# Copyright (C) 2026 Eclipse ThreadX contributors
+#
+# SPDX-License-Identifier: MIT
+#
+# Test script for the USBX Win64/Win32 regression test suite.
+# AI Disclosure: This file was largely AI-generated by Copilot (Claude Sonnet 4.6).
+# Portions of this file were generated with AI assistance.
+# Author: Frédéric Desbiens
+#
+# Usage:
+# .\test_usbx.ps1 [-Arch win64] [-Configuration all|] [-BuildDir ]
+# [-TestRegex ] [-RerunFailedOnly] [-Clean]
+
+[CmdletBinding()]
+param(
+ [ValidateSet('win64', 'win32')]
+ [string]$Arch = 'win64',
+
+ [AllowNull()]
+ [object]$Configuration = 'all',
+
+ [int]$Parallel = [Math]::Max(1, [Environment]::ProcessorCount),
+
+ [int]$RepeatFailCount = 1,
+
+ [int]$TestTimeoutSeconds = 120,
+
+ [string]$TestRegex,
+
+ [switch]$RerunFailedOnly,
+
+ [string]$BuildDir,
+
+ [switch]$Clean
+)
+
+$ErrorActionPreference = 'Stop'
+. (Join-Path $PSScriptRoot 'ux_windows_common.ps1')
+
+$repoRoot = Split-Path -Parent $PSScriptRoot
+$settings = Get-PortSettings -SelectedArch $Arch
+
+if (-not $BuildDir) {
+ $BuildDir = Join-Path $repoRoot "build\tests\$Arch"
+}
+
+$selectedConfigurations = Resolve-RegressionConfigurations -RequestedConfigurations $Configuration
+Write-Host "Selected configurations: $($selectedConfigurations -join ', ')"
+
+Enter-VisualStudioDevShell -VsArch $settings.VsArch
+
+# The Win64/Win32 ThreadX simulator pins all threads to a single core for
+# deterministic scheduling. Running multiple test processes in parallel causes
+# timer starvation. Always enforce serial execution.
+if ($Parallel -ne 1) {
+ Write-Warning "The Win64 ThreadX simulator pins all threads to a single core for deterministic scheduling. Running multiple test processes in parallel causes timer starvation. Forcing -Parallel 1."
+ $Parallel = 1
+}
+
+$failedConfigurations = @()
+
+foreach ($currentConfiguration in $selectedConfigurations) {
+ $currentBuildDirName = Get-RegressionBuildDirectoryName -ConfigurationName $currentConfiguration
+ $currentBuildDir = Join-Path $BuildDir $currentBuildDirName
+ $currentTestingTemporaryDir = Join-Path $currentBuildDir 'Testing\Temporary'
+
+ try {
+ if ($Clean) {
+ $currentTestingDir = Join-Path $currentBuildDir 'Testing'
+ Remove-CtestTestingDirectory -Path $currentTestingDir
+ }
+
+ if (-not (Test-Path -LiteralPath $currentBuildDir)) {
+ throw "Build directory does not exist for $Arch / ${currentConfiguration}: $currentBuildDir"
+ }
+
+ Remove-NinjaLock -Path $currentBuildDir
+ if (Test-Path -LiteralPath $currentTestingTemporaryDir) {
+ Remove-Item -LiteralPath (Join-Path $currentTestingTemporaryDir 'LastTest.log') -Force -ErrorAction SilentlyContinue
+ Remove-Item -LiteralPath (Join-Path $currentTestingTemporaryDir 'LastTestsFailed.log') -Force -ErrorAction SilentlyContinue
+ }
+
+ Write-Host "Testing $Arch / $currentConfiguration"
+ $ctestArguments = @(
+ '--test-dir', $currentBuildDir,
+ '--output-on-failure',
+ '--timeout', $TestTimeoutSeconds.ToString(),
+ '-j', $Parallel.ToString()
+ )
+
+ if ($RepeatFailCount -gt 1) {
+ $ctestArguments += @('--repeat', "until-pass:$RepeatFailCount")
+ }
+
+ if ($TestRegex) {
+ $ctestArguments += @('-R', $TestRegex)
+ }
+
+ if ($RerunFailedOnly) {
+ $ctestArguments += '--rerun-failed'
+ }
+
+ Invoke-NativeCommand -FilePath 'ctest' -Arguments $ctestArguments
+ }
+ catch {
+ $failedConfigurations += @{
+ Configuration = $currentConfiguration
+ Message = $_.Exception.Message
+ }
+ Write-Warning "Configuration failed: $currentConfiguration"
+ }
+}
+
+if ($failedConfigurations.Count -gt 0) {
+ Write-Host ''
+ Write-Host 'Configuration failure summary:'
+ foreach ($failedConfiguration in $failedConfigurations) {
+ Write-Host "- $($failedConfiguration.Configuration): $($failedConfiguration.Message)"
+ }
+
+ throw "One or more configurations failed: $($failedConfigurations.Configuration -join ', ')"
+}
diff --git a/scripts/ux_windows_common.ps1 b/scripts/ux_windows_common.ps1
new file mode 100644
index 000000000..6896cd29d
--- /dev/null
+++ b/scripts/ux_windows_common.ps1
@@ -0,0 +1,403 @@
+# Copyright (C) 2026 Eclipse ThreadX contributors
+#
+# SPDX-License-Identifier: MIT
+#
+# Shared helpers for the USBX Win64/Win32 build and test scripts.
+# AI Disclosure: This file was largely AI-generated by Copilot (Claude Sonnet 4.6).
+# Portions of this file were generated with AI assistance.
+# Author: Frédéric Desbiens
+
+[CmdletBinding()]
+param()
+
+$ErrorActionPreference = 'Stop'
+
+function Invoke-NativeCommand {
+ param(
+ [Parameter(Mandatory = $true)]
+ [string]$FilePath,
+
+ [Parameter()]
+ [string[]]$Arguments = @()
+ )
+
+ & $FilePath @Arguments
+ if ($LASTEXITCODE -ne 0) {
+ throw "Command failed with exit code ${LASTEXITCODE}: $FilePath $($Arguments -join ' ')"
+ }
+}
+
+function Get-CommandPathIfAvailable {
+ param(
+ [Parameter(Mandatory = $true)]
+ [string]$CommandName
+ )
+
+ $command = Get-Command $CommandName -ErrorAction SilentlyContinue
+ if ($null -eq $command) {
+ return $null
+ }
+
+ return $command.Source
+}
+
+function Get-PortSettings {
+ param(
+ [Parameter(Mandatory = $true)]
+ [string]$SelectedArch
+ )
+
+ switch ($SelectedArch) {
+ 'win32' {
+ return @{
+ UsbxArch = 'win32'
+ UsbxToolchain = 'vs_2019'
+ VsArch = 'x86'
+ }
+ }
+ 'win64' {
+ return @{
+ UsbxArch = 'win64'
+ UsbxToolchain = 'vs_2022'
+ VsArch = 'amd64'
+ }
+ }
+ default {
+ throw "Unsupported architecture: $SelectedArch"
+ }
+ }
+}
+
+function Get-RegressionConfigurations {
+ return @(
+ 'default_build_coverage'
+ )
+}
+
+# Maps a CMake build-type name to a short filesystem-safe directory name.
+function Get-ShortConfigName {
+ param(
+ [Parameter(Mandatory = $true)]
+ [string]$ConfigurationName
+ )
+
+ $knownNames = @{
+ 'default_build_coverage' = 'dbc'
+ 'error_check_build_full_coverage' = 'ecbfc'
+ 'tracex_enable_build' = 'tex'
+ 'device_buffer_owner_build' = 'dbo'
+ 'device_zero_copy_build' = 'dzc'
+ 'nofx_build_coverage' = 'nofx'
+ 'optimized_build' = 'opt'
+ 'standalone_device_build_coverage' = 'sad'
+ 'standalone_device_buffer_owner_build' = 'sadb'
+ 'standalone_device_zero_copy_build' = 'sadz'
+ 'standalone_host_build_coverage' = 'sah'
+ 'standalone_build_coverage' = 'sa'
+ 'generic_build' = 'gen'
+ 'otg_support_build' = 'otg'
+ 'memory_management_build_coverage' = 'mm'
+ 'msrc_rtos_build' = 'msrcr'
+ 'msrc_standalone_build' = 'msrcsa'
+ }
+
+ if ($knownNames.ContainsKey($ConfigurationName)) {
+ return $knownNames[$ConfigurationName]
+ }
+
+ return $ConfigurationName -replace '[^a-zA-Z0-9_-]', '_'
+}
+
+# Generic configuration resolver.
+function Resolve-Configurations {
+ param(
+ [Parameter(Mandatory = $true)]
+ [string[]]$ValidConfigurations,
+
+ [Parameter(Mandatory = $false)]
+ [AllowNull()]
+ [AllowEmptyCollection()]
+ [object]$RequestedConfigurations = 'all'
+ )
+
+ $resolvedConfigurations = @()
+
+ if ($null -eq $RequestedConfigurations) {
+ $resolvedConfigurations = @('all')
+ }
+ elseif ($RequestedConfigurations -is [System.Array]) {
+ foreach ($requestedConfiguration in $RequestedConfigurations) {
+ if ($null -ne $requestedConfiguration) {
+ $resolvedConfigurations += [string]$requestedConfiguration
+ }
+ }
+ }
+ else {
+ $resolvedConfigurations = @([string]$RequestedConfigurations)
+ }
+
+ $normalizedConfigurations = @()
+ foreach ($requestedConfiguration in $resolvedConfigurations) {
+ foreach ($configurationPart in ($requestedConfiguration -split ',')) {
+ $trimmedConfiguration = $configurationPart.Trim()
+ if ($trimmedConfiguration.Length -gt 0) {
+ $normalizedConfigurations += $trimmedConfiguration
+ }
+ }
+ }
+
+ if (($normalizedConfigurations.Count -eq 0) -or ($normalizedConfigurations -contains 'all')) {
+ return $ValidConfigurations
+ }
+
+ foreach ($normalizedConfiguration in $normalizedConfigurations) {
+ if ($ValidConfigurations -notcontains $normalizedConfiguration) {
+ throw "Unsupported configuration: $normalizedConfiguration"
+ }
+ }
+
+ return $normalizedConfigurations
+}
+
+function Resolve-RegressionConfigurations {
+ param(
+ [Parameter(Mandatory = $false)]
+ [AllowNull()]
+ [AllowEmptyCollection()]
+ [object]$RequestedConfigurations = 'all'
+ )
+
+ return Resolve-Configurations -ValidConfigurations (Get-RegressionConfigurations) `
+ -RequestedConfigurations $RequestedConfigurations
+}
+
+function Get-RegressionBuildDirectoryName {
+ param(
+ [Parameter(Mandatory = $true)]
+ [string]$ConfigurationName
+ )
+
+ return Get-ShortConfigName -ConfigurationName $ConfigurationName
+}
+
+function Enter-VisualStudioDevShell {
+ param(
+ [Parameter(Mandatory = $true)]
+ [string]$VsArch
+ )
+
+ $targetArch = switch ($VsArch) {
+ 'amd64' { 'x64' }
+ 'x86' { 'x86' }
+ default { $VsArch }
+ }
+
+ if ((Get-Command cl -ErrorAction SilentlyContinue) -and ($env:VSCMD_ARG_TGT_ARCH -eq $targetArch)) {
+ return
+ }
+
+ $vsWherePath = Join-Path ${env:ProgramFiles(x86)} 'Microsoft Visual Studio\Installer\vswhere.exe'
+ if (-not (Test-Path -LiteralPath $vsWherePath)) {
+ throw "Unable to locate vswhere.exe at $vsWherePath"
+ }
+
+ $installationPath = & $vsWherePath -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
+ if (-not $installationPath) {
+ throw 'Unable to locate a Visual Studio installation with MSVC build tools.'
+ }
+
+ $launchScript = Join-Path $installationPath 'Common7\Tools\Launch-VsDevShell.ps1'
+ if (-not (Test-Path -LiteralPath $launchScript)) {
+ throw "Unable to locate Launch-VsDevShell.ps1 at $launchScript"
+ }
+
+ $env:VSCMD_SKIP_SENDTELEMETRY = '1'
+ & $launchScript -VsInstallationPath $installationPath -Arch $VsArch -HostArch amd64 -SkipAutomaticLocation | Out-Null
+
+ if (-not (Get-Command cl -ErrorAction SilentlyContinue)) {
+ throw 'MSVC compiler environment was not activated successfully.'
+ }
+}
+
+function Remove-BuildDirectory {
+ param(
+ [Parameter(Mandatory = $true)]
+ [string]$Path,
+
+ [Parameter(Mandatory = $true)]
+ [string]$RepoRoot
+ )
+
+ $fullRepoRoot = [System.IO.Path]::GetFullPath($RepoRoot)
+ $fullPath = [System.IO.Path]::GetFullPath($Path)
+
+ if (-not $fullPath.StartsWith($fullRepoRoot, [System.StringComparison]::OrdinalIgnoreCase)) {
+ throw "Refusing to remove a directory outside the repository: $fullPath"
+ }
+
+ if (Test-Path -LiteralPath $fullPath) {
+ try {
+ Remove-Item -LiteralPath $fullPath -Recurse -Force -ErrorAction Stop
+ return
+ } catch {
+ Write-Warning "Failed to remove build directory '$fullPath': $($_.Exception.Message)"
+ }
+
+ Get-ChildItem -LiteralPath $fullPath -Force -Recurse -ErrorAction SilentlyContinue | ForEach-Object {
+ try {
+ if (($_.Attributes -band [System.IO.FileAttributes]::ReadOnly) -ne 0) {
+ $_.Attributes = ($_.Attributes -band (-bnot [System.IO.FileAttributes]::ReadOnly))
+ }
+ } catch { }
+ }
+
+ try {
+ Remove-Item -LiteralPath $fullPath -Recurse -Force -ErrorAction Stop
+ } catch {
+ Write-Warning "Proceeding with partially cleaned build directory '$fullPath': $($_.Exception.Message)"
+ }
+ }
+}
+
+function Remove-CtestTestingDirectory {
+ param(
+ [Parameter(Mandatory = $true)]
+ [string]$Path
+ )
+
+ if (-not (Test-Path -LiteralPath $Path)) {
+ return
+ }
+
+ try {
+ Remove-Item -LiteralPath $Path -Recurse -Force -ErrorAction Stop
+ return
+ } catch {
+ Write-Warning "Failed to remove CTest directory '$Path': $($_.Exception.Message)"
+ }
+
+ Get-ChildItem -LiteralPath $Path -Force -Recurse -ErrorAction SilentlyContinue | ForEach-Object {
+ try {
+ if (($_.Attributes -band [System.IO.FileAttributes]::ReadOnly) -ne 0) {
+ $_.Attributes = ($_.Attributes -band (-bnot [System.IO.FileAttributes]::ReadOnly))
+ }
+ } catch { }
+ }
+
+ try {
+ Remove-Item -LiteralPath $Path -Recurse -Force -ErrorAction Stop
+ } catch {
+ Write-Warning "Proceeding with partially cleaned CTest directory '$Path': $($_.Exception.Message)"
+ }
+}
+
+function Remove-NinjaLock {
+ param(
+ [Parameter(Mandatory = $true)]
+ [string]$Path
+ )
+
+ $ninjaLockPath = Join-Path $Path '.ninja_lock'
+ if (Test-Path -LiteralPath $ninjaLockPath) {
+ Remove-Item -LiteralPath $ninjaLockPath -Force
+ }
+}
+
+function Invoke-ProcessWithTimeout {
+ param(
+ [Parameter(Mandatory = $true)]
+ [string]$FilePath,
+
+ [Parameter()]
+ [string[]]$Arguments = @(),
+
+ [Parameter()]
+ [int]$TimeoutSeconds = 0
+ )
+
+ $argumentList = @()
+ foreach ($argument in $Arguments) {
+ if ($argument -match '\s|"') {
+ $argumentList += '"' + ($argument -replace '"', '\"') + '"'
+ }
+ else {
+ $argumentList += $argument
+ }
+ }
+
+ $process = Start-Process -FilePath $FilePath -ArgumentList $argumentList -NoNewWindow -PassThru
+ if ($TimeoutSeconds -le 0) {
+ $process | Wait-Process
+ $completed = $true
+ }
+ else {
+ try {
+ $process | Wait-Process -Timeout $TimeoutSeconds -ErrorAction Stop
+ $completed = $true
+ }
+ catch {
+ $completed = $false
+ }
+ }
+
+ if (-not $completed) {
+ $null = Start-Process -FilePath 'taskkill.exe' `
+ -ArgumentList @('/PID', $process.Id.ToString(), '/T', '/F') `
+ -WindowStyle Hidden -Wait -PassThru
+
+ return @{
+ Completed = $false
+ ExitCode = $null
+ }
+ }
+
+ $process.Refresh()
+ return @{
+ Completed = $true
+ ExitCode = $process.ExitCode
+ }
+}
+
+function Invoke-CMakeBuild {
+ param(
+ [Parameter(Mandatory = $true)]
+ [string]$BuildDir,
+
+ [Parameter()]
+ [int]$Parallel = 1,
+
+ [Parameter()]
+ [int]$TimeoutSeconds = 600
+ )
+
+ Remove-NinjaLock -Path $BuildDir
+ $buildResult = Invoke-ProcessWithTimeout -FilePath 'ninja' -Arguments @(
+ '-C', $BuildDir,
+ '-j', $Parallel.ToString()
+ ) -TimeoutSeconds $TimeoutSeconds
+
+ if ($buildResult.Completed -and ($buildResult.ExitCode -eq 0)) {
+ return
+ }
+
+ if ($buildResult.Completed) {
+ throw "Ninja build failed with exit code $($buildResult.ExitCode) in $BuildDir"
+ }
+
+ Write-Warning "Ninja build timed out after ${TimeoutSeconds}s in $BuildDir. Retrying the interrupted build."
+ Remove-NinjaLock -Path $BuildDir
+ $retryResult = Invoke-ProcessWithTimeout -FilePath 'ninja' -Arguments @(
+ '-C', $BuildDir,
+ '-j', $Parallel.ToString()
+ ) -TimeoutSeconds $TimeoutSeconds
+
+ if ($retryResult.Completed -and ($retryResult.ExitCode -eq 0)) {
+ return
+ }
+
+ if (-not $retryResult.Completed) {
+ throw "Ninja build timed out again after ${TimeoutSeconds}s in $BuildDir"
+ }
+
+ throw "Ninja retry failed with exit code $($retryResult.ExitCode) in $BuildDir"
+}
diff --git a/test/cmake/libs/CMakeLists.txt b/test/cmake/libs/CMakeLists.txt
index f66a8d25a..1e6931a9e 100644
--- a/test/cmake/libs/CMakeLists.txt
+++ b/test/cmake/libs/CMakeLists.txt
@@ -35,3 +35,4 @@ foreach(lib threadx netxduo filex)
endforeach()
endforeach()
endforeach()
+# Portions of this file were generated with AI assistance.
diff --git a/test/cmake/libs/nx_user.h b/test/cmake/libs/nx_user.h
index 3cca9406a..601148414 100644
--- a/test/cmake/libs/nx_user.h
+++ b/test/cmake/libs/nx_user.h
@@ -8,6 +8,7 @@
*
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
/**************************************************************************/
@@ -78,4 +79,3 @@
}
#endif
-
diff --git a/test/cmake/usbx/BASELINE.md b/test/cmake/usbx/BASELINE.md
new file mode 100644
index 000000000..bb043ec02
--- /dev/null
+++ b/test/cmake/usbx/BASELINE.md
@@ -0,0 +1,40 @@
+# GCC 14 baseline
+
+Measured at USBX commit `ffc0f79d951c716a03addcf7255020328e0d5b47`, with the
+dependency revisions in `dependencies.txt`, GCC/gcov 14.3.0 and gcovr 8.6.
+All 17 configurations were configured and built from clean trees with CMake and
+Ninja. CTest ran every configuration once, including configurations with build
+failures: 3,019/3,043 cases passed in 666.17 seconds of summed CTest wall time.
+
+Twenty-three cases could not run because five regression sources had incompatible
+pointer arguments or missing declarations. The sample also lacked device-stack
+declarations. One standalone printer transfer assertion failed. These results
+are retained as failures; a subsequent isolated printer pass does not erase them.
+
+Coverage below uses the existing profile-specific exclusions, so percentages are
+not comparable across profiles and cannot be averaged or merged. A dash means
+the profile was not instrumented. Standalone-device collection initially failed
+gcovr's 2^32 suspicious-hit heuristic; the same raw counters were then collected
+with the documented 2^40 threshold and unchanged exclusions. No tests were rerun
+to produce that coverage. Build times are Ninja execution spans and exclude
+configuration and dependency setup.
+
+| Profile | Passed / tests | Build s | Test s | Lines hit / valid | Branches hit / valid |
+| --- | ---: | ---: | ---: | ---: | ---: |
+| default_build_coverage | 427/430 | 10.838 | 13.89 | 7701/8014 | 3420/3738 |
+| error_check_build_full_coverage | 425/430 | 11.190 | 13.53 | 14767/24084 | 6238/11250 |
+| tracex_enable_build | 427/430 | 11.390 | 13.48 | — | — |
+| device_buffer_owner_build | 427/430 | 11.371 | 11.18 | — | — |
+| device_zero_copy_build | 427/430 | 11.271 | 16.53 | — | — |
+| nofx_build_coverage | 46/46 | 6.778 | 5.57 | 2751/7955 | 993/3738 |
+| optimized_build | 129/129 | 6.893 | 3.46 | — | — |
+| standalone_device_build_coverage | 55/57 | 6.669 | 185.88 | 2625/3098 | 880/1279 |
+| standalone_device_buffer_owner_build | 56/57 | 6.782 | 185.39 | — | — |
+| standalone_device_zero_copy_build | 56/57 | 6.896 | 177.48 | — | — |
+| standalone_host_build_coverage | 44/44 | 6.633 | 20.78 | 4005/5255 | 1464/2289 |
+| standalone_build_coverage | 20/20 | 5.412 | 0.25 | 2011/8277 | 720/3567 |
+| generic_build | 1/1 | 6.047 | 0.01 | — | — |
+| otg_support_build | 427/430 | 10.614 | 11.31 | — | — |
+| memory_management_build_coverage | 11/11 | 6.619 | 4.63 | 4748/8069 | 1715/3780 |
+| msrc_rtos_build | 33/33 | 6.482 | 0.76 | — | — |
+| msrc_standalone_build | 8/8 | 5.069 | 2.04 | — | — |
diff --git a/test/cmake/usbx/CMakeLists.txt b/test/cmake/usbx/CMakeLists.txt
index fb2f69f75..59b881aff 100644
--- a/test/cmake/usbx/CMakeLists.txt
+++ b/test/cmake/usbx/CMakeLists.txt
@@ -3,8 +3,16 @@ cmake_policy(SET CMP0054 NEW)
cmake_policy(SET CMP0057 NEW)
cmake_policy(SET CMP0077 NEW)
+# Suppress try_compile link step when MSVC cannot produce a runnable executable
+# (e.g. when the VS environment is not fully initialised for a given target arch).
+if(MSVC)
+ set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+endif()
+
project(usbx_test LANGUAGES C)
+option(USBX_CI_COVERAGE "Instrument every selected configuration" "$ENV{TX_COVERAGE}")
+
# Use customized ux_user.h
set(UX_USER_FILE ${CMAKE_CURRENT_SOURCE_DIR}/ux_user.h)
@@ -214,31 +222,125 @@ if($ENV{USBX_STATIC})
else()
message(STATUS "Building usbx BUILD_SHARED_LIBS: ${BUILD_SHARED_LIBS}")
endif()
-if(NOT BUILD_SHARED_LIBS)
- if(CMAKE_BUILD_TYPE MATCHES ".*_coverage")
+if(NOT BUILD_SHARED_LIBS AND NOT MSVC)
+ if(USBX_CI_COVERAGE OR CMAKE_BUILD_TYPE MATCHES ".*_coverage")
add_link_options(-fprofile-arcs)
add_link_options(-lgcov)
endif()
endif()
-# Control if it's for 64 bit or 32 bit
-if($ENV{ENABLE_64})
- message(STATUS "Building for 64bit")
+if(MSVC)
+ # Win64/Win32 MSVC simulation path -------------------------------------------
+ message(STATUS "Building for Windows (MSVC) - ${THREADX_ARCH}")
+ # Reduce timing constants so tests run faster under the Win64 simulation
+ # (ThreadX Win64 runs at 5x wall-clock: TX_TIMER_PERIODIC=1ms but
+ # TX_WIN32_TICKS_PER_INTERRUPT=5, so _ux_utility_delay_ms(X) takes X/5 ms).
+ # CDC-ACM device init delay: 1000ms → 100ms (saves ~3s in connection tests).
+ # Enumeration debounce: 100 → 10 ticks (2ms real at N=5) — safe in the
+ # simulator (no spurious disconnects), leaving more time for enumeration in the
+ # 100-tick poll windows used by tests.
+ # NOTE: UX_DEVICE_ADDRESS_SET_WAIT is intentionally left at default (50ms)
+ # because reducing it causes non-deterministic test failures — the simulated
+ # device needs sufficient time to switch to its new address.
+ # NOTE: UX_TEST_HCD_CONNECT_SLEEP left at default (100 ticks). Reducing it
+ # below 100 broke CDC-ACM and CCID activation (UX_HOST_CLASS_CDC_ACM_DEVICE_
+ # INIT_DELAY=100 is already applied, but the host enumeration thread still
+ # needs ~100 ticks to complete class activation).
+ # NOTE: UX_TEST_HCD_DISCONNECT_SLEEP reduced from 100 to 80 ticks. DISCONNECT_
+ # SLEEP must be at least DEACTIVATE_WAIT + ~25-30 ticks (overhead after the
+ # dummy-class sleep completes) so that the old device is fully removed before
+ # the next connect is signalled. At 60-70 ticks the "interfaces_scan" test
+ # failed because the new connect overlapped with the tail-end of the prior
+ # device teardown (freeing interfaces/configuration/device structures). At 80
+ # ticks the gap is large enough for reliable cleanup.
+ # NOTE: UX_TEST_DUMMY_DEACTIVATE_WAIT reduced from 200 to 50 ticks. The
+ # original 200-tick sleep exists to let pending host-class transfers finish,
+ # but the Win64 simulator processes all transfers near-instantly (no real
+ # hardware), so 50 ticks (80ms real) is ample. This means device teardown
+ # completes at ~55 ticks from disconnect; tests that poll for device=NULL
+ # (e.g. CCID, HID-memory, enum_bMaxPacketSize0) can start their next iteration
+ # 145 ticks sooner than with the default 200-tick wait. This constant has a
+ # #ifndef guard in ux_host_class_dummy.c (defaulting to UX_ENUMERATION_THREAD_
+ # WAIT=200) so Linux targets are unaffected.
+ # NOTE: UX_TEST_TICK_SCALE=5 compensates for the 5× faster ThreadX clock only
+ # in ux_test_sleep_break_if() timeouts (which use tx_time_get() comparisons),
+ # so tests like CCID that poll for disconnect/connect completion with tick-based
+ # timeouts get the same real-time budget as on Linux.
+ # NOTE: UX_HOST_CLASS_STORAGE_THREAD_SLEEP_TIME reduced from 2000ms to 400ms.
+ # The storage management thread cycles at this interval; the test suite uses it
+ # as a wait unit (×2 to ×6), so 2000ms causes usbx_ux_host_class_storage_
+ # thread_entry_test to take 66s. At 400ms the simulated storage operations
+ # still complete well within one cycle (operations are near-instant in sim)
+ # while the ×N multipliers provide enough cycle count margin.
+ add_compile_options(/W3 /Zi -DUX_INCLUDE_USER_DEFINE_FILE -DUX_USE_IO_INSTRUCTIONS
+ -DUX_HOST_CLASS_CDC_ACM_DEVICE_INIT_DELAY=100
+ -DUX_HOST_STACK_DEVICE_ATTACH_DEBOUNCE_DELAY=10
+ -DUX_TEST_TICK_SCALE=5
+ -DUX_HOST_CLASS_STORAGE_THREAD_SLEEP_TIME=400
+ -DUX_TEST_HCD_DISCONNECT_SLEEP=80
+ -DUX_TEST_DUMMY_DEACTIVATE_WAIT=50
+ ${${CMAKE_BUILD_TYPE}})
+ add_link_options(/DEBUG /INCREMENTAL:NO)
+
+ # Copy ux_user_win.h into the same custom_inc directory where ux_user.h lands
+ # so that ux_user.h can #include "ux_user_win.h" without additional -I flags.
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ux_user_win.h
+ ${CMAKE_BINARY_DIR}/usbx/custom_inc/ux_user_win.h COPYONLY)
+
+ # On Windows, build ThreadX, FileX and NetXDuo from source.
+ if(NOT DEFINED THREADX_SOURCE_DIR)
+ message(FATAL_ERROR
+ "THREADX_SOURCE_DIR must point to a ThreadX source tree. "
+ "Pass -DTHREADX_SOURCE_DIR= or use build_usbx.ps1.")
+ endif()
+ if(NOT DEFINED FILEX_SOURCE_DIR)
+ message(FATAL_ERROR
+ "FILEX_SOURCE_DIR must point to a FileX source tree. "
+ "Pass -DFILEX_SOURCE_DIR= or use build_usbx.ps1.")
+ endif()
+ if(NOT DEFINED NETXDUO_SOURCE_DIR)
+ message(FATAL_ERROR
+ "NETXDUO_SOURCE_DIR must point to a NetXDuo source tree. "
+ "Pass -DNETXDUO_SOURCE_DIR= or use build_usbx.ps1.")
+ endif()
+
+ add_subdirectory(${THREADX_SOURCE_DIR} threadx_build)
+ # Fast-forward the ThreadX Win64 simulated clock through idle periods so the
+ # regression suite is CPU-bound rather than wall-clock-bound (mirrors the
+ # Linux port's TX_LINUX_NO_IDLE_ENABLE). Applied only to the ThreadX port.
+ target_compile_options(threadx PRIVATE -DTX_WIN32_NO_IDLE_ENABLE)
+ add_subdirectory(${FILEX_SOURCE_DIR} filex_build)
+ # Supply the win64 pointer-extension macros to NetXDuo before adding it.
+ set(NX_USER_FILE "${CMAKE_CURRENT_SOURCE_DIR}/libs/nx_user.h"
+ CACHE FILEPATH "NetX Duo user configuration file" FORCE)
+ add_subdirectory(${NETXDUO_SOURCE_DIR} netxduo_build)
else()
- add_compile_options(-m32)
- add_link_options(-m32)
- message(STATUS "Building for 32bit")
+ if(NOT BUILD_SHARED_LIBS)
+ if(CMAKE_BUILD_TYPE MATCHES ".*_coverage")
+ add_link_options(-fprofile-arcs)
+ add_link_options(-lgcov)
+ endif()
+ endif()
+
+ # Control if it's for 64 bit or 32 bit
+ if($ENV{ENABLE_64})
+ message(STATUS "Building for 64bit")
+ else()
+ add_compile_options(-m32)
+ add_link_options(-m32)
+ message(STATUS "Building for 32bit")
+ endif()
+ add_compile_options(
+ -std=c99
+ -ggdb
+ -g3
+ -gdwarf-2
+ -fdiagnostics-color
+ -DUX_USE_IO_INSTRUCTIONS
+ #-DUX_DEVICE_CLASS_DFU_CUSTOM_REQUEST_ENABLE
+ #-DUX_DEVICE_CLASS_DFU_STATUS_MODE=1
+ ${${CMAKE_BUILD_TYPE}})
endif()
-add_compile_options(
- -std=c99
- -ggdb
- -g3
- -gdwarf-2
- -fdiagnostics-color
- -DUX_USE_IO_INSTRUCTIONS
- #-DUX_DEVICE_CLASS_DFU_CUSTOM_REQUEST_ENABLE
- #-DUX_DEVICE_CLASS_DFU_STATUS_MODE=1
- ${${CMAKE_BUILD_TYPE}})
enable_testing()
@@ -250,61 +352,71 @@ else()
endif()
# TODO: Unmask after adding sample for STANDALONE
-if(NOT (CMAKE_BUILD_TYPE MATCHES "standalone.*"))
+if(NOT MSVC AND NOT (CMAKE_BUILD_TYPE MATCHES "standalone.*"))
add_subdirectory(../usbx/samples samples)
endif()
-# Coverage
-if(CMAKE_BUILD_TYPE MATCHES ".*_coverage")
+# Coverage instrumentation (GCC/Clang only — not supported by MSVC)
+if(NOT MSVC AND (USBX_CI_COVERAGE OR CMAKE_BUILD_TYPE MATCHES ".*_coverage"))
target_compile_options(usbx PRIVATE -fprofile-arcs -ftest-coverage)
target_link_options(usbx PRIVATE -fprofile-arcs -ftest-coverage)
endif()
-# Build ThreadX library once
-execute_process(COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/run.sh build_libs)
-add_custom_target(build_libs ALL COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/run.sh
- build_libs)
-
-add_dependencies(usbx build_libs)
-target_include_directories(usbx PUBLIC ${CMAKE_BINARY_DIR}/../libs/inc)
-
-add_library(threadx SHARED IMPORTED GLOBAL)
-add_library("azrtos::threadx" ALIAS threadx)
-set_target_properties(
- threadx PROPERTIES IMPORTED_LOCATION
- ${CMAKE_BINARY_DIR}/../libs/threadx/libthreadx.so)
-
-add_library(netxduo SHARED IMPORTED GLOBAL)
-add_library("azrtos::netxduo" ALIAS netxduo)
-set_target_properties(
- netxduo PROPERTIES IMPORTED_LOCATION
- ${CMAKE_BINARY_DIR}/../libs/netxduo/libnetxduo.so)
-
-add_library(filex SHARED IMPORTED GLOBAL)
-add_library("azrtos::filex" ALIAS filex)
-set_target_properties(
- filex PROPERTIES IMPORTED_LOCATION
- ${CMAKE_BINARY_DIR}/../libs/filex/libfilex.so)
-
-target_compile_options(
- usbx
- PRIVATE -Werror
- -Wall
- -Wextra
- -pedantic
- -fmessage-length=0
- -fsigned-char
- -ffunction-sections
- -fdata-sections
- -Wunused
- -Wuninitialized
- -Wmissing-declarations
- -Wconversion
- -Wpointer-arith
- -Wshadow
- -Wlogical-op
- -Waggregate-return
- -Wfloat-equal)
+# Build ThreadX/FileX/NetXDuo shared libraries (Linux only)
+if(NOT MSVC)
+ execute_process(COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/run.sh build_libs
+ RESULT_VARIABLE dependency_status)
+ if(NOT dependency_status EQUAL 0)
+ message(FATAL_ERROR "Dependency build failed: ${dependency_status}")
+ endif()
+ add_custom_target(build_libs ALL COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/run.sh
+ build_libs)
+
+ add_dependencies(usbx build_libs)
+ target_include_directories(usbx PUBLIC ${CMAKE_BINARY_DIR}/../libs/inc)
+
+ add_library(threadx SHARED IMPORTED GLOBAL)
+ add_library("azrtos::threadx" ALIAS threadx)
+ set_target_properties(
+ threadx PROPERTIES IMPORTED_LOCATION
+ ${CMAKE_BINARY_DIR}/../libs/threadx/libthreadx.so)
+
+ add_library(netxduo SHARED IMPORTED GLOBAL)
+ add_library("azrtos::netxduo" ALIAS netxduo)
+ set_target_properties(
+ netxduo PROPERTIES IMPORTED_LOCATION
+ ${CMAKE_BINARY_DIR}/../libs/netxduo/libnetxduo.so)
+
+ add_library(filex SHARED IMPORTED GLOBAL)
+ add_library("azrtos::filex" ALIAS filex)
+ set_target_properties(
+ filex PROPERTIES IMPORTED_LOCATION
+ ${CMAKE_BINARY_DIR}/../libs/filex/libfilex.so)
+endif()
+
+if(MSVC)
+ target_compile_options(usbx PRIVATE /W3)
+else()
+ target_compile_options(
+ usbx
+ PRIVATE -Werror
+ -Wall
+ -Wextra
+ -pedantic
+ -fmessage-length=0
+ -fsigned-char
+ -ffunction-sections
+ -fdata-sections
+ -Wunused
+ -Wuninitialized
+ -Wmissing-declarations
+ -Wconversion
+ -Wpointer-arith
+ -Wshadow
+ -Wlogical-op
+ -Waggregate-return
+ -Wfloat-equal)
+endif()
# Remove includes and files not needed from usbx build
set(UX_STANDALONE_HOST_EXCLUDES
@@ -428,9 +540,15 @@ endif()
if(CMAKE_BUILD_TYPE STREQUAL "generic_build")
get_target_property(INCLUDES_LIST usbx INCLUDE_DIRECTORIES)
set(NEW_INCLUDES_LIST "")
+ if(MSVC)
+ set(_port_to_replace "ports/${THREADX_ARCH}/${THREADX_TOOLCHAIN}")
+ else()
+ set(_port_to_replace "ports/linux/gnu")
+ endif()
foreach(INCLUDE_LIST ${INCLUDES_LIST})
- string(REPLACE "ports/linux/gnu" "ports/generic" INCLUDE_LIST ${INCLUDE_LIST})
+ string(REPLACE "${_port_to_replace}" "ports/generic" INCLUDE_LIST ${INCLUDE_LIST})
list(APPEND NEW_INCLUDES_LIST "${INCLUDE_LIST}")
endforeach()
set_target_properties(usbx PROPERTIES INCLUDE_DIRECTORIES "${NEW_INCLUDES_LIST}")
-endif()
\ No newline at end of file
+endif()
+# Portions of this file were generated with AI assistance.
diff --git a/test/cmake/usbx/README.md b/test/cmake/usbx/README.md
new file mode 100644
index 000000000..1011555e9
--- /dev/null
+++ b/test/cmake/usbx/README.md
@@ -0,0 +1,62 @@
+# Linux regression and coverage
+
+The regression workflow builds and tests all 17 profiles on every pull request to
+`dev` or `master`. Its check name is `auto_tests / run_tests`. Workflow
+success alone does not enforce merging: repository rules must separately require
+that check. The staged Otterdog ruleset must remain disabled until this workflow
+is available on `dev`.
+
+Run `scripts/install.sh` on Ubuntu 24.04, then use GCC 14 and its matching gcov with
+CMake and Ninja:
+
+```sh
+TX_COVERAGE=ON ./scripts/build.sh all
+TX_COVERAGE=ON ./scripts/test.sh all
+python3 test/cmake/usbx/test_runner.py
+```
+
+The installer installs gcovr 8.6 in a virtual environment and exports its location
+through GitHub Actions environment files. Outside Actions, activate the reported
+virtual environment before running coverage. `CC` and `GCOV` can select matching
+compiler and coverage executables. The default build and test concurrency is four.
+CTest runs each case once; failing cases are not retried into a passing result.
+
+`dependencies.txt` records immutable ThreadX, FileX and NetX Duo revisions. FileX
+PR #106 is open at the pinned revision; this setup does not assume it has merged.
+Existing dependency checkouts must be clean and match their pins. Remove an old
+checkout explicitly when updating a pin. The ThreadX bootstrap supplies JUnit
+output without runtime edits to dependency files.
+
+Pass profile names instead of `all` to either script, or select them in the manual
+workflow. Build and test output names the exact selection. JUnit files, test logs
+and `build/results.txt` report actual counts and elapsed test times. The generic
+profile's single CTest case is a build-only placeholder, not a functional USB test.
+
+Every selected profile is instrumented when `TX_COVERAGE=ON`, including the generic
+build. Raw JSON, Cobertura XML and HTML use one inclusion policy: all compiled C
+sources matching `common/*/src/*.c`. Host controllers, simulators, optional classes
+and untested source lines remain in the denominator. Dependency and test code are
+outside that policy. No profile-specific diagnostic exclusion affects the union.
+
+Each input must have nonempty JSON, XML and HTML, measured source lines, and
+repository-relative paths. The merger checks that JSON and XML agree and that its
+measured and covered source-line sets equal the exact unions of its inputs.
+Reports and execution counters are cleared before each test selection. A subset
+cannot consume an earlier full run's reports or publish complete coverage.
+Available diagnostics and coverage survive failing tests; missing coverage itself
+fails the runner. Full-suite line and branch floors are in `coverage-floors.json`.
+Standalone polling produces more than six billion positive hits in a single
+profile. Direct GCC 14 output confirms balanced loop counts. Collection uses a
+2^40 suspicious-hit threshold instead of gcovr's default 2^32 heuristic; negative
+counts and parse errors remain fatal, and no lines are ignored to obtain a report.
+
+Only successful complete runs on `master` can deploy Pages. Callers grant the
+permissions required for GitHub to validate the pinned reusable workflow's
+separate deployment job; its test job retains narrower permissions. The template
+bounds installation, build and test steps and uploads diagnostics on failure.
+The manual selector is parsed from the event file, never interpolated as shell
+code. All pull requests retain the full matrix; there is no conditional routing.
+
+Dependabot targets `dev` once its configuration is present on the default branch.
+The cross-repository workflow/bootstrap revision requires a separate review and
+is excluded from routine action updates.
diff --git a/test/cmake/usbx/VALIDATION.md b/test/cmake/usbx/VALIDATION.md
new file mode 100644
index 000000000..df5eb34d8
--- /dev/null
+++ b/test/cmake/usbx/VALIDATION.md
@@ -0,0 +1,75 @@
+# Full-matrix validation
+
+GCC/gcov 14.3.0, gcovr 8.6, CMake and Ninja: 3,043/3,043 tests passed across
+all 17 configurations, with no skips or retries. Summed CTest wall time was
+674.14 seconds. The generic profile contributes one build-only placeholder.
+The compiler errors and original coverage are recorded in [BASELINE.md](BASELINE.md).
+
+| Profile | Passed / tests | Build s | Test s | Lines hit / valid | Branches hit / valid |
+| --- | ---: | ---: | ---: | ---: | ---: |
+| default_build_coverage | 430/430 | 11.879 | 13.99 | 14228/24018 | 5741/11162 |
+| error_check_build_full_coverage | 430/430 | 12.779 | 15.38 | 14914/24084 | 6385/11250 |
+| tracex_enable_build | 430/430 | 12.593 | 14.91 | 14698/24806 | 5768/11272 |
+| device_buffer_owner_build | 430/430 | 12.885 | 14.69 | 15337/25269 | 5994/11474 |
+| device_zero_copy_build | 430/430 | 12.952 | 14.87 | 15291/25242 | 5974/11474 |
+| nofx_build_coverage | 46/46 | 7.399 | 3.96 | 3302/23982 | 1179/11208 |
+| optimized_build | 129/129 | 8.226 | 3.71 | 3604/22895 | 1329/10645 |
+| standalone_device_build_coverage | 57/57 | 7.577 | 190.04 | 8520/24155 | 3131/11106 |
+| standalone_device_buffer_owner_build | 57/57 | 8.021 | 179.81 | 9044/25436 | 3256/11381 |
+| standalone_device_zero_copy_build | 57/57 | 7.503 | 180.82 | 8904/25214 | 3225/11319 |
+| standalone_host_build_coverage | 44/44 | 6.951 | 20.78 | 7659/24626 | 2725/11307 |
+| standalone_build_coverage | 20/20 | 5.490 | 0.25 | 2965/24467 | 1037/11107 |
+| generic_build | 1/1 | 6.589 | 0.00 | 0/24070 | 0/11310 |
+| otg_support_build | 430/430 | 11.547 | 13.46 | 14289/24140 | 5789/11292 |
+| memory_management_build_coverage | 11/11 | 7.130 | 4.53 | 5527/24073 | 1966/11204 |
+| msrc_rtos_build | 33/33 | 7.019 | 0.86 | 7271/24595 | 2602/11492 |
+| msrc_standalone_build | 8/8 | 5.786 | 2.08 | 3567/24991 | 1189/11363 |
+
+Build times are Ninja execution spans, excluding configuration and dependency
+setup. Coverage includes all compiled common C sources under the same policy
+in every profile. The merge contains exactly the raw source-line union:
+**20,991/31,649 lines (66.3244%) and 12,118/22,004 branches (55.0718%)**.
+Every expected JSON, XML and HTML input was nonempty. All source paths were
+repository-relative. An independent raw-JSON set comparison also matched both
+the measured and covered line unions. Standalone transfer/task sources absent
+from the default build contribute to the merged denominator.
+
+Floors are 66% lines and 54.5% branches, with small margins below the measured
+results for simulator scheduling variation. They guard against regression; they
+do not meet the project target of 100%. The broader denominator must not be
+compared to the baseline's filtered default report as if they measured the same
+sources.
+
+Remaining uncovered source lines are included, not excluded:
+
+| Source area | Covered / measured lines | Uncovered lines |
+| --- | ---: | ---: |
+| Core | 4707/5425 | 718 |
+| Device classes | 6568/8962 | 2394 |
+| Host classes | 7995/12407 | 4412 |
+| Hardware host controllers | 0/2317 | 2317 |
+| Network integration | 164/195 | 31 |
+| PictBridge | 1557/2343 | 786 |
+
+Closing these gaps requires controller simulation or hardware tests, additional
+class/protocol scenarios, and error-path tests. Hardware tests were not run.
+The descriptor-size regression covers zero, three-byte and eight-byte invalid
+fields, empty layouts and alignment boundaries; the two previously unhit lines
+are now covered and that source has 100% measured line coverage in the default
+profile.
+
+Runner tests exercise failed fetch/checkout, a real CMake dependency error, a
+real failing CTest case, missing/empty coverage inputs, unsafe manual selectors,
+and a real gcovr merge with overlapping and disjoint lines. Eight tests pass.
+The complete report also passes the configured line and branch floors.
+An additional failing CTest case injected into the built generic profile returned
+failure while retaining real gcovr JSON/XML/HTML and JUnit diagnostics. A following
+manual generic-only run passed 1/1 and produced exactly one profile's reports,
+labelled subset, with no stale merged report.
+
+The baseline standalone printer assertion failed once and passed in the complete
+revised run. No printer behavior change or retry is claimed as its fix.
+
+Actionlint, ShellCheck and whitespace checks pass. The Ubuntu installer completes
+with matching GCC/gcov and the pinned gcovr environment. The staged dev ruleset
+remains disabled until workflow rollout; passing CI is not merge enforcement.
diff --git a/test/cmake/usbx/coverage-floors.json b/test/cmake/usbx/coverage-floors.json
new file mode 100644
index 000000000..dd7a99fca
--- /dev/null
+++ b/test/cmake/usbx/coverage-floors.json
@@ -0,0 +1 @@
+{"lines": 66.0, "branches": 54.5}
diff --git a/test/cmake/usbx/coverage.py b/test/cmake/usbx/coverage.py
new file mode 100644
index 000000000..97ffcadc3
--- /dev/null
+++ b/test/cmake/usbx/coverage.py
@@ -0,0 +1,176 @@
+#!/usr/bin/env python3
+"""Collect one consistent source universe and verify every merge input."""
+import json
+import os
+from pathlib import Path, PurePosixPath
+import re
+import shutil
+import subprocess
+import sys
+import xml.etree.ElementTree as ET
+
+ROOT = Path(__file__).resolve().parents[3]
+HERE = Path(__file__).resolve().parent
+REPORT = HERE / 'coverage_report'
+POLICY = r'common/[^/]+/src/[^/]+\.c$'
+
+
+def profiles():
+ """Read the same profile list used by CMake and the bootstrap."""
+ text = (HERE / 'CMakeLists.txt').read_text()
+ block = text.split('set(BUILD_CONFIGURATIONS', 1)[1].split(')', 1)[0]
+ return re.findall(r'[a-z_]*build[a-z_]*', block)
+
+
+def nonempty(path):
+ """Reject absent and zero-byte artifacts before publishing."""
+ if not path.is_file() or not path.stat().st_size:
+ raise ValueError(f'Missing or empty coverage input: {path.name}')
+
+
+def source_name(name):
+ """Require repository-relative USBX source paths without traversal."""
+ if PurePosixPath(name).is_absolute() or '..' in PurePosixPath(name).parts or not re.fullmatch(POLICY, name):
+ raise ValueError(f'Invalid coverage source: {name}')
+
+
+def trace_lines(path):
+ """Return measured and covered source-line sets from an unfiltered trace."""
+ nonempty(path)
+ data = json.loads(path.read_text())
+ measured, covered = set(), set()
+ for entry in data['files']:
+ name = entry['file']
+ source_name(name)
+ for line in entry['lines']:
+ if line.get('gcovr/excluded', False) or line.get('gcovr/noncode', False):
+ continue
+ key = (name, line['line_number'])
+ measured.add(key)
+ if line['count'] > 0:
+ covered.add(key)
+ if not measured:
+ raise ValueError(f'No measured source lines: {path.name}')
+ return measured, covered
+
+
+def xml_lines(path):
+ """Validate Cobertura denominators and repository-relative filenames."""
+ nonempty(path)
+ root = ET.parse(path).getroot()
+ measured, covered = set(), set()
+ for entry in root.findall('.//class'):
+ name = entry.attrib['filename']
+ source_name(name)
+ for line in entry.findall('./lines/line'):
+ key = (name, int(line.attrib['number']))
+ measured.add(key)
+ if int(line.attrib['hits']) > 0:
+ covered.add(key)
+ if not measured or len(measured) != int(root.attrib['lines-valid']):
+ raise ValueError(f'Invalid source-line denominator: {path.name}')
+ if len(covered) != int(root.attrib['lines-covered']):
+ raise ValueError(f'Invalid covered-line count: {path.name}')
+ if any(source.text not in ('.', '') for source in root.findall('./sources/source')):
+ raise ValueError('Coverage source root must be repository-relative')
+ return measured, covered
+
+
+def relative_xml(path):
+ """Normalize gcovr's source root without changing file or line records."""
+ tree = ET.parse(path)
+ for source in tree.findall('./sources/source'):
+ source.text = '.'
+ tree.write(path, encoding='utf-8', xml_declaration=True)
+
+
+def generate(base, inputs):
+ """Generate all formats from the same gcovr invocation and policy."""
+ base.mkdir(parents=True, exist_ok=True)
+ args = ['gcovr', '--root', str(ROOT), '--filter', POLICY,
+ '--gcov-executable', os.environ.get('GCOV', 'gcov-14'),
+ '--merge-mode-functions', 'separate',
+ # Standalone polling legitimately exceeds gcovr's 32-bit heuristic.
+ '--gcov-suspicious-hits-threshold', str(2**40),
+ '--json', str(base.with_suffix('.json')),
+ '--xml', str(base.with_suffix('.xml')), '--xml-pretty',
+ '--html-details', str(base / 'index.html'), *inputs]
+ subprocess.run(args, cwd=ROOT, check=True)
+ relative_xml(base.with_suffix('.xml'))
+ verify(base)
+
+
+def verify(base):
+ """Check all expected formats and their exact line-set agreement."""
+ nonempty(base / 'index.html')
+ actual = trace_lines(base.with_suffix('.json'))
+ if actual != xml_lines(base.with_suffix('.xml')):
+ raise ValueError(f'JSON/XML line mismatch: {base.name}')
+ return actual
+
+
+def merge():
+ """Merge only the current selection, retaining every measured input line."""
+ # Remove old aggregate reports before checking inputs, including failure paths.
+ for name in ('merged', 'subset'):
+ shutil.rmtree(REPORT / name, ignore_errors=True)
+ for suffix in ('.json', '.xml'):
+ (REPORT / (name + suffix)).unlink(missing_ok=True)
+ selection = (REPORT / 'profiles.txt').read_text().splitlines()
+ available = profiles()
+ if not selection or len(set(selection)) != len(selection) or not set(selection) <= set(available):
+ raise ValueError('Invalid coverage profile selection')
+ expected, hit = set(), set()
+ inputs = []
+ for profile in selection:
+ base = REPORT / 'per_configuration' / profile
+ lines, covered = verify(base)
+ expected |= lines
+ hit |= covered
+ inputs += ['--add-tracefile', str(base.with_suffix('.json'))]
+ complete = set(selection) == set(available) and (REPORT / 'full-suite').is_file()
+ base = REPORT / ('merged' if complete else 'subset')
+ generate(base, inputs)
+ if verify(base) != (expected, hit):
+ raise ValueError('Merged report differs from the exact source-line union')
+ root = ET.parse(base.with_suffix('.xml')).getroot()
+ summary = f"{'Complete' if complete else 'Subset'} coverage: {len(selection)}/{len(available)} profiles; "
+ for label in ('lines', 'branches'):
+ covered, valid = int(root.attrib[f'{label}-covered']), int(root.attrib[f'{label}-valid'])
+ if valid == 0:
+ raise ValueError(f'Empty {label} denominator')
+ rate = covered * 100 / valid
+ summary += f'{label} {covered}/{valid} ({rate:.4f}%); '
+ print(summary)
+ (REPORT / 'summary.txt').write_text(summary + '\n')
+ if os.environ.get('GITHUB_STEP_SUMMARY'):
+ with open(os.environ['GITHUB_STEP_SUMMARY'], 'a') as stream:
+ stream.write(summary + '\n')
+ if complete:
+ floors = json.loads((HERE / 'coverage-floors.json').read_text())
+ for label, minimum in floors.items():
+ if int(root.attrib[f'{label}-covered']) * 100 < int(root.attrib[f'{label}-valid']) * minimum:
+ raise ValueError(f'{label} coverage is below {minimum}%')
+
+
+def main():
+ """Dispatch collection or union validation with a failing exit on any error."""
+ if sys.argv[1:] == ['--merge']:
+ merge()
+ elif len(sys.argv) == 2 and sys.argv[1] in profiles():
+ profile = sys.argv[1]
+ if profile not in (REPORT / 'profiles.txt').read_text().splitlines():
+ raise ValueError('Profile does not belong to this test run')
+ objects = HERE / 'build' / profile / 'usbx' / 'CMakeFiles' / 'usbx.dir' / 'common'
+ if not any(objects.rglob('*.gcno')):
+ raise ValueError(f'No instrumented objects: {profile}')
+ generate(REPORT / 'per_configuration' / profile, [str(objects)])
+ else:
+ raise ValueError('Expected a known profile or --merge')
+
+
+if __name__ == '__main__':
+ try:
+ main()
+ except (ValueError, OSError, KeyError, ET.ParseError, subprocess.CalledProcessError) as error:
+ sys.exit(str(error))
diff --git a/test/cmake/usbx/coverage.sh b/test/cmake/usbx/coverage.sh
index f5f30c714..9efe8a176 100755
--- a/test/cmake/usbx/coverage.sh
+++ b/test/cmake/usbx/coverage.sh
@@ -1,124 +1,4 @@
#!/bin/bash
-
-set -e
-
-cd $(dirname $0)
-root_path=$(cd ../../../common; pwd)
-
-# Exclude strings
-exclude_file_list=" $root_path/*/src/*_class_asix*"
-exclude_file_list+=" $root_path/*/src/*_class_audio*"
-exclude_file_list+=" $root_path/*/src/*_class_ccid*"
-exclude_file_list+=" $root_path/*/src/*_class_dfu*"
-exclude_file_list+=" $root_path/*/src/*_class_gser*"
-exclude_file_list+=" $root_path/*/src/*_class_pima*"
-exclude_file_list+=" $root_path/*/src/*_class_rndis*"
-exclude_file_list+=" $root_path/*/src/*_class_printer*"
-exclude_file_list+=" $root_path/*/src/*_class_prolific*"
-exclude_file_list+=" $root_path/*/src/*_class_swar*"
-exclude_file_list+=" $root_path/*/src/*_class_video*"
-exclude_file_list+=" $root_path/*/src/*_hnp_*"
-exclude_file_list+=" $root_path/*/src/*_role_*"
-exclude_file_list+=" $root_path/*/src/ux_utility_set_interrupt_handler.c"
-exclude_file_list+=" $root_path/*/src/*dcd_sim_slave*"
-exclude_file_list+=" $root_path/*/src/*device_class_dpump*"
-exclude_file_list+=" $root_path/*/src/*hcd_sim_host*"
-exclude_file_list+=" $root_path/*/src/*host_class_dpump*"
-exclude_file_list+=" $root_path/*/src/*ux_network_driver*"
-
-# Device HID interrupt OUT related
-exclude_file_list+=" $root_path/*/src/ux_device_class_hid_read.c"
-exclude_file_list+=" $root_path/*/src/ux_device_class_hid_receiver*"
-
-# CB/CBI related
-exclude_file_list+=" $root_path/*/src/*_storage*_cb.c"
-exclude_file_list+=" $root_path/*/src/*_storage*_cbi.c"
-
-# CD/DVD related things
-exclude_file_list+=" $root_path/*/src/*_storage_get_status*"
-exclude_file_list+=" $root_path/*/src/*_storage_get_configuration*"
-exclude_file_list+=" $root_path/*/src/*_storage_get_performance*"
-exclude_file_list+=" $root_path/*/src/*_storage_read_disk_information*"
-exclude_file_list+=" $root_path/*/src/*_storage_report_key*"
-exclude_file_list+=" $root_path/*/src/*_storage_read_dvd*"
-exclude_file_list+=" $root_path/*/src/*_storage_read_toc*"
-
-# Obsolete
-exclude_file_list+=" $root_path/*/src/ux_device_stack_interface_get.c"
-exclude_file_list+=" $root_path/*/src/ux_host_stack_delay_ms.c"
-
-# Host controllers
-exclude_file_list+=" $root_path/usbx_host_controllers/src/*"
-
-# Pictbridge related files
-exclude_file_list+=" $root_path/usbx_pictbridge/src/*"
-
-# Host related files
-exclude_host_list=" $root_path/*/src/*_host_*"
-
-# Device related files
-exclude_device_list=" $root_path/*/src/*_device_*"
-
-# RTOS related files
-exclude_rtos_list=" $root_path/*/src/*_thread*"
-exclude_rtos_list+=" $root_path/*/src/*_event_*"
-exclude_rtos_list+=" $root_path/*/src/*_mutex_*"
-exclude_rtos_list+=" $root_path/*/src/*_semaphore_*"
-exclude_rtos_list+=" $root_path/*/src/*_timer_*"
-
-exclude_rtos_list+=" $root_path/*/src/*_cdc_ecm_*"
-
-exclude_rtos_list+=" $root_path/*/src/*_hub_*"
-
-exclude_rtos_list+=" $root_path/*/src/*_cdc_acm_capabilities_get.c"
-exclude_rtos_list+=" $root_path/*/src/*_cdc_acm_configure.c"
-
-exclude_rtos_list+=" $root_path/*/src/*_hid_configure.c"
-exclude_rtos_list+=" $root_path/*/src/*_hid_descriptor_parse.c"
-exclude_rtos_list+=" $root_path/*/src/*_hid_report_descriptor_get.c"
-
-exclude_rtos_list+=" $root_path/*/src/*_storage_configure.c"
-exclude_rtos_list+=" $root_path/*/src/*_storage_media_mount.c"
-exclude_rtos_list+=" $root_path/*/src/*_storage_media_open.c"
-exclude_rtos_list+=" $root_path/*/src/*_storage_partition_read.c"
-exclude_rtos_list+=" $root_path/*/src/*_storage_transport.c"
-
-# Standalone related files
-exclude_standalone_list=" $root_path/*/src/*_run.c"
-
-if [[ $1 = *"_full_coverage" ]]; then
-
- exclude_options=""
-else
-
- exclude_options=""
- for f in $exclude_file_list;do
- exclude_options+=" -e $f"
- done
-
- if [[ $1 = *"_device_"* ]]; then
- for f in $exclude_host_list;do
- exclude_options+=" -e $f"
- done
- fi
-
- if [[ $1 = *"_host_"* ]]; then
- for f in $exclude_device_list;do
- exclude_options+=" -e $f"
- done
- fi
-
- if [[ $1 = "standalone_"* ]]; then
- for f in $exclude_rtos_list;do
- exclude_options+=" -e $f"
- done
- else
- for f in $exclude_standalone_list;do
- exclude_options+=" -e $f"
- done
- fi
-fi
-
-mkdir -p coverage_report/$1
-gcovr --object-directory=build/$1/usbx/CMakeFiles/usbx.dir/common -r ../../../common $exclude_options --xml-pretty --output coverage_report/$1.xml
-gcovr --object-directory=build/$1/usbx/CMakeFiles/usbx.dir/common -r ../../../common $exclude_options --html --html-details --html-high-threshold 100.0 --output coverage_report/$1/index.html
+set -euo pipefail
+cd "$(dirname "$0")"
+exec python3 coverage.py "$@"
diff --git a/test/cmake/usbx/dependencies.txt b/test/cmake/usbx/dependencies.txt
new file mode 100644
index 000000000..5fd5cf43e
--- /dev/null
+++ b/test/cmake/usbx/dependencies.txt
@@ -0,0 +1,3 @@
+threadx b37cd4a81a1cb8c2ebefc438220ab7f009e13362
+filex 79c703d917e648c615ae6e0c253e63a73bb134a5
+netxduo 400e647de10a71763e9facea2b98667bfa93b285
diff --git a/test/cmake/usbx/libs/CMakeLists.txt b/test/cmake/usbx/libs/CMakeLists.txt
new file mode 100644
index 000000000..1e6931a9e
--- /dev/null
+++ b/test/cmake/usbx/libs/CMakeLists.txt
@@ -0,0 +1,38 @@
+cmake_minimum_required(VERSION 3.13 FATAL_ERROR)
+
+project(libs LANGUAGES C)
+
+if($ENV{ENABLE_64})
+ message(STATUS "Building for 64bit")
+ set(NX_USER_FILE ${CMAKE_CURRENT_SOURCE_DIR}/nx_user.h)
+else()
+ add_compile_options(-m32)
+ add_link_options(-m32)
+ message(STATUS "Building for 32bit")
+endif()
+message(STATUS "Using toolchain file: ${CMAKE_TOOLCHAIN_FILE}.")
+
+get_filename_component(externals ${CMAKE_CURRENT_SOURCE_DIR}/../../../externals
+ ABSOLUTE)
+add_subdirectory(${externals}/threadx threadx)
+add_subdirectory(${externals}/netxduo netxduo)
+add_subdirectory(${externals}/filex filex)
+target_compile_options(threadx PRIVATE -DTX_ENABLE_EVENT_TRACE)
+if(NOT DEFINED ENV{ENABLE_IDLE})
+ target_compile_options(threadx PRIVATE -DTX_LINUX_NO_IDLE_ENABLE)
+endif()
+target_compile_options(filex PRIVATE -DFX_ENABLE_EXFAT)
+
+target_compile_options(netxduo PRIVATE -DTX_ENABLE_EVENT_TRACE -DNX_PHYSICAL_HEADER=20)
+
+foreach(lib threadx netxduo filex)
+ get_target_property(dirs ${lib} INCLUDE_DIRECTORIES)
+ execute_process(COMMAND mkdir -p ${CMAKE_BINARY_DIR}/inc)
+ foreach(dir ${dirs})
+ file(GLOB header_files ${dir}/*.h)
+ foreach(header_file ${header_files})
+ execute_process(COMMAND ln -sf ${header_file} ${CMAKE_BINARY_DIR}/inc)
+ endforeach()
+ endforeach()
+endforeach()
+# Portions of this file were generated with AI assistance.
diff --git a/test/cmake/usbx/libs/nx_user.h b/test/cmake/usbx/libs/nx_user.h
new file mode 100644
index 000000000..601148414
--- /dev/null
+++ b/test/cmake/usbx/libs/nx_user.h
@@ -0,0 +1,81 @@
+/***************************************************************************
+ * Copyright (c) 2024 Microsoft Corporation
+ * Copyright (c) 2026-present Eclipse ThreadX contributors
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the MIT License which is available at
+ * https://opensource.org/licenses/MIT.
+ *
+ * SPDX-License-Identifier: MIT
+ **************************************************************************/
+// Portions of this file were generated with AI assistance.
+
+
+/**************************************************************************/
+/**************************************************************************/
+/** */
+/** NetX Component */
+/** */
+/** User Specific */
+/** */
+/**************************************************************************/
+/**************************************************************************/
+
+
+/**************************************************************************/
+/* */
+/* PORT SPECIFIC C INFORMATION RELEASE */
+/* */
+/* nx_user.h PORTABLE C */
+/* 6.0 */
+/* */
+/* AUTHOR */
+/* */
+/* Yuxin Zhou, Microsoft Corporation */
+/* */
+/* DESCRIPTION */
+/* */
+/* This file contains user defines for configuring NetX in specific */
+/* ways. This file will have an effect only if the application and */
+/* NetX library are built with NX_INCLUDE_USER_DEFINE_FILE defined. */
+/* Note that all the defines in this file may also be made on the */
+/* command line when building NetX library and application objects. */
+/* */
+/**************************************************************************/
+
+#ifndef NX_USER_H
+#define NX_USER_H
+
+/* Define the extension to hold the control block for 64-bit mode. */
+#define NX_THREAD_EXTENSION_PTR_SET(a, b) { \
+ TX_THREAD *thread_ptr; \
+ thread_ptr = (TX_THREAD *) (a); \
+ (thread_ptr -> tx_thread_extension_ptr) = (VOID *)(b); \
+ }
+#define NX_THREAD_EXTENSION_PTR_GET(a, b, c) { \
+ NX_PARAMETER_NOT_USED(c); \
+ TX_THREAD *thread_ptr; \
+ thread_ptr = tx_thread_identify(); \
+ while(1)\
+ { \
+ if (thread_ptr -> tx_thread_extension_ptr) \
+ { \
+ (a) = (b *)(thread_ptr -> tx_thread_extension_ptr); \
+ break; \
+ } \
+ tx_thread_sleep(1); \
+ } \
+ }
+#define NX_TIMER_EXTENSION_PTR_SET(a, b) { \
+ TX_TIMER *timer_ptr; \
+ timer_ptr = (TX_TIMER *) (a); \
+ (timer_ptr -> tx_timer_internal.tx_timer_internal_extension_ptr) = (VOID *)(b); \
+ }
+#define NX_TIMER_EXTENSION_PTR_GET(a, b, c) { \
+ NX_PARAMETER_NOT_USED(c); \
+ if (!_tx_timer_expired_timer_ptr -> tx_timer_internal_extension_ptr) \
+ return; \
+ (a) = (b *)(_tx_timer_expired_timer_ptr -> tx_timer_internal_extension_ptr); \
+ }
+
+#endif
diff --git a/test/cmake/usbx/regression/CMakeLists.txt b/test/cmake/usbx/regression/CMakeLists.txt
index 729559c49..95dc36ea6 100644
--- a/test/cmake/usbx/regression/CMakeLists.txt
+++ b/test/cmake/usbx/regression/CMakeLists.txt
@@ -173,6 +173,7 @@ set(ux_class_hid_test_cases
${SOURCE_DIR}/usbx_ux_host_class_hid_descriptor_parse_coverage_test.c
${SOURCE_DIR}/usbx_ux_host_class_hid_descriptor_parse_test2.c
${SOURCE_DIR}/usbx_ux_host_class_hid_descriptor_parse_test4.c
+ ${SOURCE_DIR}/usbx_ux_host_class_hid_report_item_bounds_test.c
${SOURCE_DIR}/usbx_ux_host_class_hid_descriptor_parse_test5.c
${SOURCE_DIR}/usbx_hid_keyboard_extraction_test2.c
${SOURCE_DIR}/usbx_hid_mouse_extraction_test2.c
@@ -236,6 +237,7 @@ set(ux_class_hid_test_cases
${SOURCE_DIR}/usbx_hid_report_descriptor_delimiter_test.c
${SOURCE_DIR}/usbx_hid_report_descriptor_delimiter_unknown_test.c
${SOURCE_DIR}/usbx_hid_report_descriptor_end_collection_error_test.c
+ ${SOURCE_DIR}/usbx_ux_host_class_hid_report_walk_bounds_test.c
${SOURCE_DIR}/usbx_hid_report_descriptor_example_andisplay_test.c
${SOURCE_DIR}/usbx_hid_report_descriptor_example_delimit_test.c
${SOURCE_DIR}/usbx_hid_report_descriptor_example_digit_test.c
@@ -291,6 +293,7 @@ set(ux_class_hid_host_standalone_test_cases
${SOURCE_DIR}/usbx_class_hid_basic_memory_test.c
${SOURCE_DIR}/usbx_ux_host_class_hid_report_set_int_out_test.c
${SOURCE_DIR}/usbx_uxe_host_hid_test.c
+ ${SOURCE_DIR}/usbx_ux_host_class_hid_report_walk_bounds_test.c
)
set(ux_class_hid_standalone_test_cases
)
@@ -534,6 +537,7 @@ set(ux_class_video_test_cases
${SOURCE_DIR}/usbx_ux_host_class_video_dwMaxPayloadTransferSize_test.c
${SOURCE_DIR}/usbx_ux_host_class_video_format_frame_based_test.c # device control buffer > 512
${SOURCE_DIR}/usbx_ux_host_class_video_format_h264_test.c # device control buffer > 512
+ ${SOURCE_DIR}/usbx_ux_host_class_video_format_walk_bounds_test.c
${SOURCE_DIR}/usbx_uxe_device_video_test.c
${SOURCE_DIR}/usbx_uxe_host_video_test.c
)
@@ -562,6 +566,8 @@ set(ux_msrc_test_cases_rtos
${SOURCE_DIR}/usbx_msrc_66679_test.c
${SOURCE_DIR}/usbx_msrc_72427_ecm_host_mac_test.c
${SOURCE_DIR}/usbx_msrc_72525_host_pima_obj_handles_get_test.c
+ ${SOURCE_DIR}/usbx_ghsa_2ch9_host_pima_obj_handles_bound_test.c
+ ${SOURCE_DIR}/usbx_ghsa_2ch9_host_pima_info_bounds_test.c
${SOURCE_DIR}/usbx_msrc_72619_host_pima_stor_ids_get_test.c
${SOURCE_DIR}/usbx_msrc_72526_pictbridge_dps_host_start_test.c
${SOURCE_DIR}/usbx_msrc_72227_host_pima_read_test.c
@@ -646,6 +652,9 @@ set(test_utility_files
add_library(test_utility ${test_utility_files})
target_link_libraries(test_utility PUBLIC azrtos::usbx azrtos::threadx azrtos::netxduo azrtos::filex)
target_compile_definitions(test_utility PUBLIC CTEST)
+if(MSVC)
+ target_compile_options(test_utility PRIVATE /W3)
+endif()
if (CMAKE_BUILD_TYPE MATCHES "msrc_rtos_build")
set(test_cases
@@ -734,9 +743,38 @@ else()
endif()
endif()
+# Exclude test files that use GCC/Clang-specific directives (#warning) not
+# supported by MSVC in C mode. At configure time, create patched copies in
+# the build directory that replace "#warning " with the MSVC-compatible
+# "#pragma message()" directive. Original source files are never modified, so
+# Linux builds are unaffected.
+if(MSVC)
+ set(_msvc_test_cases)
+ foreach(_src ${test_cases})
+ file(READ "${_src}" _content)
+ if(_content MATCHES "#warning")
+ get_filename_component(_fname "${_src}" NAME)
+ set(_dst "${CMAKE_CURRENT_BINARY_DIR}/msvc_compat/${_fname}")
+ string(REGEX REPLACE
+ "#warning ([^\n\r]*)"
+ "#pragma message(\"warning: \\1\")"
+ _content "${_content}")
+ file(WRITE "${_dst}" "${_content}")
+ list(APPEND _msvc_test_cases "${_dst}")
+ else()
+ list(APPEND _msvc_test_cases "${_src}")
+ endif()
+ endforeach()
+ set(test_cases "${_msvc_test_cases}")
+endif()
+
foreach(test_case ${test_cases})
get_filename_component(test_name ${test_case} NAME_WE)
add_executable(${test_name} ${test_case})
target_link_libraries(${test_name} PRIVATE test_utility)
+ if(MSVC)
+ target_compile_options(${test_name} PRIVATE /W3)
+ endif()
add_test(${CMAKE_BUILD_TYPE}::${test_name} ${test_name})
endforeach()
+# Portions of this file were generated with AI assistance.
diff --git a/test/cmake/usbx/report.py b/test/cmake/usbx/report.py
new file mode 100644
index 000000000..11a31ca46
--- /dev/null
+++ b/test/cmake/usbx/report.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python3
+"""Summarize the actual JUnit results, including failed or missing runs."""
+import os
+import re
+from pathlib import Path
+import sys
+import xml.etree.ElementTree as ET
+
+rows = ['| Profile | Passed / tests | Seconds |', '| --- | ---: | ---: |']
+failed = False
+for profile in sys.argv[1:]:
+ path = Path('build') / profile / f'{profile}.xml'
+ try:
+ root = ET.parse(path).getroot()
+ cases = root.findall('.//testcase')
+ passed = sum(case.get('status') == 'run' and
+ case.find('failure') is None and case.find('skipped') is None
+ for case in cases)
+ log = path.with_suffix('.txt').read_text()
+ duration = re.search(r'Total Test time \(real\) =\s*([0-9.]+) sec', log)
+ if duration is None:
+ raise ValueError(f'Missing duration: {profile}')
+ seconds = float(duration.group(1))
+ rows.append(f'| {profile} | {passed} / {len(cases)} | {seconds:.2f} |')
+ failed |= not cases or passed != len(cases)
+ except (OSError, ET.ParseError, ValueError):
+ rows.append(f'| {profile} | missing results | — |')
+ failed = True
+text = '\n'.join(rows) + '\n'
+print(text)
+Path('build/results.md').write_text(text, encoding='utf-8')
+# The reusable workflow uploads build/*.txt on failure as well as success.
+Path('build/results.txt').write_text(text, encoding='utf-8')
+if os.environ.get('GITHUB_STEP_SUMMARY'):
+ with open(os.environ['GITHUB_STEP_SUMMARY'], 'a', encoding='utf-8') as stream:
+ stream.write(text)
+sys.exit(int(failed))
diff --git a/test/cmake/usbx/run.sh b/test/cmake/usbx/run.sh
index 040343f3b..e5a9197a5 100755
--- a/test/cmake/usbx/run.sh
+++ b/test/cmake/usbx/run.sh
@@ -1,17 +1,106 @@
#!/bin/bash
+set -euo pipefail
+cd "$(dirname "$0")"
-cd $(dirname $0)
+# Resolve only the reviewed revisions; never alter an existing checkout.
+mkdir -p ../../externals
+while read -r dependency revision; do
+ [[ "$revision" =~ ^[0-9a-f]{40}$ ]] || exit 1
+ destination="../../externals/$dependency"
+ if [ ! -e "$destination" ]; then
+ temporary=$(mktemp -d "../../externals/.${dependency}.XXXXXX")
+ trap 'rm -rf -- "$temporary"' EXIT
+ git init -q "$temporary"
+ git -C "$temporary" remote add origin "https://github.com/eclipse-threadx/$dependency.git"
+ timeout 180 git -C "$temporary" fetch --depth 1 origin "$revision"
+ git -C "$temporary" checkout -q --detach "$revision"
+ mv -- "$temporary" "$destination"
+ trap - EXIT
+ fi
+ if [ "$(git -C "$destination" rev-parse HEAD)" != "$revision" ] ||
+ [ -n "$(git -C "$destination" status --porcelain --untracked-files=no)" ]; then
+ echo "Dependency $dependency must be clean at $revision." >&2
+ exit 1
+ fi
+ printf 'Dependency: %s %s\n' "$dependency" "$revision"
+done < dependencies.txt
-# Checkout externals
-[ -d externals ] || mkdir ../../externals
-git clone https://github.com/eclipse-threadx/threadx.git ../../externals/threadx
-git clone https://github.com/eclipse-threadx/netxduo.git ../../externals/netxduo
-git clone https://github.com/eclipse-threadx/filex.git ../../externals/filex
+bootstrap=../../externals/threadx/scripts/cmake_bootstrap.sh
+[ -s "$bootstrap" ]
+ln -sfn "$bootstrap" .run.sh
+if [ "${1:-}" = build_libs ]; then
+ exec ./.run.sh build_libs
+fi
-# Add junit output for ctest generation
-if ! grep -q "\-\-output\-junit \$1.xml" ../../externals/threadx/scripts/cmake_bootstrap.sh; then
- sed -i 's/ctest $parallel --timeout 1000 -O $1.txt/& --output-junit $1.xml/g' ../../externals/threadx/scripts/cmake_bootstrap.sh
+command=${1:-}
+shift || true
+manual_full=true
+if [ "${1:-}" = --manual ]; then
+ manual_full=$(python3 -c 'import json, os; print(str(json.load(open(os.environ["GITHUB_EVENT_PATH"]))["inputs"].get("tests_to_run", "all") == "all").lower())')
+ mapfile -t manual < <(python3 -c 'import json, os; print("\n".join(json.load(open(os.environ["GITHUB_EVENT_PATH"]))["inputs"].get("tests_to_run", "all").split()))')
+ [ "${#manual[@]}" -gt 0 ] || exit 1
+ set -- "${manual[@]}"
+fi
+mapfile -t available < <(sed -n '/^set(BUILD_CONFIGURATIONS/,/^ )/p' CMakeLists.txt | grep -oE '[a-z_]*build[a-z_]*')
+if [ "$#" -eq 0 ]; then
+ selected=("${available[0]}")
+elif [ "$*" = all ]; then
+ selected=("${available[@]}")
+else
+ selected=("$@")
+fi
+for profile in "${selected[@]}"; do
+ if ! printf '%s\n' "${available[@]}" | grep -qxF "$profile"; then
+ echo "Unknown profile: $profile" >&2
+ exit 1
+ fi
+done
+if [ "$(printf '%s\n' "${selected[@]}" | sort -u | wc -l)" -ne "${#selected[@]}" ]; then
+ echo 'Duplicate profiles are not allowed.' >&2
+ exit 1
fi
+full_suite=false
+if [ "$*" = all ] && "$manual_full"; then full_suite=true; fi
+printf 'Selected profiles (%s): %s\n' "${#selected[@]}" "${selected[*]}"
+export CTEST_REPEAT_FAIL=1
+export CTEST_PARALLEL_LEVEL=${CTEST_PARALLEL_LEVEL:-4}
-[ -f .run.sh ] || ln -sf ../../externals/threadx/scripts/cmake_bootstrap.sh .run.sh
-./.run.sh $*
\ No newline at end of file
+case "$command" in
+ build)
+ # Fresh build trees prevent compiler, instrumentation and gcda reuse.
+ rm -rf coverage_report
+ rm -f build/built-profiles.txt
+ for profile in "${selected[@]}"; do
+ rm -rf -- "build/$profile"
+ done
+ ./.run.sh build "${selected[@]}"
+ mkdir -p build
+ printf '%s\n' "${selected[@]}" > build/built-profiles.txt
+ printf 'Built profiles (%s): %s\n' "${#selected[@]}" "${selected[*]}"
+ ;;
+ test)
+ # Clear reports even for subsets, before validating their build inputs.
+ rm -rf coverage_report
+ mkdir -p coverage_report
+ printf '%s\n' "${selected[@]}" > coverage_report/profiles.txt
+ if "$full_suite"; then touch coverage_report/full-suite; fi
+ for profile in "${selected[@]}"; do
+ grep -qxF "$profile" build/built-profiles.txt
+ [ -s "build/$profile/CTestTestfile.cmake" ]
+ if [ "${TX_COVERAGE:-OFF}" = ON ]; then
+ grep -qxF 'USBX_CI_COVERAGE:BOOL=ON' "build/$profile/CMakeCache.txt"
+ fi
+ find "build/$profile" -name '*.gcda' -delete
+ rm -f -- "build/$profile/$profile.xml"
+ done
+ status=0
+ ./.run.sh test "${selected[@]}" || status=$?
+ python3 report.py "${selected[@]}" || status=1
+ printf 'Tested profiles (%s): %s\n' "${#selected[@]}" "${selected[*]}"
+ exit "$status"
+ ;;
+ *)
+ echo 'Usage: run.sh {build|test|build_libs} [all|profile ...]' >&2
+ exit 1
+ ;;
+esac
diff --git a/test/cmake/usbx/test_runner.py b/test/cmake/usbx/test_runner.py
new file mode 100644
index 000000000..d3b7deb1a
--- /dev/null
+++ b/test/cmake/usbx/test_runner.py
@@ -0,0 +1,239 @@
+#!/usr/bin/env python3
+"""Exercise failure propagation in isolated runner trees using real CTest."""
+import importlib.util
+import json
+import os
+from pathlib import Path
+import shutil
+import subprocess
+import tempfile
+import unittest
+
+HERE = Path(__file__).resolve().parent
+SPEC = importlib.util.spec_from_file_location('coverage_checks', HERE / 'coverage.py')
+coverage = importlib.util.module_from_spec(SPEC)
+SPEC.loader.exec_module(coverage)
+
+
+class RunnerFailures(unittest.TestCase):
+ """Fault injections leave the production build and dependency trees intact."""
+
+ def setUp(self):
+ """Create a disposable runner with the same pinned dependencies."""
+ self.temporary = tempfile.TemporaryDirectory()
+ self.addCleanup(self.temporary.cleanup)
+ self.root = Path(self.temporary.name)
+ self.runner = self.root / 'test/cmake/usbx'
+ self.runner.mkdir(parents=True)
+ externals = self.root / 'test/externals'
+ externals.mkdir()
+ for name in ('threadx', 'filex', 'netxduo'):
+ (externals / name).symlink_to(HERE.parents[1] / 'externals' / name)
+ for name in ('run.sh', 'dependencies.txt', 'report.py'):
+ shutil.copy2(HERE / name, self.runner / name)
+ (self.runner / 'CMakeLists.txt').write_text('set(BUILD_CONFIGURATIONS\n generic_build\n )\n')
+ self.env = dict(os.environ, CC='gcc-14', GCOV='gcov-14',
+ CTEST_PARALLEL_LEVEL='1', TX_COVERAGE='OFF')
+
+ def run_command(self, *arguments):
+ """Capture diagnostics and return the runner's actual exit status."""
+ return subprocess.run(['bash', './run.sh', *arguments], cwd=self.runner,
+ env=self.env, text=True, stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT, timeout=60)
+
+ def test_manual_input_is_data(self):
+ """Shell metacharacters in a manual selector cannot execute commands."""
+ event = self.root / 'event.json'
+ event.write_text(json.dumps({'inputs': {'tests_to_run': 'generic_build; touch injected'}}))
+ self.env['GITHUB_EVENT_PATH'] = str(event)
+ result = self.run_command('test', '--manual')
+ self.assertNotEqual(result.returncode, 0, result.stdout)
+ self.assertIn('Unknown profile', result.stdout)
+ self.assertFalse((self.runner / 'injected').exists())
+
+ def test_checkout_failure(self):
+ """A failed fetch cannot continue into configuration or testing."""
+ (self.root / 'test/externals/threadx').unlink()
+ bin_dir = self.root / 'bin'
+ bin_dir.mkdir()
+ git = shutil.which('git')
+ wrapper = bin_dir / 'git'
+ wrapper.write_text(f'#!/bin/bash\nfor arg in "$@"; do\n'
+ ' if [ "$arg" = fetch ]; then exit 71; fi\ndone\n'
+ f'exec {git} "$@"\n')
+ wrapper.chmod(0o755)
+ self.env['PATH'] = str(bin_dir) + os.pathsep + self.env['PATH']
+ result = self.run_command('build', 'all')
+ self.assertEqual(result.returncode, 71, result.stdout)
+ self.assertFalse((self.runner / 'build').exists())
+
+ self.env['USBX_TEST_DEPENDENCY'] = str(HERE.parents[1] / 'externals/threadx')
+ wrapper.write_text(
+ '#!/bin/bash\n'
+ 'if [ "${3:-}" = checkout ]; then exit 72; fi\n'
+ f'if [ "${{3:-}}" = fetch ]; then exec {git} -C "$2" fetch '
+ '--depth 1 "$USBX_TEST_DEPENDENCY" "$7"; fi\n'
+ f'exec {git} "$@"\n')
+ result = self.run_command('build', 'all')
+ self.assertEqual(result.returncode, 72, result.stdout)
+ self.assertFalse((self.runner / 'build').exists())
+
+ def test_dependency_build_failure(self):
+ """An actual CMake dependency error propagates through the bootstrap."""
+ libs = self.runner / 'libs'
+ libs.mkdir()
+ (libs / 'CMakeLists.txt').write_text(
+ 'cmake_minimum_required(VERSION 3.13)\nproject(failure NONE)\n'
+ 'message(FATAL_ERROR "injected dependency failure")\n')
+ result = self.run_command('build_libs')
+ self.assertNotEqual(result.returncode, 0, result.stdout)
+ self.assertIn('injected dependency failure', result.stdout)
+
+ (libs / 'CMakeLists.txt').write_text(
+ 'cmake_minimum_required(VERSION 3.13)\nproject(failure NONE)\n'
+ 'add_custom_target(failing_dependency ALL COMMAND ${CMAKE_COMMAND} -E false)\n')
+ result = self.run_command('build_libs')
+ self.assertNotEqual(result.returncode, 0, result.stdout)
+ self.assertIn('failing_dependency', result.stdout)
+ self.assertIn('FAILED', result.stdout)
+
+ def test_ctest_failure_keeps_diagnostics_and_collects_coverage(self):
+ """A failing CTest case stays red while collection still executes."""
+ source = self.root / 'fixture'
+ source.mkdir()
+ (source / 'CMakeLists.txt').write_text(
+ 'cmake_minimum_required(VERSION 3.13)\nproject(failure NONE)\n'
+ 'enable_testing()\nadd_test(NAME injected_failure COMMAND '
+ '${CMAKE_COMMAND} -E false)\n')
+ build = self.runner / 'build/generic_build'
+ subprocess.run(['cmake', '-S', str(source), '-B', str(build), '-G', 'Ninja',
+ '-DUSBX_CI_COVERAGE:BOOL=ON'], check=True, capture_output=True)
+ subprocess.run(['cmake', '--build', str(build)], check=True, capture_output=True)
+ (build.parent / 'built-profiles.txt').write_text('generic_build\n')
+ report = self.runner / 'coverage_report'
+ report.mkdir()
+ (report / 'merged.xml').write_text('stale')
+ # Record both bootstrap coverage callbacks independently of gcovr.
+ collector = self.runner / 'coverage.sh'
+ collector.write_text('#!/bin/bash\nprintf "%s\\n" "$1" >> coverage_report/collected.txt\n')
+ collector.chmod(0o755)
+ self.env['TX_COVERAGE'] = 'ON'
+ result = self.run_command('test', 'all')
+ self.assertNotEqual(result.returncode, 0, result.stdout)
+ self.assertIn('injected_failure', (build / 'generic_build.xml').read_text())
+ self.assertTrue(list((build / 'Testing/Temporary').glob('LastTest*.log')))
+ self.assertEqual((report / 'collected.txt').read_text(), 'generic_build\n--merge\n')
+ self.assertFalse((report / 'merged.xml').exists())
+
+ def test_missing_coverage_fails_runner(self):
+ """Passing CTest cannot hide missing coverage objects or tracefiles."""
+ source = self.root / 'fixture'
+ source.mkdir()
+ (source / 'CMakeLists.txt').write_text(
+ 'cmake_minimum_required(VERSION 3.13)\nproject(passing NONE)\n'
+ 'enable_testing()\nadd_test(NAME passing COMMAND '
+ '${CMAKE_COMMAND} -E true)\n')
+ build = self.runner / 'build/generic_build'
+ subprocess.run(['cmake', '-S', str(source), '-B', str(build), '-G', 'Ninja',
+ '-DUSBX_CI_COVERAGE:BOOL=ON'], check=True, capture_output=True)
+ subprocess.run(['cmake', '--build', str(build)], check=True, capture_output=True)
+ (build.parent / 'built-profiles.txt').write_text('generic_build\n')
+ for name in ('coverage.sh', 'coverage.py', 'coverage-floors.json'):
+ shutil.copy2(HERE / name, self.runner / name)
+ self.env['TX_COVERAGE'] = 'ON'
+ result = self.run_command('test', 'all')
+ self.assertNotEqual(result.returncode, 0, result.stdout)
+ self.assertIn('100% tests passed', result.stdout)
+ self.assertIn('No instrumented objects', result.stdout)
+ self.assertIn('Missing or empty coverage input', result.stdout)
+
+ collector = self.runner / 'coverage.sh'
+ collector.write_text(
+ '#!/bin/bash\nset -e\n'
+ 'if [ "$1" = --merge ]; then exec python3 coverage.py --merge; fi\n'
+ 'mkdir -p coverage_report/per_configuration/generic_build\n'
+ 'touch coverage_report/per_configuration/generic_build/index.html\n'
+ 'touch coverage_report/per_configuration/generic_build.json\n'
+ 'touch coverage_report/per_configuration/generic_build.xml\n')
+ result = self.run_command('test', 'all')
+ self.assertNotEqual(result.returncode, 0, result.stdout)
+ self.assertIn('100% tests passed', result.stdout)
+ self.assertIn('Missing or empty coverage input', result.stdout)
+
+
+class CoverageInputs(unittest.TestCase):
+ """Reject missing, empty, invalid and non-relative raw inputs."""
+
+ def setUp(self):
+ """Allocate a temporary tracefile independent of matrix outputs."""
+ self.temporary = tempfile.TemporaryDirectory()
+ self.addCleanup(self.temporary.cleanup)
+ self.path = Path(self.temporary.name) / 'trace.json'
+
+ def test_missing_and_empty(self):
+ """Both missing and zero-byte files fail before merging."""
+ with self.assertRaises(ValueError):
+ coverage.trace_lines(self.path)
+ self.path.touch()
+ with self.assertRaises(ValueError):
+ coverage.trace_lines(self.path)
+ self.path.write_text('{"files": []}')
+ with self.assertRaises(ValueError):
+ coverage.trace_lines(self.path)
+
+ def test_source_policy_and_lines(self):
+ """Keep host and device sources, including their uncovered lines."""
+ files = [{'file': f'common/{area}/src/probe.c', 'lines': [
+ {'line_number': 10, 'count': 1}, {'line_number': 20, 'count': 0}]
+ } for area in ('core', 'usbx_host_classes', 'usbx_device_classes')]
+ self.path.write_text(json.dumps({'files': files}))
+ measured, covered = coverage.trace_lines(self.path)
+ self.assertEqual(len(measured), 6)
+ self.assertEqual(len(covered), 3)
+ for name in ('/absolute/probe.c', '../probe.c', 'test/probe.c'):
+ files[0]['file'] = name
+ self.path.write_text(json.dumps({'files': files}))
+ with self.assertRaises(ValueError):
+ coverage.trace_lines(self.path)
+
+
+class CoverageMerge(unittest.TestCase):
+ """Exercise gcovr's real merge with overlapping and disjoint source lines."""
+
+ def test_union_and_missing_input_invalidation(self):
+ """The union keeps unhit lines and invalidates stale aggregate reports."""
+ with tempfile.TemporaryDirectory() as directory:
+ previous = coverage.REPORT
+ coverage.REPORT = Path(directory)
+ self.addCleanup(setattr, coverage, 'REPORT', previous)
+ selection = coverage.profiles()[:2]
+ (coverage.REPORT / 'profiles.txt').write_text('\n'.join(selection) + '\n')
+ source = 'common/core/src/ux_dcd_sim_slave_endpoint_create.c'
+ expected = set()
+ for profile, numbers in zip(selection, ((87, 90), (87, 93))):
+ lines = []
+ for number in numbers:
+ expected.add((source, number))
+ lines.append({'line_number': number, 'count': int(number == 87),
+ 'branches': [{'count': 1, 'fallthrough': True,
+ 'throw': False, 'source_block_id': 2,
+ 'destination_block_id': 3}]})
+ raw = coverage.REPORT / f'{profile}-input.json'
+ raw.write_text(json.dumps({'gcovr/format_version': '0.14', 'files': [
+ {'file': source, 'lines': lines, 'functions': []}]}))
+ coverage.generate(coverage.REPORT / 'per_configuration' / profile,
+ ['--add-tracefile', str(raw)])
+ coverage.merge()
+ measured, covered = coverage.verify(coverage.REPORT / 'subset')
+ self.assertEqual(measured, expected)
+ self.assertEqual(covered, {(source, 87)})
+ self.assertFalse((coverage.REPORT / 'merged.xml').exists())
+ (coverage.REPORT / 'per_configuration' / (selection[1] + '.json')).write_text('')
+ with self.assertRaises(ValueError):
+ coverage.merge()
+ self.assertFalse((coverage.REPORT / 'subset.xml').exists())
+
+
+if __name__ == '__main__':
+ os.environ.pop('GITHUB_STEP_SUMMARY', None)
+ unittest.main()
diff --git a/test/cmake/usbx/ux_user.h b/test/cmake/usbx/ux_user.h
index 091e51ad1..fa12c2712 100644
--- a/test/cmake/usbx/ux_user.h
+++ b/test/cmake/usbx/ux_user.h
@@ -8,6 +8,7 @@
*
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
/**************************************************************************/
@@ -330,5 +331,9 @@ void ux_test_assert_hit(char* file, int line);
#include "usbh_core.h"
#endif
+/* Windows simulation port overrides (LLP64 pointer extension macros, etc.) */
+#ifdef _WIN32
+#include "ux_user_win.h"
#endif
+#endif
diff --git a/test/cmake/usbx/ux_user_win.h b/test/cmake/usbx/ux_user_win.h
new file mode 100644
index 000000000..9ea13e1ef
--- /dev/null
+++ b/test/cmake/usbx/ux_user_win.h
@@ -0,0 +1,98 @@
+/***************************************************************************
+ * Copyright (c) 2024 Microsoft Corporation
+ * Copyright (C) 2026 Eclipse ThreadX contributors
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the MIT License which is available at
+ * https://opensource.org/licenses/MIT.
+ *
+ * SPDX-License-Identifier: MIT
+ **************************************************************************/
+// Portions of this file were generated with AI assistance.
+
+/* AI Disclosure: This file was largely AI-generated by Copilot (Claude Sonnet 4.6). */
+
+/**************************************************************************/
+/**************************************************************************/
+/** */
+/** USBX Component */
+/** */
+/** User Specific — Windows Simulation Port */
+/** */
+/**************************************************************************/
+/**************************************************************************/
+
+
+/**************************************************************************/
+/* */
+/* PORT SPECIFIC C INFORMATION RELEASE */
+/* */
+/* ux_user_win.h Win32/Win64 */
+/* 6.5.2.202603 */
+/* */
+/* AUTHOR */
+/* */
+/* Frédéric Desbiens */
+/* */
+/* DESCRIPTION */
+/* */
+/* This file overrides selected USBX configuration constants for the */
+/* Windows simulation port. It is included by ux_user.h (which is */
+/* included when UX_INCLUDE_USER_DEFINE_FILE is defined). */
+/* */
+/* This file is intended for test builds only; it is not part of any */
+/* production configuration. */
+/* */
+/**************************************************************************/
+
+#ifndef UX_USER_WIN_H
+#define UX_USER_WIN_H
+
+
+/* On 64-bit Windows the ABI is LLP64: ULONG is 32 bits while pointers are
+ 64 bits. USBX thread/timer entry functions receive control-block pointers
+ through a ULONG parameter, which silently truncates the upper 32 bits.
+ The UX_THREAD_EXTENSION_PTR_SET/GET and UX_TIMER_EXTENSION_PTR_SET/GET
+ hooks work around this by storing the full 64-bit pointer in the TX_THREAD
+ / TX_TIMER_INTERNAL extension field (a VOID *) and recovering it via
+ tx_thread_identify() / the expired-timer pointer.
+ Win32 builds are unaffected: on ILP32/LLP32 ULONG and pointers are both
+ 32 bits so the default no-op macros in ux_api.h are correct. */
+
+#ifdef _WIN64
+
+#define UX_THREAD_EXTENSION_PTR_SET(a, b) { \
+ TX_THREAD *_tx_ptr; \
+ _tx_ptr = (TX_THREAD *)(a); \
+ (_tx_ptr -> tx_thread_extension_ptr) = (VOID *)(b); \
+ }
+#define UX_THREAD_EXTENSION_PTR_GET(a, b, c) { \
+ UX_PARAMETER_NOT_USED(c); \
+ TX_THREAD *_tx_ptr; \
+ _tx_ptr = tx_thread_identify(); \
+ while (1) \
+ { \
+ if (_tx_ptr -> tx_thread_extension_ptr) \
+ { \
+ (a) = (b *)(_tx_ptr -> tx_thread_extension_ptr); \
+ break; \
+ } \
+ tx_thread_sleep(1); \
+ } \
+ }
+#define UX_TIMER_EXTENSION_PTR_SET(a, b) { \
+ TX_TIMER *_timer_ptr; \
+ _timer_ptr = (TX_TIMER *)(a); \
+ (_timer_ptr -> tx_timer_internal.tx_timer_internal_extension_ptr) = (VOID *)(b); \
+ }
+#define UX_TIMER_EXTENSION_PTR_GET(a, b, c) { \
+ UX_PARAMETER_NOT_USED(c); \
+ if (!_tx_timer_expired_timer_ptr -> tx_timer_internal_extension_ptr) \
+ return; \
+ (a) = (b *)(_tx_timer_expired_timer_ptr -> tx_timer_internal_extension_ptr); \
+ }
+
+#endif /* _WIN64 */
+
+
+#endif /* UX_USER_WIN_H */
diff --git a/test/regression/usbx_class_multi_interface_enumeration_test.c b/test/regression/usbx_class_multi_interface_enumeration_test.c
index d33d57c05..64e5c128e 100644
--- a/test/regression/usbx_class_multi_interface_enumeration_test.c
+++ b/test/regression/usbx_class_multi_interface_enumeration_test.c
@@ -9,6 +9,8 @@
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/* This test is designed to test the simple dpump host/device class operation. */
#include
@@ -21,6 +23,18 @@
#include "ux_test.h"
+/* Scale factor for the hand-rolled tick-based connect/remove wait loops below.
+ On ports where ThreadX ticks advance faster than 1ms/tick (e.g. the Win32/
+ Win64 simulator with tick batching TX_WIN32_TICKS_PER_INTERRUPT=5) a raw
+ N-tick budget represents 1/scale of the intended real time, which is too
+ tight on slower single-core hosts. Multiplying by UX_TEST_TICK_SCALE (set
+ to the batch factor on those ports, 1 elsewhere) restores the same real-time
+ budget these waits get on Linux. */
+#ifndef UX_TEST_TICK_SCALE
+#define UX_TEST_TICK_SCALE 1
+#endif
+
+
/* Define USBX demo constants. */
#define UX_DEMO_STACK_SIZE 4096
@@ -345,6 +359,8 @@ UX_HOST_CLASS *cls;
static UINT ux_demo_dummy_instance_connect_wait(ULONG wait_ticks)
{
ULONG t0 = tx_time_get(), t1;
+ if (wait_ticks != 0 && wait_ticks != 0xFFFFFFFFul)
+ wait_ticks *= UX_TEST_TICK_SCALE;
while(1)
{
#if defined(UX_HOST_STANDALONE)
@@ -377,6 +393,8 @@ ULONG t0 = tx_time_get(), t1;
static UINT ux_demo_dummy_instance_remove_wait(ULONG wait_ticks)
{
ULONG t0 = tx_time_get(), t1;
+ if (wait_ticks != 0 && wait_ticks != 0xFFFFFFFFul)
+ wait_ticks *= UX_TEST_TICK_SCALE;
while(1)
{
#if defined(UX_HOST_STANDALONE)
diff --git a/test/regression/usbx_ghsa_2ch9_host_pima_info_bounds_test.c b/test/regression/usbx_ghsa_2ch9_host_pima_info_bounds_test.c
new file mode 100644
index 000000000..2c4e3125d
--- /dev/null
+++ b/test/regression/usbx_ghsa_2ch9_host_pima_info_bounds_test.c
@@ -0,0 +1,4029 @@
+/***************************************************************************
+ * Copyright (c) 2026 Eclipse ThreadX contributors
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the MIT License which is available at
+ * https://opensource.org/licenses/MIT.
+ *
+ * AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5).
+ * The AI-generated portions may be considered public domain (CC0-1.0)
+ * and not subject to the project's licence. The human contributor has
+ * reviewed and verified that the code is correct.
+ *
+ * SPDX-License-Identifier: MIT and CC0-1.0
+ **************************************************************************/
+
+/* This test drives the PIMA host GetDeviceInfo parser with a device whose declared
+ field lengths accumulate past the end of the fixed receive buffer. Each length is
+ individually inside its own cap, so every per field check passes; it is the running
+ total that leaves the allocation. */
+
+#include
+#include "tx_api.h"
+#include "fx_api.h"
+#include "ux_api.h"
+#include "ux_system.h"
+#include "ux_utility.h"
+
+#include "ux_device_class_pima.h"
+#include "ux_host_class_pima.h"
+
+#include "ux_hcd_sim_host.h"
+#include "ux_device_stack.h"
+
+#include "ux_test_dcd_sim_slave.h"
+#include "ux_test_hcd_sim_host.h"
+#include "ux_test_utility_sim.h"
+
+
+/* Define constants. */
+#define UX_TEST_STACK_SIZE (2*1024)
+#define UX_TEST_MEMORY_SIZE (512*1024)
+
+#define UX_TEST_RAM_DISK_SIZE (128*1024)
+#define UX_TEST_RAM_DISK_LAST_LBA ((UX_TEST_RAM_DISK_SIZE / 512) - 1)
+
+#define UX_TEST_MAX_HANDLES 16
+#define UX_TEST_MAX_DATASET_HEADER 32
+#define UX_TEST_MAX_DATASET_SIZE 1024
+#define UX_TEST_PIMA_STORAGE_ID 1
+#define UX_TEST_VENDOR_REQUEST 0x54
+
+#define UX_TEST_CUSTOM_VID 0x0000
+#define UX_TEST_CUSTOM_PID 0x0000
+
+#define UX_TEST_AUDIO_CODEC_WAVE_FORMAT_MPEGLAYER3 0x00000055
+#define UX_TEST_AUDIO_CODEC_WAVE_FORMAT_MPEG 0x00000050
+#define UX_TEST_AUDIO_CODEC_WAVE_FORMAT_RAW_AAC1 0x000000FF
+
+
+/* Define local/extern function prototypes. */
+
+extern VOID _fx_ram_driver(FX_MEDIA *media_ptr);
+
+static void test_thread_entry(ULONG);
+
+static TX_THREAD test_thread_host_simulation;
+static TX_THREAD test_thread_device_simulation;
+static void test_thread_host_simulation_entry(ULONG);
+static void test_thread_device_simulation_entry(ULONG);
+
+static VOID test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params);
+static VOID test_hcd_entry_interaction_request_sem_put(UX_TEST_ACTION *action, VOID *params);
+static VOID test_hcd_entry_interaction_invoked(UX_TEST_ACTION *action, VOID *params);
+static VOID test_hcd_entry_interaction_wait_transfer_disconnection(UX_TEST_ACTION *action, VOID *params);
+
+static VOID test_pima_instance_activate(VOID *pima_instance);
+static VOID test_pima_instance_deactivate(VOID *pima_instance);
+
+UINT pima_device_device_reset();
+UINT pima_device_device_prop_desc_get(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG device_property,
+ UCHAR **device_prop_dataset,
+ ULONG *device_prop_dataset_length);
+UINT pima_device_device_prop_value_get(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG device_property,
+ UCHAR **device_prop_value,
+ ULONG *device_prop_value_length);
+UINT pima_device_device_prop_value_set(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG device_property,
+ UCHAR *device_prop_value,
+ ULONG device_prop_value_length);
+UINT pima_device_storage_format(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG storage_id);
+UINT pima_device_storage_info_get(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG storage_id);
+UINT pima_device_object_number_get(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_format_code,
+ ULONG object_association,
+ ULONG *object_number);
+UINT pima_device_object_handles_get (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handles_format_code,
+ ULONG object_handles_association,
+ ULONG *object_handles_array,
+ ULONG object_handles_max_number);
+UINT pima_device_object_info_get (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle,
+ UX_SLAVE_CLASS_PIMA_OBJECT **object);
+UINT pima_device_object_data_get (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle,
+ UCHAR *object_buffer,
+ ULONG object_offset,
+ ULONG object_length_requested,
+ ULONG *object_actual_length);
+UINT pima_device_object_info_send (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ UX_SLAVE_CLASS_PIMA_OBJECT *object,
+ ULONG storage_id,
+ ULONG parent_object_handle,
+ ULONG *object_handle);
+UINT pima_device_object_data_send (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle,
+ ULONG phase ,
+ UCHAR *object_buffer,
+ ULONG object_offset,
+ ULONG object_length);
+UINT pima_device_object_delete(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle);
+UINT pima_device_object_prop_desc_get (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_property,
+ ULONG object_format_code,
+ UCHAR **object_prop_dataset,
+ ULONG *object_prop_dataset_length);
+UINT pima_device_object_prop_value_get (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle,
+ ULONG object_property,
+ UCHAR **object_prop_value,
+ ULONG *object_prop_value_length);
+UINT pima_device_object_prop_value_set (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle,
+ ULONG object_property,
+ UCHAR *object_prop_value,
+ ULONG object_prop_value_length);
+UINT pima_device_object_references_get (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle,
+ UCHAR **object_references_array,
+ ULONG *object_references_array_length);
+UINT pima_device_object_references_set (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle,
+ UCHAR *object_references_array,
+ ULONG object_references_array_length);
+UINT pima_device_object_handle_check(ULONG object_handle,
+ UX_SLAVE_CLASS_PIMA_OBJECT **object,
+ ULONG *caller_handle_index);
+UINT pima_device_device_class_custom_entry(UX_SLAVE_CLASS_COMMAND *command);
+UINT pima_device_vendor_request(ULONG request, ULONG request_value, ULONG request_index, ULONG request_length,
+ UCHAR *transfer_request_buffer,
+ ULONG *transfer_request_length);
+
+
+/* Define global data structures. */
+static UCHAR usbx_memory[UX_TEST_MEMORY_SIZE + (UX_TEST_STACK_SIZE * 2)];
+
+static UX_SLAVE_CLASS_PIMA *pima_device;
+static UX_SLAVE_CLASS_PIMA_PARAMETER pima_device_parameter;
+
+static UX_HOST_CLASS_PIMA *pima_host;
+static UX_HOST_CLASS_PIMA_SESSION pima_host_session;
+static UX_HOST_CLASS_PIMA_DEVICE pima_host_device;
+static UX_HOST_CLASS_PIMA_OBJECT pima_host_object;
+static UX_HOST_CLASS_PIMA_STORAGE pima_host_storage;
+
+static ULONG host_buffer[4096];
+static UCHAR *host_buffer8 = (UCHAR *)host_buffer;
+static USHORT *host_buffer16 = (USHORT *)host_buffer;
+static ULONG *host_buffer32 = (ULONG *)host_buffer;
+
+static FX_MEDIA ram_disk;
+static CHAR ram_disk_memory[UX_TEST_RAM_DISK_SIZE];
+static CHAR ram_disk_buffer[2048];
+
+
+static ULONG error_counter;
+
+static ULONG set_cfg_counter;
+
+static ULONG rsc_mem_free_on_set_cfg;
+static ULONG rsc_sem_on_set_cfg;
+static ULONG rsc_sem_get_on_set_cfg;
+static ULONG rsc_mutex_on_set_cfg;
+
+static ULONG rsc_enum_sem_usage;
+static ULONG rsc_enum_sem_get_count;
+static ULONG rsc_enum_mutex_usage;
+static ULONG rsc_enum_mem_usage;
+
+static ULONG rsc_cdc_sem_usage;
+static ULONG rsc_cdc_sem_get_count;
+static ULONG rsc_cdc_mutex_usage;
+static ULONG rsc_cdc_mem_usage;
+
+static ULONG interaction_count;
+
+static UCHAR error_callback_ignore = UX_TRUE;
+static ULONG error_callback_counter;
+
+
+/* Structure of the Object property dataset. This is specific to the local device. */
+typedef struct TEST_PIMA_OBJECT_PROP_DATASET_STRUCT
+{
+ ULONG test_pima_object_prop_dataset_storage_id;
+ ULONG test_pima_object_prop_dataset_object_format;
+ ULONG test_pima_object_prop_dataset_protection_status;
+ ULONG test_pima_object_prop_dataset_object_size_low;
+ ULONG test_pima_object_prop_dataset_object_size_high;
+ UCHAR test_pima_object_prop_dataset_object_file_name[128];
+ ULONG test_pima_object_prop_dataset_parent_object;
+ ULONG test_pima_object_prop_dataset_persistent_unique_object_identifier[4];
+ UCHAR test_pima_object_prop_dataset_name[128];
+ UCHAR test_pima_object_prop_dataset_non_consumable;
+ UCHAR test_pima_object_prop_dataset_artist[128];
+ ULONG test_pima_object_prop_dataset_track;
+ ULONG test_pima_object_prop_dataset_use_count;
+ UCHAR test_pima_object_prop_dataset_date_authored[16];
+ UCHAR test_pima_object_prop_dataset_genre[128];
+ UCHAR test_pima_object_prop_dataset_album_name[128];
+ UCHAR test_pima_object_prop_dataset_album_artist[128];
+ ULONG test_pima_object_prop_dataset_sample_rate;
+ ULONG test_pima_object_prop_dataset_number_of_channels;
+ ULONG test_pima_object_prop_dataset_audio_wave_codec;
+ ULONG test_pima_object_prop_dataset_audio_bitrate;
+ ULONG test_pima_object_prop_dataset_duration;
+ ULONG test_pima_object_prop_dataset_width;
+ ULONG test_pima_object_prop_dataset_height;
+ ULONG test_pima_object_prop_dataset_scan_type;
+ ULONG test_pima_object_prop_dataset_fourcc_codec;
+ ULONG test_pima_object_prop_dataset_video_bitrate;
+ ULONG test_pima_object_prop_dataset_frames_per_thousand_seconds;
+ ULONG test_pima_object_prop_dataset_keyframe_distance;
+ UCHAR test_pima_object_prop_dataset_encoding_profile[128];
+
+} TEST_PIMA_PROP_DATASET;
+
+
+/* Define device framework. */
+
+UCHAR device_framework_full_speed[] = {
+
+ /* Device descriptor */
+ 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08,
+ 0xE8, 0x04, 0xC5, 0x68, 0x00, 0x00, 0x01, 0x02,
+ 0x03, 0x01,
+
+ /* Configuration descriptor */
+ 0x09, 0x02, 0x27, 0x00, 0x01, 0x01, 0x00, 0xc0,
+ 0x32,
+
+ /* Interface descriptor */
+ 0x09, 0x04, 0x00, 0x00, 0x03, 0x06, 0x01, 0x01,
+ 0x00,
+
+ /* Endpoint descriptor (Bulk In) */
+ 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00,
+
+ /* Endpoint descriptor (Bulk Out) */
+ 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00,
+
+ /* Endpoint descriptor (Interrupt In) */
+ 0x07, 0x05, 0x83, 0x03, 0x40, 0x00, 0x04
+};
+#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed)
+
+UCHAR device_framework_high_speed[] = {
+
+ /* Device descriptor */
+ 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
+ 0xE8, 0x04, 0xC5, 0x68, 0x01, 0x00, 0x01, 0x02,
+ 0x03, 0x01,
+
+ /* Device qualifier descriptor */
+ 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
+ 0x01, 0x00,
+
+ /* Configuration descriptor */
+ 0x09, 0x02, 0x27, 0x00, 0x01, 0x01, 0x00, 0xc0,
+ 0x32,
+
+ /* Interface descriptor */
+ 0x09, 0x04, 0x00, 0x00, 0x03, 0x06, 0x01, 0x01,
+ 0x00,
+
+ /* Endpoint descriptor (Bulk In) */
+ 0x07, 0x05, 0x81, 0x02, 0x00, 0x02, 0x00,
+
+ /* Endpoint descriptor (Bulk Out) */
+ 0x07, 0x05, 0x02, 0x02, 0x00, 0x02, 0x00,
+
+ /* Endpoint descriptor (Interrupt In) */
+ 0x07, 0x05, 0x83, 0x03, 0x40, 0x00, 0x04
+};
+#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed)
+
+/* String Device Framework :
+ Byte 0 and 1 : Word containing the language ID : 0x0904 for US or 0x0000 for none.
+ Byte 2 : Byte containing the index of the descriptor
+ Byte 3 : Byte containing the length of the descriptor string
+
+ The last string entry can be the optional Microsoft String descriptor.
+*/
+UCHAR string_framework[] = {
+
+ /* Manufacturer string descriptor : Index 1 */
+ 0x09, 0x04, 0x01, 0x0c,
+ 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x20, 0x4c,
+ 0x6f, 0x67, 0x69, 0x63,
+
+ /* Product string descriptor : Index 2 */
+ 0x09, 0x04, 0x02, 0x0a,
+ 0x4d, 0x54, 0x50, 0x20, 0x70, 0x6c, 0x61, 0x79,
+ 0x65, 0x72,
+
+ /* Serial Number string descriptor : Index 3 */
+ 0x09, 0x04, 0x03, 0x04,
+ 0x30, 0x30, 0x30, 0x31,
+
+ /* Microsoft OS string descriptor : Index 0xEE. String is MSFT100.
+ The last byte is the vendor code used to filter Vendor specific commands.
+ The vendor commands will be executed in the class.
+ This code can be anything but must not be 0x66 or 0x67 which are PIMA class commands. */
+ 0x00, 0x00, 0xEE, 0x08,
+ 0x4D, 0x53, 0x46, 0x54,
+ 0x31, 0x30, 0x30,
+ UX_TEST_VENDOR_REQUEST
+
+};
+#define STRING_FRAMEWORK_LENGTH sizeof(string_framework)
+
+/* Multiple languages are supported on the device, to add
+ a language besides english, the unicode language code must
+ be appended to the language_id_framework array and the length
+ adjusted accordingly. */
+UCHAR language_id_framework[] = {
+
+ /* English. */
+ 0x09, 0x04
+};
+#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework)
+
+
+/* Define PIMA supported device properties. The last entry MUST be a zero. The DeviceInfoSet command
+ will parse this array and compute the number of functions supported and return it to the
+ host. For each declared device property, a dataset must be created in the application. */
+USHORT pima_device_prop_supported[] = {
+
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_UNDEFINED, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_BATTERY_LEVEL, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_FUNCTIONALMODE, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_IMAGE_SIZE, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_COMPRESSION_SETTING, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_WHITE_BALANCE, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_RGB_GAIN, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_F_NUMBER, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_FOCAL_LENGTH, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_FOCUS_DISTANCE, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_FOCUS_MODE, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_EXPOSURE_METERING_MODE, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_FLASH_MODE, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_EXPOSURE_TIME, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_EXPOSURE_PROGRAM_MODE, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_EXPOSURE_INDEX, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_EXPOSURE_BIAS_COMPENSATION, */
+ UX_DEVICE_CLASS_PIMA_DEV_PROP_DATE_TIME,
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_CAPTURE_DELAY, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_STILL_CAPTURE_MODE, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_CONTRAST, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_SHARPNESS, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_DIGITAL_ZOOM, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_EFFECT_MODE, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_BURST_NUMBER, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_BURST_INTERVAL, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_TIME_LAPSE_NUMBER, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_TIME_LAPSE_INTERVAL, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_FOCUS_METERING_MODE, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_UPLOAD_URL, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_ARTIST, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_COPYRIGHT_INFO, */
+#ifdef UX_PIMA_WITH_MTP_SUPPORT
+ UX_DEVICE_CLASS_PIMA_DEV_PROP_SYNCHRONIZATION_PARTNER,
+ UX_DEVICE_CLASS_PIMA_DEV_PROP_DEVICE_FRIENDLY_NAME,
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_VOLUME, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_SUPPORTED_FORMATS_ORDERED, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_DEVICE_ICON, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_PLAYBACK_RATE, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_PLAYBACK_OBJECT, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_PLAYBACK_CONTAINER, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_SESSION_INITIATOR_VERSION_INFO, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_PERCEIVED_DEVICE_TYPE, */
+#endif
+ 0
+};
+
+/* Define PIMA supported capture formats. The last entry MUST be a zero. The DeviceInfoSet command
+ will parse this array and compute the number of functions supported and return it to the
+ host. */
+USHORT pima_device_supported_capture_formats[] = {
+ 0
+};
+
+/* Define PIMA supported image formats. The last entry MUST be a zero. The DeviceInfoSet command
+ will parse this array and compute the number of formats supported and return it to the
+ host. */
+USHORT pima_device_supported_image_formats[] = {
+ UX_DEVICE_CLASS_PIMA_OFC_UNDEFINED,
+ UX_DEVICE_CLASS_PIMA_OFC_ASSOCIATION,
+ /*UX_DEVICE_CLASS_PIMA_OFC_SCRIPT, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_EXECUTABLE, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_TEXT, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_HTML, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_DPOF, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_AIFF, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_WAV,*/
+ UX_DEVICE_CLASS_PIMA_OFC_MP3,
+ /*UX_DEVICE_CLASS_PIMA_OFC_AVI, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_MPEG, */
+ UX_DEVICE_CLASS_PIMA_OFC_ASF,
+ /*UX_DEVICE_CLASS_PIMA_OFC_DEFINED, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_EXIF_JPEG, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_TIFF_EP, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_FLASHPIX, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_BMP, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_CIFF, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_UNDEFINED, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_GIF, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_JFIF, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_CD, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_PICT, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_PNG, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_UNDEFINED, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_TIFF, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_TIFF_IT, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_JP2, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_JPX, */
+#ifdef UX_PIMA_WITH_MTP_SUPPORT
+ /*UX_DEVICE_CLASS_PIMA_OFC_UNDEFINED_FIRMWARE, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_WINDOWS_IMAGE_FORMAT, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_UNDEFINED_AUDIO, */
+ UX_DEVICE_CLASS_PIMA_OFC_WMA,
+ /*UX_DEVICE_CLASS_PIMA_OFC_OGG, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_AAC, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_AUDIBLE, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_FLAC, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_UNDEFINED_VIDEO, */
+ UX_DEVICE_CLASS_PIMA_OFC_WMV,
+ /*UX_DEVICE_CLASS_PIMA_OFC_MP4_CONTAINER, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_MP2, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_3GP_CONTAINER, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_UNDEFINED_COLLECTION, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_MULTIMEDIA_ALBUM, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_IMAGE_ALBUM, */
+ UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_AUDIO_ALBUM,
+ /*UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_VIDEO_ALBUM, */
+ UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_AUDIO_AND_VIDEO_PLAYLIST,
+ /*UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_CONTACT_GROUP, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_MESSAGE_FOLDER, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_CHAPTERED_PRODUCTION, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_AUDIO_PLAYLIST, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_VIDEO_PLAYLIST, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_MEDIACAST, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_WPL_PLAYLIST, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_M3U_PLAYLIST, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_MPL_PLAYLIST, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_ASX_PLAYLIST, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_PLS_PLAYLIST, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_UNDEFINED_DOCUMENT, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_DOCUMENT, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_XML_DOCUMENT, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_MICROSOFT_WORD_DOCUMENT, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_MHT_COMPILED_HTML_DOCUMENT, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_MICROSOFT_EXCEL_SPREADSHEET, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_MICROSOFT_POWERPOINT_PRESENTATION, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_UNDEFINED_MESSAGE, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_MESSAGE, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_UNDEFINED_CONTACT, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_CONTACT, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_VCARD2, */
+#endif
+ 0
+};
+
+/* Device property dataset. Here we give the example of the Date/Time dataset. */
+UCHAR pima_device_prop_date_time_dataset[] = {
+
+ /* Device prop code : Date/Time. */
+ 0x11, 0x50, /* Prop code */
+ 0xff, 0xff, /* String */
+ 0x01, /* GET/SET */
+ 0x00, /* Default value : empty string. */
+ 0x10, /* Current value : length of the unicode string. */
+ 0x31, 0x00, 0x39, 0x00, 0x38, 0x00, 0x30, 0x00, /* YYYY */
+ 0x30, 0x00, 0x31, 0x00, /* MM */
+ 0x30, 0x00, 0x31, 0x00, /* DD */
+ 0x54, 0x00, /* T */
+ 0x30, 0x00, 0x30, 0x00, /* HH */
+ 0x30, 0x00, 0x30, 0x00, /* MM */
+ 0x30, 0x00, 0x30, 0x00, /* SS */
+ 0x00, 0x00, /* Unicode terminator. */
+ 0x00 /* Form Flag : None. */
+};
+#define DEVICE_PROP_DATE_TIME_DATASET_LENGTH sizeof(pima_device_prop_date_time_dataset) /* 40 */
+
+/* Device property dataset. Here we give the example of the synchronization partner dataset. */
+UCHAR pima_device_prop_synchronization_partner_dataset[] = {
+
+ /* Device prop code : Synchronization Partner. */
+ 0x01, 0xD4, /* Prop code */
+ 0xff, 0xff, /* String */
+ 0x01, /* GET/SET */
+ 0x00, /* Default value : empty string. */
+ 0x00, /* Current value : empty string. */
+ 0x00 /* Form Flag : None. */
+};
+#define DEVICE_PROP_SYNCHRONIZATION_PARTNER_DATASET_LENGTH sizeof(pima_device_prop_synchronization_partner_dataset) /* 8 */
+
+/* Device property dataset. Here we give the example of the device friendly name dataset. */
+UCHAR pima_device_prop_device_friendly_name_dataset[] = {
+
+ /* Device prop code : Device Friendly Name. */
+ 0x02, 0xD4, /* Prop code */
+ 0xff, 0xff, /* String */
+ 0x01, /* GET/SET */
+ 0x0E, /* Default value. Length of Unicode string. */
+ 0x45, 0x00, 0x4C, 0x00, 0x20, 0x00, 0x4D, 0x00, /* Unicode string. */
+ 0x54, 0x00, 0x50, 0x00, 0x20, 0x00, 0x44, 0x00,
+ 0x65, 0x00, 0x76, 0x00, 0x69, 0x00, 0x63, 0x00,
+ 0x65, 0x00,
+ 0x00, 0x00, /* Unicode terminator. */
+ 0x0E, /* Current value. Length of Unicode string. */
+ 0x45, 0x00, 0x4C, 0x00, 0x20, 0x00, 0x4D, 0x00,
+ 0x54, 0x00, 0x50, 0x00, 0x20, 0x00, 0x44, 0x00,
+ 0x65, 0x00, 0x76, 0x00, 0x69, 0x00, 0x63, 0x00, /* Unicode terminator. */
+ 0x65, 0x00,
+ 0x00, 0x00, /* Unicode terminator. */
+ 0x00 /* Form Flag : None. */
+};
+#define DEVICE_PROP_DEVICE_FRIENDLY_NAME_DATASET_LENGTH sizeof(pima_device_prop_device_friendly_name_dataset) /* 64 */
+
+/* Object property supported.
+ WORD 0 : Object Format Code
+ WORD 1 : Number of Prop codes for this Object format
+ WORD n : Prop Codes
+ WORD n+2 : Next Object Format code ....
+
+ This array is in whatever endinaness of the system and will be translated
+ by the PTP class in little endian.
+
+*/
+USHORT pima_device_object_prop_supported[] = {
+
+ /* Object format code : Undefined. */
+ UX_DEVICE_CLASS_PIMA_OFC_UNDEFINED,
+
+ /* NUmber of objects supported for this format. */
+ 9,
+ /* Mandatory objects for all formats. */
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_STORAGEID,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FORMAT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PROTECTION_STATUS,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_SIZE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FILE_NAME,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PARENT_OBJECT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NAME,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NON_CONSUMABLE,
+
+ /* Object format code : Association. */
+ UX_DEVICE_CLASS_PIMA_OFC_ASSOCIATION,
+
+ /* NUmber of objects supported for this format. */
+ 9,
+ /* Mandatory objects for all formats. */
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_STORAGEID,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FORMAT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PROTECTION_STATUS,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_SIZE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FILE_NAME,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PARENT_OBJECT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NAME,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NON_CONSUMABLE,
+
+ /* Object format code : Advanced System Format. */
+ UX_DEVICE_CLASS_PIMA_OFC_ASF,
+
+ /* NUmber of objects supported for this format. */
+ 9,
+ /* Mandatory objects for all formats. */
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_STORAGEID,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FORMAT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PROTECTION_STATUS,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_SIZE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FILE_NAME,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PARENT_OBJECT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NAME,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NON_CONSUMABLE,
+
+ /* Object format code : Audio Clip. */
+ UX_DEVICE_CLASS_PIMA_OFC_MP3,
+
+ /* NUmber of objects supported for this format. */
+ 20,
+ /* Mandatory objects for all formats. */
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_STORAGEID,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FORMAT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PROTECTION_STATUS,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_SIZE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FILE_NAME,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PARENT_OBJECT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NAME,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NON_CONSUMABLE,
+
+ /* Mandatory objects for all audio objects. */
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ARTIST,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_TRACK,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_DATE_AUTHORED,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_GENRE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_USE_COUNT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ALBUM_NAME,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ALBUM_ARTIST,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_SAMPLE_RATE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NUMBER_OF_CHANNELS,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_AUDIO_WAVE_CODEC,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_AUDIO_BITRATE,
+
+ /* Object format code : Windows Media Audio Clip. */
+ UX_DEVICE_CLASS_PIMA_OFC_WMA,
+
+ /* NUmber of objects supported for this format. */
+ 20,
+ /* Mandatory objects for all formats. */
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_STORAGEID,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FORMAT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PROTECTION_STATUS,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_SIZE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FILE_NAME,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PARENT_OBJECT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NAME,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NON_CONSUMABLE,
+
+ /* Mandatory objects for all audio objects. */
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ARTIST,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_TRACK,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_DATE_AUTHORED,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_GENRE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_USE_COUNT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ALBUM_NAME,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ALBUM_ARTIST,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_SAMPLE_RATE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NUMBER_OF_CHANNELS,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_AUDIO_WAVE_CODEC,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_AUDIO_BITRATE,
+
+ /* Object format code : Windows Media Video. */
+ UX_DEVICE_CLASS_PIMA_OFC_WMV,
+
+ /* NUmber of objects supported for this format. */
+ 24,
+ /* Mandatory objects for all formats. */
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_STORAGEID,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FORMAT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PROTECTION_STATUS,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_SIZE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FILE_NAME,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PARENT_OBJECT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NAME,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NON_CONSUMABLE,
+
+ /* Mandatory objects for all video objects. */
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_WIDTH,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_HEIGHT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_DATE_AUTHORED,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_GENRE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_USE_COUNT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_SAMPLE_RATE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NUMBER_OF_CHANNELS,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_SCAN_TYPE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_AUDIO_WAVE_CODEC,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_AUDIO_BITRATE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_VIDEO_FOURCC_CODEC,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_VIDEO_BITRATE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_FRAMES_PER_THOUSAND_SECONDS,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_KEYFRAME_DISTANCE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ENCODING_PROFILE,
+
+ /* Object format code : Abstract Audio Album. */
+ UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_AUDIO_ALBUM,
+ 2,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_GENRE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ALBUM_ARTIST,
+
+ /* Object format code : Abstract Audio and Video Playlist. */
+ UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_AUDIO_AND_VIDEO_PLAYLIST,
+ 2,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_GENRE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ALBUM_ARTIST,
+
+ 0
+};
+
+/* PIMA MTP names ... */
+UCHAR pima_device_info_vendor_name[] = "Microsoft AzureRTOS";
+UCHAR pima_device_info_product_name[] = "AzureRTOS MTP Device";
+UCHAR pima_device_info_serial_no[] = "1.1.1.1";
+UCHAR pima_device_info_version[] = "V1.0";
+
+/* PIMA MTP storage names. */
+UCHAR pima_parameter_volume_description[] = "MTP Client Storage Volume";
+UCHAR pima_parameter_volume_label[] = "MTP Client Storage Label";
+
+/* Array of handles for the demo. */
+ULONG pima_device_object_number_handles;
+ULONG pima_device_object_number_handles_array[UX_TEST_MAX_HANDLES];
+UX_SLAVE_CLASS_PIMA_OBJECT pima_device_object_info_array[UX_TEST_MAX_HANDLES];
+FX_FILE pima_device_object_filex_array[UX_TEST_MAX_HANDLES];
+TEST_PIMA_PROP_DATASET pima_device_object_property_array[UX_TEST_MAX_HANDLES];
+
+/* Local storage for one Object property. This is a temporary storage to create
+ the demanded dataset. The size of the dataset depends on the type and number of object properties. */
+UCHAR pima_device_object_property_dataset_data_buffer [UX_TEST_MAX_DATASET_SIZE];
+
+/* This is a 128 bit unique identifier. For the demo we make it 32 bits only as it is easier to manipulate. */
+ULONG pima_device_object_persistent_unique_identifier = 1;
+
+
+/* Prototype for test control return. */
+
+void test_control_return(UINT status);
+
+static VOID error_callback(UINT system_level, UINT system_context, UINT error_code)
+{
+
+ error_callback_counter ++;
+
+ if (!error_callback_ignore)
+ {
+ {
+ /* Failed test. */
+ printf("Error #%d, system_level: %d, system_context: %d, error_code: 0x%x\n", __LINE__, system_level, system_context, error_code);
+ test_control_return(1);
+ }
+ }
+}
+
+static UINT sleep_break_on_error(VOID)
+{
+
+ if (error_callback_counter >= 3)
+ return error_callback_counter;
+
+ return UX_SUCCESS;
+}
+
+/* Define the ISR dispatch routine. */
+
+static void test_isr(void)
+{
+
+ /* For further expansion of interrupt-level testing. */
+}
+
+
+
+static UINT test_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst)
+{
+ // printf("hChg:%lx, %p, %p\n", event, cls, inst);
+ switch(event)
+ {
+ case UX_DEVICE_INSERTION:
+ if (cls->ux_host_class_entry_function == ux_host_class_pima_entry)
+ {
+ pima_host = (UX_HOST_CLASS_PIMA *)inst;
+ }
+ break;
+
+ case UX_DEVICE_REMOVAL:
+ if (cls->ux_host_class_entry_function == ux_host_class_pima_entry)
+ {
+ if ((VOID*)pima_host == inst)
+ pima_host = UX_NULL;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+static VOID test_pima_instance_activate(VOID *instance)
+{
+ pima_device = (UX_SLAVE_CLASS_PIMA *)instance;
+}
+static VOID test_pima_instance_deactivate(VOID *instance)
+{
+ if ((VOID *)pima_device == instance)
+ pima_device = UX_NULL;
+}
+
+
+/* Define what the initial system looks like. */
+
+#ifdef CTEST
+void test_application_define(void *first_unused_memory)
+#else
+void usbx_ghsa_2ch9_pima_info_bounds_test_application_define(void *first_unused_memory)
+#endif
+{
+
+UINT status;
+CHAR * stack_pointer;
+CHAR * memory_pointer;
+ULONG test_n;
+
+ /* Inform user. */
+ printf("Running GHSA 2ch9 PIMA info bounds Test........................... ");
+
+ /* Reset testing counts. */
+ ux_test_utility_sim_mutex_create_count_reset();
+ ux_test_utility_sim_sem_create_count_reset();
+ ux_test_utility_sim_sem_get_count_reset();
+ /* Reset error generations */
+ ux_test_utility_sim_sem_error_generation_stop();
+ ux_test_utility_sim_mutex_error_generation_stop();
+ ux_test_utility_sim_sem_get_error_generation_stop();
+
+ ux_utility_memory_set(ram_disk_memory, 0, UX_TEST_RAM_DISK_SIZE);
+ fx_system_initialize();
+ status = fx_media_format(&ram_disk, _fx_ram_driver, ram_disk_memory, ram_disk_buffer, 512, "RAM DISK", 2, 512, 0, (UX_TEST_RAM_DISK_SIZE / 512), 512, 4, 1, 1);
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d\n", __LINE__);
+ test_control_return(1);
+ }
+ status = fx_media_open(&ram_disk, "RAM DISK", _fx_ram_driver, ram_disk_memory, ram_disk_buffer, 512);
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d\n", __LINE__);
+ test_control_return(1);
+ }
+
+ /* Initialize the free memory pointer */
+ stack_pointer = (CHAR *) usbx_memory;
+ memory_pointer = stack_pointer + (UX_TEST_STACK_SIZE * 2);
+
+ /* Initialize USBX Memory */
+ status = ux_system_initialize(memory_pointer, UX_TEST_MEMORY_SIZE, UX_NULL,0);
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d\n", __LINE__);
+ test_control_return(1);
+ }
+
+ /* Register the error callback. */
+ _ux_utility_error_callback_register(error_callback);
+
+ /* The code below is required for installing the host portion of USBX */
+ status = ux_host_stack_initialize(test_system_host_change_function);
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d\n", __LINE__);
+ test_control_return(1);
+ }
+
+ /* Register PIMA class. */
+ status = ux_host_stack_class_register(_ux_system_host_class_pima_name, ux_host_class_pima_entry);
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d\n", __LINE__);
+ test_control_return(1);
+ }
+
+ /* The code below is required for installing the device portion of USBX. No call back for
+ device status change in this example. */
+ status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED,
+ device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED,
+ string_framework, STRING_FRAMEWORK_LENGTH,
+ language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH,UX_NULL);
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d\n", __LINE__);
+ test_control_return(1);
+ }
+
+ /* MTP requires MTP extensions. */
+ status = ux_device_stack_microsoft_extension_register(UX_TEST_VENDOR_REQUEST, pima_device_vendor_request);
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d\n", __LINE__);
+ test_control_return(1);
+ }
+
+ /* Set the parameters for PIMA device. */
+ pima_device_parameter.ux_device_class_pima_instance_activate = test_pima_instance_activate;
+ pima_device_parameter.ux_device_class_pima_instance_deactivate = test_pima_instance_deactivate;
+
+ /* Initialize the pima device parameter. */
+ pima_device_parameter.ux_device_class_pima_parameter_manufacturer = pima_device_info_vendor_name;
+ pima_device_parameter.ux_device_class_pima_parameter_model = pima_device_info_product_name;
+ pima_device_parameter.ux_device_class_pima_parameter_device_version = pima_device_info_version;
+ pima_device_parameter.ux_device_class_pima_parameter_serial_number = pima_device_info_serial_no;
+ pima_device_parameter.ux_device_class_pima_parameter_storage_id = UX_TEST_PIMA_STORAGE_ID;
+ pima_device_parameter.ux_device_class_pima_parameter_storage_type = UX_DEVICE_CLASS_PIMA_STC_FIXED_RAM;
+ pima_device_parameter.ux_device_class_pima_parameter_storage_file_system_type = UX_DEVICE_CLASS_PIMA_FSTC_GENERIC_FLAT;
+ pima_device_parameter.ux_device_class_pima_parameter_storage_access_capability = UX_DEVICE_CLASS_PIMA_AC_READ_WRITE;
+ pima_device_parameter.ux_device_class_pima_parameter_storage_max_capacity_low = ram_disk.fx_media_total_clusters * ram_disk.fx_media_sectors_per_cluster * ram_disk.fx_media_bytes_per_sector;
+ pima_device_parameter.ux_device_class_pima_parameter_storage_max_capacity_high = 0;
+ pima_device_parameter.ux_device_class_pima_parameter_storage_free_space_low = ram_disk.fx_media_available_clusters * ram_disk.fx_media_sectors_per_cluster * ram_disk.fx_media_bytes_per_sector;
+ pima_device_parameter.ux_device_class_pima_parameter_storage_free_space_high = 0;
+ pima_device_parameter.ux_device_class_pima_parameter_storage_free_space_image = 0xFFFFFFFF;
+ pima_device_parameter.ux_device_class_pima_parameter_storage_description = pima_parameter_volume_description;
+ pima_device_parameter.ux_device_class_pima_parameter_storage_volume_label = pima_parameter_volume_label;
+ pima_device_parameter.ux_device_class_pima_parameter_device_properties_list = pima_device_prop_supported;
+ pima_device_parameter.ux_device_class_pima_parameter_supported_capture_formats_list= pima_device_supported_capture_formats;
+ pima_device_parameter.ux_device_class_pima_parameter_supported_image_formats_list = pima_device_supported_image_formats;
+ pima_device_parameter.ux_device_class_pima_parameter_object_properties_list = pima_device_object_prop_supported;
+
+ /* Define the callbacks. */
+ pima_device_parameter.ux_device_class_pima_parameter_device_reset = pima_device_device_reset;
+ pima_device_parameter.ux_device_class_pima_parameter_device_prop_desc_get = pima_device_device_prop_desc_get;
+ pima_device_parameter.ux_device_class_pima_parameter_device_prop_value_get = pima_device_device_prop_value_get;
+ pima_device_parameter.ux_device_class_pima_parameter_device_prop_value_set = pima_device_device_prop_value_set;
+ pima_device_parameter.ux_device_class_pima_parameter_storage_format = pima_device_storage_format;
+ pima_device_parameter.ux_device_class_pima_parameter_storage_info_get = pima_device_storage_info_get;
+ pima_device_parameter.ux_device_class_pima_parameter_object_number_get = pima_device_object_number_get;
+ pima_device_parameter.ux_device_class_pima_parameter_object_handles_get = pima_device_object_handles_get;
+ pima_device_parameter.ux_device_class_pima_parameter_object_info_get = pima_device_object_info_get;
+ pima_device_parameter.ux_device_class_pima_parameter_object_data_get = pima_device_object_data_get;
+ pima_device_parameter.ux_device_class_pima_parameter_object_info_send = pima_device_object_info_send;
+ pima_device_parameter.ux_device_class_pima_parameter_object_data_send = pima_device_object_data_send;
+ pima_device_parameter.ux_device_class_pima_parameter_object_delete = pima_device_object_delete;
+ pima_device_parameter.ux_device_class_pima_parameter_object_prop_desc_get = pima_device_object_prop_desc_get;
+ pima_device_parameter.ux_device_class_pima_parameter_object_prop_value_get = pima_device_object_prop_value_get;
+ pima_device_parameter.ux_device_class_pima_parameter_object_prop_value_set = pima_device_object_prop_value_set;
+ pima_device_parameter.ux_device_class_pima_parameter_object_references_get = pima_device_object_references_get;
+ pima_device_parameter.ux_device_class_pima_parameter_object_references_set = pima_device_object_references_set;
+
+ /* Store the instance owner. */
+ pima_device_parameter.ux_device_class_pima_parameter_application = (VOID *) 0;
+
+ /* Initialize the device PIMA class. */
+ status = ux_device_stack_class_register(_ux_system_slave_class_pima_name, ux_device_class_pima_entry,
+ 1, 0, &pima_device_parameter);
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d\n", __LINE__);
+ test_control_return(1);
+ }
+
+ /* Initialize the simulated device controller. */
+ status = _ux_dcd_sim_slave_initialize();
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d\n", __LINE__);
+ test_control_return(1);
+ }
+
+ /* Register all the USB host controllers available in this system */
+ status = ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize,0,0);
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d\n", __LINE__);
+ test_control_return(1);
+ }
+
+ /* Create the main host simulation thread. */
+ status = tx_thread_create(&test_thread_host_simulation, "tx demo host simulation", test_thread_host_simulation_entry, 0,
+ stack_pointer, UX_TEST_STACK_SIZE,
+ 20, 20, 1, TX_AUTO_START);
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d\n", __LINE__);
+ test_control_return(1);
+ }
+
+ /* Create the main slave simulation thread. */
+ status = tx_thread_create(&test_thread_device_simulation, "tx demo device simulation", test_thread_device_simulation_entry, 0,
+ stack_pointer + UX_TEST_STACK_SIZE, UX_TEST_STACK_SIZE,
+ 20, 20, 1, TX_AUTO_START);
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d\n", __LINE__);
+ test_control_return(1);
+ }
+}
+
+static TX_THREAD replace_pima_cmd_thread;
+static UCHAR replace_pima_cmd_thread_stack[UX_TEST_STACK_SIZE];
+static TX_SEMAPHORE replace_pima_cmd_semaphore;
+static ULONG replace_pima_obj_n = 0;
+static ULONG replace_pima_container_l = UX_DEVICE_CLASS_PIMA_DATA_HEADER_SIZE;
+
+/* A GetDeviceInfo payload built byte by byte, so field lengths can be declared
+ independently of what the response actually carries. The host always asks for
+ UX_HOST_CLASS_PIMA_DEVICE_MAX_LENGTH bytes and always gets that many, which keeps
+ the parse deterministic: every byte the parser reads inside the allocation is one
+ this test wrote. */
+static UCHAR crafted_payload[UX_HOST_CLASS_PIMA_DEVICE_MAX_LENGTH];
+
+/* The opcode and payload length the hooked response carries. The host asks for the
+ dataset's own maximum and gets exactly that many bytes, so the parse stays
+ deterministic: every byte inside the allocation is one this test wrote. */
+static USHORT crafted_opcode = UX_DEVICE_CLASS_PIMA_OC_GET_DEVICE_INFO;
+static ULONG crafted_length = UX_HOST_CLASS_PIMA_DEVICE_MAX_LENGTH;
+
+
+/* Zero the payload and select which dataset it now describes. */
+static void test_crafted_reset(USHORT opcode, ULONG length)
+{
+ _ux_utility_memory_set(crafted_payload, 0, sizeof(crafted_payload));
+ crafted_opcode = opcode;
+ crafted_length = length;
+}
+
+/* Declare a string of the given character count at the offset. The one byte prefix
+ is the count; the characters themselves stay zero. Returns where the next field
+ would start, which is allowed to run past the payload: that running total is the
+ defect under test, and writes are clipped so the builder never overruns itself. */
+static ULONG test_put_string(ULONG offset, ULONG characters)
+{
+ if (offset < sizeof(crafted_payload))
+ crafted_payload[offset] = (UCHAR) characters;
+
+ return(offset + 1 + (characters * 2));
+}
+
+/* Declare an array of the given element count at the offset. The count is a ULONG
+ and the elements are USHORTs, matching what the parser steps over. */
+static ULONG test_put_array(ULONG offset, ULONG elements)
+{
+ if ((offset + sizeof(ULONG)) <= sizeof(crafted_payload))
+ _ux_utility_long_put(crafted_payload + offset, elements);
+
+ return(offset + (ULONG)sizeof(ULONG) + (elements * 2));
+}
+
+/* Lay out a DeviceInfo dataset. The eight leading bytes are the standard version,
+ vendor extension id and vendor extension version, and the two after the vendor
+ extension description are the functional mode. */
+static void test_build_device_info(ULONG vendor, ULONG operations, ULONG events,
+ ULONG properties, ULONG captures, ULONG images,
+ ULONG manufacturer, ULONG model, ULONG version,
+ ULONG serial)
+{
+ULONG offset;
+
+ test_crafted_reset(UX_DEVICE_CLASS_PIMA_OC_GET_DEVICE_INFO,
+ UX_HOST_CLASS_PIMA_DEVICE_MAX_LENGTH);
+
+ offset = UX_HOST_CLASS_PIMA_DEVICE_VENDOR_EXTENSION_DESC;
+ offset = test_put_string(offset, vendor);
+ offset += sizeof(USHORT);
+ offset = test_put_array(offset, operations);
+ offset = test_put_array(offset, events);
+ offset = test_put_array(offset, properties);
+ offset = test_put_array(offset, captures);
+ offset = test_put_array(offset, images);
+ offset = test_put_string(offset, manufacturer);
+ offset = test_put_string(offset, model);
+ offset = test_put_string(offset, version);
+ (VOID) test_put_string(offset, serial);
+}
+
+/* Lay out a StorageInfo dataset: a fixed head, then the storage description and the
+ volume label, one after the other. */
+static void test_build_storage_info(ULONG description, ULONG label)
+{
+ULONG offset;
+
+ test_crafted_reset(UX_DEVICE_CLASS_PIMA_OC_GET_STORAGE_INFO,
+ UX_HOST_CLASS_PIMA_STORAGE_MAX_LENGTH);
+
+ offset = UX_HOST_CLASS_PIMA_STORAGE_VARIABLE_OFFSET;
+ offset = test_put_string(offset, description);
+ (VOID) test_put_string(offset, label);
+}
+
+/* Lay out an ObjectInfo dataset: a fixed head, then the filename, the capture and
+ modification dates, and the keywords. */
+static void test_build_object_info(ULONG filename, ULONG capture, ULONG modification,
+ ULONG keywords)
+{
+ULONG offset;
+
+ test_crafted_reset(UX_DEVICE_CLASS_PIMA_OC_GET_OBJECT_INFO,
+ UX_HOST_CLASS_PIMA_OBJECT_MAX_LENGTH);
+
+ offset = UX_HOST_CLASS_PIMA_OBJECT_VARIABLE_OFFSET;
+ offset = test_put_string(offset, filename);
+ offset = test_put_string(offset, capture);
+ offset = test_put_string(offset, modification);
+ (VOID) test_put_string(offset, keywords);
+}
+
+/* Send the crafted payload as a data container for the selected operation. */
+static void test_pima_crafted_send(UX_SLAVE_CLASS_PIMA *pima)
+{
+UX_SLAVE_ENDPOINT *endpoint = pima -> ux_device_class_pima_bulk_in_endpoint;
+UX_SLAVE_TRANSFER *transfer = &endpoint -> ux_slave_endpoint_transfer_request;
+UCHAR *buffer = transfer -> ux_slave_transfer_request_data_pointer;
+ULONG container_length;
+
+ container_length = UX_DEVICE_CLASS_PIMA_DATA_HEADER_SIZE + crafted_length;
+
+ _ux_utility_short_put(buffer + UX_DEVICE_CLASS_PIMA_DATA_HEADER_TYPE,
+ UX_DEVICE_CLASS_PIMA_CT_DATA_BLOCK);
+ _ux_utility_short_put(buffer + UX_DEVICE_CLASS_PIMA_DATA_HEADER_CODE, crafted_opcode);
+ _ux_utility_long_put(buffer + UX_DEVICE_CLASS_PIMA_DATA_HEADER_TRANSACTION_ID,
+ pima -> ux_device_class_pima_transaction_id);
+
+ _ux_utility_memory_copy(buffer + UX_DEVICE_CLASS_PIMA_DATA_HEADER_SIZE,
+ crafted_payload, crafted_length);
+
+ _ux_utility_long_put(buffer + UX_DEVICE_CLASS_PIMA_DATA_HEADER_LENGTH,
+ container_length);
+
+ _ux_device_stack_transfer_request(transfer, container_length, 0);
+ _ux_device_class_pima_response_send(pima, UX_DEVICE_CLASS_PIMA_RC_OK, 0, 0, 0, 0);
+}
+
+void replace_pima_cmd_thread_entry(ULONG arg)
+{
+ while(1)
+ {
+ tx_semaphore_get(&replace_pima_cmd_semaphore, TX_WAIT_FOREVER);
+ test_pima_crafted_send(pima_device);
+ }
+}
+
+static VOID ux_test_pima_command(UX_TEST_ACTION *action, VOID *params)
+{
+ tx_semaphore_put(&replace_pima_cmd_semaphore);
+ tx_semaphore_put(&pima_host -> ux_host_class_pima_bulk_out_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_semaphore);
+}
+
+static UX_TEST_HCD_SIM_ACTION replace_bulk_out_transfer[] = {
+/* function, request to match,
+ port action, port status,
+ request action, request EP, request data, request actual length, request status,
+ status, additional callback,
+ no_return */
+{ UX_HCD_TRANSFER_REQUEST, UX_NULL,
+ UX_FALSE, 0,
+ UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, 0,
+ UX_SUCCESS, ux_test_pima_command,
+ UX_FALSE},
+{ 0 }
+};
+
+/* Free bytes across both pools. The receive buffer is cache safe memory, which some
+ configurations back with the regular pool, so both are counted and a shared pool is
+ simply counted twice on each side of the comparison. */
+static ULONG test_free_memory(void)
+{
+ return(_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available +
+ _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available);
+}
+
+/* Ask for each dataset with the hook re-armed, since a matched action is spent. */
+static UINT test_device_info_get(void)
+{
+ ux_test_hcd_sim_host_set_actions(replace_bulk_out_transfer);
+
+ return(ux_host_class_pima_device_info_get(pima_host, &pima_host_device));
+}
+
+static UINT test_storage_info_get(void)
+{
+ ux_test_hcd_sim_host_set_actions(replace_bulk_out_transfer);
+
+ return(ux_host_class_pima_storage_info_get(pima_host, &pima_host_session,
+ UX_TEST_PIMA_STORAGE_ID, &pima_host_storage));
+}
+
+static UINT test_object_info_get(void)
+{
+ ux_test_hcd_sim_host_set_actions(replace_bulk_out_transfer);
+
+ return(ux_host_class_pima_object_info_get(pima_host, &pima_host_session,
+ 1, &pima_host_object));
+}
+
+static void test_ghsa_2ch9_cases(void)
+{
+UINT status;
+ULONG free_before;
+ULONG free_after;
+
+ /* The real device answers normally, which is the parser's ordinary path. */
+ status = ux_host_class_pima_device_info_get(pima_host, &pima_host_device);
+ UX_TEST_CHECK_SUCCESS(status);
+
+ tx_semaphore_create(&replace_pima_cmd_semaphore, "cmd_sem", 0);
+ tx_thread_create(&replace_pima_cmd_thread, "cmd_thr, ", replace_pima_cmd_thread_entry, 0,
+ replace_pima_cmd_thread_stack, UX_TEST_STACK_SIZE,
+ 20, 20, 1, TX_AUTO_START);
+
+ /* A crafted but modest dataset parses, so the bounds do not reject a device that
+ simply fills every field. */
+ test_build_device_info(16, 8, 8, 8, 8, 8, 16, 16, 16, 16);
+ status = test_device_info_get();
+ UX_TEST_CHECK_SUCCESS(status);
+
+ /* The largest dataset that still fits. Each field sits at its cap and the total
+ lands inside the buffer, so this must be accepted: it is the boundary the
+ bounds have to admit. */
+ test_build_device_info(128, 126, 126, 8, 8, 8, 8, 8, 8, 8);
+ status = test_device_info_get();
+ UX_TEST_CHECK_SUCCESS(status);
+
+ /* Now one element more in the third array. Every field is still inside its own
+ cap, but the running total leaves the 1024 byte allocation, and before the fix
+ the parser followed it out. */
+ test_build_device_info(128, 126, 126, 126, 8, 8, 8, 8, 8, 8);
+ status = test_device_info_get();
+ UX_TEST_CHECK_NOT_SUCCESS(status);
+
+ /* The same overrun reached through the strings at the tail rather than the
+ arrays, so the string bound is exercised as well as the array bound. */
+ test_build_device_info(128, 126, 126, 8, 8, 8, 128, 128, 32, 128);
+ status = test_device_info_get();
+ UX_TEST_CHECK_NOT_SUCCESS(status);
+
+ /* A refused dataset must not keep the receive buffer. An attached device would
+ otherwise drain the pool by being enumerated repeatedly. */
+ free_before = test_free_memory();
+ test_build_device_info(128, 126, 126, 126, 8, 8, 8, 8, 8, 8);
+ status = test_device_info_get();
+ UX_TEST_CHECK_NOT_SUCCESS(status);
+ free_after = test_free_memory();
+ if (free_before != free_after)
+ {
+ printf("ERROR #%d: leaked %lu bytes\n", __LINE__, free_before - free_after);
+ test_control_return(1);
+ }
+
+ /* The storage info parser walks a description then a volume label. A description
+ at its cap leaves the label less room than the label's own cap allows, which is
+ where the two disagree. */
+ ux_test_hcd_sim_host_set_actions(UX_NULL);
+ status = ux_host_class_pima_session_open(pima_host, &pima_host_session);
+ UX_TEST_CHECK_SUCCESS(status);
+
+ test_build_storage_info(16, 16);
+ status = test_storage_info_get();
+ UX_TEST_CHECK_SUCCESS(status);
+
+ test_build_storage_info(127, 127);
+ status = test_storage_info_get();
+ UX_TEST_CHECK_NOT_SUCCESS(status);
+
+ /* The object info parser walks a filename, two dates and the keywords. The
+ keywords field is the one the accumulated offsets can push past the end. */
+ test_build_object_info(16, 8, 8, 16);
+ status = test_object_info_get();
+ UX_TEST_CHECK_SUCCESS(status);
+
+ test_build_object_info(127, 31, 31, 127);
+ status = test_object_info_get();
+ UX_TEST_CHECK_NOT_SUCCESS(status);
+
+ /* Back to the real device, to show the refusals left the host usable. */
+ ux_test_hcd_sim_host_set_actions(UX_NULL);
+ status = ux_host_class_pima_session_close(pima_host, &pima_host_session);
+ UX_TEST_CHECK_SUCCESS(status);
+
+ status = ux_host_class_pima_device_info_get(pima_host, &pima_host_device);
+ UX_TEST_CHECK_SUCCESS(status);
+}
+
+void test_thread_host_simulation_entry(ULONG arg)
+{
+
+UINT status;
+INT i;
+
+ for (i = 0; i < 100; i ++)
+ {
+ if (pima_host && pima_device)
+ break;
+ ux_utility_delay_ms(1);
+ }
+ if (pima_host == UX_NULL || pima_device == UX_NULL)
+ {
+ printf("ERROR #%d\n", __LINE__);
+ test_control_return(1);
+ }
+
+ test_ghsa_2ch9_cases();
+
+ stepinfo(">>>>>>>>>>>> All Done\n");
+
+ /* Finally disconnect the device. */
+ ux_device_stack_disconnect();
+
+ /* And deinitialize the class. */
+ status = ux_device_stack_class_unregister(_ux_system_slave_class_pima_name, ux_device_class_pima_entry);
+
+ /* Deinitialize the device side of usbx. */
+ _ux_device_stack_uninitialize();
+
+ /* And finally the usbx system resources. */
+ _ux_system_uninitialize();
+
+ /* Successful test. */
+ printf("SUCCESS!\n");
+ test_control_return(0);
+
+}
+
+
+void test_thread_device_simulation_entry(ULONG arg)
+{
+
+UINT status;
+
+ while(1)
+ {
+
+ /* Sleep so ThreadX on Win32 will delete this thread. */
+ tx_thread_sleep(10);
+ }
+}
+
+
+UINT pima_device_vendor_request(ULONG request, ULONG request_value, ULONG request_index, ULONG request_length,
+ UCHAR *transfer_request_buffer,
+ ULONG *transfer_request_length)
+{
+UINT status;
+ULONG length;
+
+ /* Do some sanity check. The request must be our vendor request. */
+ if (request != UX_TEST_VENDOR_REQUEST)
+
+ /* Do not proceed. */
+ return(UX_ERROR);
+
+ /* Check the wIndex value. Values can be :
+ 0x0001 : Genre
+ 0x0004 : Extended compatible ID
+ 0x0005 : Extended properties */
+ switch (request_index)
+ {
+
+ case 0x0001 :
+
+ /* Not sure what this is for. Windows does not seem to request this. Drop it. */
+ status = UX_ERROR;
+ break;
+
+ case 0x0004 :
+ case 0x0005 :
+
+ /* Length to return. */
+ length = UX_MIN(0x28, request_length);
+
+ /* Length check. */
+ UX_ASSERT(*transfer_request_length >= length);
+
+ /* At least length should be returned. */
+ if (length < 4)
+ {
+ status = UX_ERROR;
+ break;
+ }
+ status = UX_SUCCESS;
+
+ /* Return the length. */
+ *transfer_request_length = length;
+
+ /* Reset returned bytes. */
+ ux_utility_memory_set(transfer_request_buffer, 0, length);
+
+ /* Build the descriptor to be returned. This is not a composite descriptor. Single MTP.
+ First dword is length of the descriptor. */
+ ux_utility_long_put(transfer_request_buffer, 0x0028);
+ length -= 4;
+
+ /* Then the version. fixed to 0x0100. */
+ if (length < 2)
+ break;
+ ux_utility_short_put(transfer_request_buffer + 4, 0x0100);
+ length -= 2;
+
+ /* Then the descriptor ID. Fixed to 0x0004. */
+ if (length < 2)
+ break;
+ ux_utility_short_put(transfer_request_buffer + 6, 0x0004);
+ length -= 2;
+
+ /* Then the bcount field. Fixed to 0x0001. */
+ if (length < 1)
+ break;
+ *(transfer_request_buffer + 8) = 0x01;
+ length -= 1;
+
+ /* Reset the next 7 bytes. */
+ if (length < 7)
+ break;
+ ux_utility_memory_set(transfer_request_buffer + 9, 0x00, 7);
+ length -= 7;
+
+ /* Last byte of header is the interface number, here 0. */
+ if (length < 1)
+ break;
+ *(transfer_request_buffer + 16) = 0x00;
+ length -= 1;
+
+ /* First byte of descriptor is set to 1. */
+ if (length < 1)
+ break;
+ *(transfer_request_buffer + 17) = 0x01;
+ length -= 1;
+
+ /* Reset the next 8 + 8 + 6 bytes. */
+ if (length < (8+8+6))
+ break;
+ ux_utility_memory_set(transfer_request_buffer + 18, 0x00, (8 + 8 + 6));
+ length -= 8+8+6;
+
+ /* Set the compatible ID to MTP. */
+ if (length < 3)
+ break;
+ ux_utility_memory_copy(transfer_request_buffer + 18, "MTP", 3);
+ length -= 3;
+
+ /* We are done here. */
+ status = UX_SUCCESS;
+ break;
+
+ default :
+ status = UX_ERROR;
+ break;
+
+ }
+ /* Return status to device stack. */
+ return(status);
+}
+
+UINT pima_device_device_reset()
+{
+
+ /* Do nothing here. Return Success. */
+ return(UX_SUCCESS);
+
+}
+
+UINT pima_device_device_prop_desc_get(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG device_property,
+ UCHAR **device_prop_dataset,
+ ULONG *device_prop_dataset_length)
+
+{
+UINT status;
+
+ /* We assume the worst. */
+ status = UX_DEVICE_CLASS_PIMA_RC_DEVICE_PROP_NOT_SUPPORTED;
+
+ /* Check which device property the host is inquiring. It needs
+ to be one that we have declared. */
+ switch (device_property)
+ {
+
+ case UX_DEVICE_CLASS_PIMA_DEV_PROP_DATE_TIME :
+
+ /* Buffer length validation. */
+ UX_ASSERT(*device_prop_dataset_length >= DEVICE_PROP_DATE_TIME_DATASET_LENGTH);
+
+ /* The host is inquiring about the date/time dataset. */
+ *device_prop_dataset = pima_device_prop_date_time_dataset;
+ *device_prop_dataset_length = DEVICE_PROP_DATE_TIME_DATASET_LENGTH;
+
+ /* We have a successful operation. */
+ status = UX_SUCCESS;
+
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_DEV_PROP_SYNCHRONIZATION_PARTNER :
+
+ /* Buffer length validation. */
+ UX_ASSERT(*device_prop_dataset_length >= DEVICE_PROP_SYNCHRONIZATION_PARTNER_DATASET_LENGTH);
+
+ /* The host is inquiring about the synchronization partner dataset. */
+ *device_prop_dataset = pima_device_prop_synchronization_partner_dataset;
+ *device_prop_dataset_length = DEVICE_PROP_SYNCHRONIZATION_PARTNER_DATASET_LENGTH;
+
+ /* We have a successful operation. */
+ status = UX_SUCCESS;
+
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_DEV_PROP_DEVICE_FRIENDLY_NAME :
+
+ /* Buffer length validation. */
+ UX_ASSERT(*device_prop_dataset_length >= DEVICE_PROP_DEVICE_FRIENDLY_NAME_DATASET_LENGTH);
+
+ /* The host is inquiring about the device friendly name dataset. */
+ *device_prop_dataset = pima_device_prop_device_friendly_name_dataset;
+ *device_prop_dataset_length = DEVICE_PROP_DEVICE_FRIENDLY_NAME_DATASET_LENGTH;
+
+ /* We have a successful operation. */
+ status = UX_SUCCESS;
+
+ break;
+
+ default :
+
+ /* We get here when the Initiator inquires about a property we don't know about.
+ That should never happen as the properties are declared to the initiator. */
+ status = UX_DEVICE_CLASS_PIMA_RC_DEVICE_PROP_NOT_SUPPORTED;
+
+ break;
+ }
+
+ /* Return what we found. */
+ return(status);
+
+}
+
+UINT pima_device_device_prop_value_get(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG device_property,
+ UCHAR **device_prop_value,
+ ULONG *device_prop_value_length)
+{
+
+UINT status;
+
+ /* We assume the worst. */
+ status = UX_DEVICE_CLASS_PIMA_RC_DEVICE_PROP_NOT_SUPPORTED;
+
+ /* Check which device property the host is inquiring. It needs
+ to be one that we have declared. */
+ switch (device_property)
+ {
+
+ case UX_DEVICE_CLASS_PIMA_DEV_PROP_DATE_TIME :
+
+ /* Buffer length validation. */
+ UX_ASSERT(*device_prop_value_length >= 33);
+
+ /* The host is inquiring about the date/time value. */
+ *device_prop_value = pima_device_prop_date_time_dataset + 6;
+ *device_prop_value_length = 33;
+
+ /* We have a successful operation. */
+ status = UX_SUCCESS;
+
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_DEV_PROP_SYNCHRONIZATION_PARTNER :
+
+ /* Buffer length validation. */
+ UX_ASSERT(*device_prop_value_length >= 1);
+
+ /* The host is inquiring about the synchronization name dataset. */
+ *device_prop_value = pima_device_prop_synchronization_partner_dataset + 6;
+ *device_prop_value_length = 1;
+
+ /* We have a successful operation. */
+ status = UX_SUCCESS;
+
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_DEV_PROP_DEVICE_FRIENDLY_NAME :
+
+ /* Buffer length validation. */
+ UX_ASSERT(*device_prop_value_length >= 29);
+
+ /* The host is inquiring about the device friendly name dataset. */
+ *device_prop_value = pima_device_prop_device_friendly_name_dataset + 6;
+ *device_prop_value_length = 29;
+
+ /* We have a successful operation. */
+ status = UX_SUCCESS;
+
+ break;
+
+ default :
+
+ /* We get here when the Initiator inquires about a property we don't know about.
+ That should never happen as the properties are declared to the initiator. */
+ status = UX_DEVICE_CLASS_PIMA_RC_DEVICE_PROP_NOT_SUPPORTED;
+
+ break;
+ }
+
+ /* Return what we found. */
+ return(status);
+
+}
+
+UINT pima_device_device_prop_value_set(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG device_property,
+ UCHAR *device_prop_value,
+ ULONG device_prop_value_length)
+{
+
+UINT status;
+
+ /* We assume the worst. */
+ status = UX_DEVICE_CLASS_PIMA_RC_DEVICE_PROP_NOT_SUPPORTED;
+
+ /* Check which device property the host wants to set. It needs
+ to be one that we have declared. */
+ switch (device_property)
+ {
+
+ case UX_DEVICE_CLASS_PIMA_DEV_PROP_DATE_TIME :
+
+ /* The host wants to set time and date value.
+ We only take the first 16 bytes of the Unicode string. */
+ ux_utility_memory_copy (pima_device_prop_date_time_dataset + 6, device_prop_value, 0x10);
+
+ /* We have a successful operation. */
+ status = UX_SUCCESS;
+
+ break;
+
+ }
+
+ /* Return what we found. */
+ return(status);
+
+
+}
+
+
+UINT pima_device_storage_format(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG storage_id)
+{
+
+UINT status;
+
+ /* Check the storage ID. */
+ if (storage_id == UX_TEST_PIMA_STORAGE_ID)
+ {
+
+ /* Format the ram drive. */
+ status = fx_media_format(&ram_disk, _fx_ram_driver, ram_disk_memory, ram_disk_buffer, 512, "RAM DISK", 2, 512, 0, UX_TEST_RAM_DISK_SIZE / 512, 512, 4, 1, 1);
+
+ /* Reset the handle counter. */
+ pima_device_object_number_handles = 0;
+
+ /* Is there an error ? */
+ if (status == UX_SUCCESS)
+
+ /* Success. */
+ return(status);
+
+ else
+
+ /* Error. */
+ return(UX_DEVICE_CLASS_PIMA_RC_ACCESS_DENIED);
+ }
+ else
+
+ /* Error, wrong storage ID. */
+ return(UX_DEVICE_CLASS_PIMA_RC_INVALID_STORAGE_ID);
+
+}
+
+
+UINT pima_device_storage_info_get(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG storage_id)
+{
+
+ /* Check the storage ID. */
+ if (storage_id == UX_TEST_PIMA_STORAGE_ID)
+ {
+
+ /* We come here when the Initiator needs to update the storage info dataset.
+ The PIMA structure has the storage info main dataset. This version only
+ support one storage container. */
+ pima -> ux_device_class_pima_storage_max_capacity_low = ram_disk.fx_media_total_clusters * ram_disk.fx_media_sectors_per_cluster * ram_disk.fx_media_bytes_per_sector;
+ pima -> ux_device_class_pima_storage_max_capacity_high = 0;
+ pima -> ux_device_class_pima_storage_free_space_low = ram_disk.fx_media_available_clusters * ram_disk.fx_media_sectors_per_cluster * ram_disk.fx_media_bytes_per_sector;
+ pima -> ux_device_class_pima_storage_free_space_high = 0;
+
+
+ /* Success. */
+ return( UX_SUCCESS);
+
+ }
+ else
+
+ /* Error, wrong storage ID. */
+ return(UX_DEVICE_CLASS_PIMA_RC_INVALID_STORAGE_ID);
+
+}
+
+UINT pima_device_object_number_get(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_format_code,
+ ULONG object_association,
+ ULONG *object_number)
+{
+
+ /* Return the object number. */
+ *object_number = pima_device_object_number_handles;
+
+ /* Return success. */
+ return(UX_SUCCESS);
+}
+
+UINT pima_device_object_handles_get (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handles_format_code,
+ ULONG object_handles_association,
+ ULONG *object_handles_array,
+ ULONG object_handles_max_number)
+{
+ULONG handle_index;
+ULONG number_handles;
+ULONG found_handles;
+ULONG *object_handles_array_pointer;
+
+ /* Number of max handles we can store in our demo. */
+ number_handles = UX_TEST_MAX_HANDLES;
+ if (number_handles > object_handles_max_number)
+ number_handles = object_handles_max_number;
+
+ /* We start with no handles found. */
+ found_handles = 0;
+
+ /* We store the handles in the array pointer, skipping the array count. */
+ object_handles_array_pointer = object_handles_array + 1;
+
+ /* Store all the handles we have in the media for the specific format code if utilized. */
+ for (handle_index = 0; handle_index < number_handles; handle_index++)
+ {
+
+ /* Check if this handle is valid. If 0, it may have been destroyed or unused yet. */
+ if (pima_device_object_number_handles_array[handle_index] != 0)
+ {
+
+ /* This handle is populated. Check the format code supplied by the app.
+ if 0 or -1, we discard the format code check. If not 0 or -1 check
+ it the stored object matches the format code. */
+ if ((object_handles_format_code == 0) || (object_handles_format_code == 0xFFFFFFFF) ||
+ pima_device_object_info_array[handle_index].ux_device_class_pima_object_format == object_handles_format_code)
+ {
+ /* We have a candidate. Store the handle. */
+ ux_utility_long_put((UCHAR *) object_handles_array_pointer, pima_device_object_number_handles_array[handle_index]);
+
+ /* Next array container. */
+ object_handles_array_pointer++;
+
+ /* We have found one handle more. */
+ found_handles++;
+
+ /* Check if we are reaching the max array of handles. */
+ if (found_handles == object_handles_max_number)
+ {
+
+ /* Array is saturated. Store what we have found. */
+ ux_utility_long_put((UCHAR *) object_handles_array, found_handles);
+
+ /* And return to the Pima class. */
+ return(UX_SUCCESS);
+
+ }
+ }
+ }
+
+ }
+
+ /* Array is populated. Store what we have found. */
+ ux_utility_long_put((UCHAR *) object_handles_array, found_handles);
+
+ /* And return to the Pima class. */
+ return(UX_SUCCESS);
+
+}
+
+UINT pima_device_object_info_get (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle,
+ UX_SLAVE_CLASS_PIMA_OBJECT **object)
+{
+UINT status;
+ULONG handle_index;
+
+ /* Check the object handle. It must be in the local array. */
+ status = pima_device_object_handle_check(object_handle, object, &handle_index);
+
+ /* Does the object handle exist ? */
+ if (status == UX_SUCCESS)
+ {
+
+ /* Yes, the handle is valid. The object pointer has been updated. */
+ return(UX_SUCCESS);
+ }
+ else
+
+ /* Done here. Return error. */
+ return(UX_DEVICE_CLASS_PIMA_RC_INVALID_OBJECT_HANDLE);
+
+}
+
+UINT pima_device_object_data_get (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle,
+ UCHAR *object_buffer,
+ ULONG object_offset,
+ ULONG object_length_requested,
+ ULONG *object_actual_length)
+
+{
+
+UINT status;
+UINT status_close;
+ULONG handle_index;
+UX_SLAVE_CLASS_PIMA_OBJECT *object;
+CHAR object_filename[64];
+
+
+ /* Check the object handle. It must be in the local array. */
+ status = pima_device_object_handle_check(object_handle, &object, &handle_index);
+
+ /* Does the object handle exist ? */
+ if (status != UX_SUCCESS)
+ return(status);
+
+ /* Check if entire file is read,
+ this could happen if last actual length equals to length requested. */
+ if (object_offset >= pima_device_object_filex_array[handle_index].fx_file_current_file_size)
+ {
+
+ /* Nothing to read. */
+ *object_actual_length = 0;
+ return(UX_SUCCESS);
+ }
+
+ /* We are either at the beginning of the transfer or continuing the transfer.
+ Check of the filex array handle exist already. */
+ if (pima_device_object_filex_array[handle_index].fx_file_id == 0)
+ {
+
+ /* The object file name is in Unicode, decrypt it first because FileX is not using
+ unicode format. */
+ _ux_utility_unicode_to_string(object -> ux_device_class_pima_object_filename, (UCHAR *) object_filename);
+
+ /* File not yet opened for this object. Open the file. */
+ status = fx_file_open(&ram_disk, &pima_device_object_filex_array[handle_index], (CHAR *) object_filename, FX_OPEN_FOR_READ);
+
+ /* Any problems with the opening ? */
+ if (status != UX_SUCCESS)
+ return(UX_DEVICE_CLASS_PIMA_RC_OBJECT_NOT_OPENED);
+
+ }
+
+ /* Seek to the offset of the object file. */
+ status = fx_file_seek(&pima_device_object_filex_array[handle_index], object_offset);
+ if (status != UX_SUCCESS)
+ return(UX_DEVICE_CLASS_PIMA_RC_INVALID_OBJECT_REFERENCE);
+
+ /* Read from the file into the media buffer. */
+ status = fx_file_read(&pima_device_object_filex_array[handle_index], object_buffer, object_length_requested, object_actual_length);
+
+ /* Check the status. */
+ if (status == UX_SUCCESS)
+
+ /* Done. Operation successful. */
+ status = UX_SUCCESS;
+
+ else
+ {
+
+ /* See what the error might be. */
+ switch (status)
+ {
+
+ case FX_MEDIA_NOT_OPEN :
+
+ /* Problem with media. */
+ status = UX_DEVICE_CLASS_PIMA_RC_STORE_NOT_AVAILABLE;
+ break;
+
+ case FX_NO_MORE_SPACE :
+
+ /* Media is full. */
+ status = UX_DEVICE_CLASS_PIMA_RC_STORE_FULL;
+ break;
+
+ default :
+ status = UX_DEVICE_CLASS_PIMA_RC_ACCESS_DENIED;
+ break;
+
+ }
+ }
+
+ /* Check if we have read the entire file. We compare the current position in the file with the file size. */
+ if (pima_device_object_filex_array[handle_index].fx_file_current_file_size == pima_device_object_filex_array[handle_index].fx_file_current_file_offset)
+ {
+
+ /* This is the end of the transfer for the object. Close it. */
+ status_close = fx_file_close(&pima_device_object_filex_array[handle_index]);
+
+ /* FX file id is not cleared by fx_file_close. */
+ pima_device_object_filex_array[handle_index].fx_file_id = 0;
+
+ /* Check the status. */
+ if (status_close == UX_SUCCESS && status == UX_SUCCESS)
+
+ /* Done. Operation successful. */
+ return (UX_SUCCESS);
+
+ else
+ {
+
+ /* See what the error might be. */
+ switch (status_close)
+ {
+
+ case FX_MEDIA_NOT_OPEN :
+
+ /* Problem with media. */
+ status_close = UX_DEVICE_CLASS_PIMA_RC_STORE_NOT_AVAILABLE;
+ break;
+
+ default :
+ status_close = UX_DEVICE_CLASS_PIMA_RC_ACCESS_DENIED;
+ break;
+
+ }
+
+ /* If status is error. we return status. If status_close is error we return status_close. */
+ if(status != UX_SUCCESS)
+
+ /* We return the status of read operation. */
+ return(status);
+
+ else
+
+ /* Return status from close operation. */
+ return(status_close);
+
+ }
+ }
+
+ /* Done here. Return status. */
+ return(status);
+}
+
+UINT pima_device_object_info_send (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ UX_SLAVE_CLASS_PIMA_OBJECT *object,
+ ULONG storage_id,
+ ULONG parent_object_handle,
+ ULONG *object_handle)
+{
+ULONG handle_index;
+CHAR object_filename[64];
+UINT status;
+
+ /* Make sure we can accommodate a new object here. */
+ if (pima_device_object_number_handles < UX_TEST_MAX_HANDLES)
+ {
+
+ /* The object file name is in Unicode, decrypt it first because FileX is not using
+ unicode format. */
+ ux_utility_unicode_to_string(object -> ux_device_class_pima_object_filename, (UCHAR *) object_filename);
+
+ /* The object can be either an association object (a directory) or a regular file such
+ a photo, music file, video file ... */
+ if (object -> ux_device_class_pima_object_format == UX_DEVICE_CLASS_PIMA_OFC_ASSOCIATION)
+ {
+
+ /* The object info refers to a association. We treat it as a folder. */
+ status = fx_directory_create(&ram_disk, object_filename);
+
+ /* Check status. If error, identify the problem and convert FileX error code into PIMA error code. */
+ if (status != UX_SUCCESS)
+ {
+
+ /* See what the error might be. */
+ switch (status)
+ {
+
+ case FX_MEDIA_NOT_OPEN :
+
+ /* Problem with media. */
+ status = UX_DEVICE_CLASS_PIMA_RC_STORE_NOT_AVAILABLE;
+ break;
+
+ case FX_NO_MORE_SPACE :
+
+ /* Media is full. */
+ status = UX_DEVICE_CLASS_PIMA_RC_STORE_FULL;
+ break;
+
+ case FX_WRITE_PROTECT :
+
+ /* Media is write protected. */
+ status = UX_DEVICE_CLASS_PIMA_RC_STORE_READ_ONLY;
+ break;
+
+ default :
+ status = UX_DEVICE_CLASS_PIMA_RC_ACCESS_DENIED;
+ break;
+
+ }
+
+ /* Could not create the object on the local media, return an error. */
+ return (status);
+ }
+ }
+ else
+ {
+ /* The format is for another object. */
+ /* Create the destination file. */
+ status = fx_file_create(&ram_disk, object_filename);
+
+ /* Check status. If error, identify the problem and convert FileX error code into PIMA error code. */
+ if (status != UX_SUCCESS)
+ {
+
+ /* See what the error might be. */
+ switch (status)
+ {
+
+ case FX_MEDIA_NOT_OPEN :
+
+ /* Problem with media. */
+ status = UX_DEVICE_CLASS_PIMA_RC_STORE_NOT_AVAILABLE;
+ break;
+
+ case FX_NO_MORE_SPACE :
+
+ /* Media is full. */
+ status = UX_DEVICE_CLASS_PIMA_RC_STORE_FULL;
+ break;
+
+ case FX_WRITE_PROTECT :
+
+ /* Media is write protected. */
+ status = UX_DEVICE_CLASS_PIMA_RC_STORE_READ_ONLY;
+ break;
+
+ default :
+ status = UX_DEVICE_CLASS_PIMA_RC_ACCESS_DENIED;
+ break;
+
+ }
+
+ /* Could not create the object on the local media, return an error. */
+ return (status);
+ }
+ }
+
+ /* The object is created. Store the object handle. Find a spot. */
+ for (handle_index = 0; handle_index < UX_TEST_MAX_HANDLES; handle_index++)
+ {
+
+ /* Check for an empty slot. */
+ if (pima_device_object_number_handles_array[handle_index] == 0)
+ {
+
+ /* We have found the place to store the handle and the object info. */
+ ux_utility_memory_copy(&pima_device_object_info_array[handle_index], object, sizeof(UX_SLAVE_CLASS_PIMA_OBJECT));
+ if (pima_device_object_info_array[handle_index].ux_device_class_pima_object_storage_id == 0)
+ pima_device_object_info_array[handle_index].ux_device_class_pima_object_storage_id = storage_id;
+ if (pima_device_object_info_array[handle_index].ux_device_class_pima_object_parent_object == 0xFFFFFFFF)
+ pima_device_object_info_array[handle_index].ux_device_class_pima_object_parent_object = 0;
+
+ /* Remember the object handle locally. */
+ pima_device_object_number_handles_array[handle_index] = handle_index + 1;
+
+ /* Extract from the object the MTP dataset information we need : StorageID.
+ if the storage id in the object info dataset is 0, the Initiator leaves it to the responder to store the object. */
+ if (object -> ux_device_class_pima_object_storage_id != 0)
+ pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_storage_id = object -> ux_device_class_pima_object_storage_id;
+ else
+ /* Take the storage ID given as a parameter by the function. */
+ pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_storage_id = storage_id;
+
+ /* Extract from the object the MTP dataset information we need : Format. */
+ pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_object_format = object -> ux_device_class_pima_object_format;
+
+ /* Extract from the object the MTP dataset information we need : Protection Status. */
+ pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_protection_status = object -> ux_device_class_pima_object_protection_status;
+
+ /* Extract from the object the MTP dataset information we need : Size. */
+ pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_object_size_low = object -> ux_device_class_pima_object_compressed_size;
+ pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_object_size_high = 0;
+
+ /* Extract from the object the MTP dataset information we need : Parent Object. */
+ if (object -> ux_device_class_pima_object_parent_object == 0xFFFFFFFF)
+ pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_parent_object = 0;
+ else
+ pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_parent_object = object -> ux_device_class_pima_object_parent_object;
+
+ /* Keep the file name in ASCIIZ. */
+ ux_utility_unicode_to_string(object -> ux_device_class_pima_object_filename, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_object_file_name);
+ ux_utility_unicode_to_string(object -> ux_device_class_pima_object_filename, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_name);
+
+ /* Keep the unique object identifier for this object. This is incremented each time we have a new object.
+ This number is unique to the MTP device for every object stored, even after being deleted.
+ There is a hack here. We only keep track of the first dword. A full implementation should ensure all 128 bits are used.
+ The identifier is incremented as soon as it is being used. */
+ pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_persistent_unique_object_identifier[0] = pima_device_object_persistent_unique_identifier++;
+
+ /* Return the object handle to the application. */
+ *object_handle = handle_index + 1;
+
+ /* Increment the number of known handles. */
+ pima_device_object_number_handles++;
+
+ /* We are done here. Return success. */
+ return(UX_SUCCESS);
+ }
+ }
+
+ /* We should never get here. */
+ return(UX_DEVICE_CLASS_PIMA_RC_STORE_FULL);
+
+ }
+
+ /* No more space for handle. Return storage full. */
+ return(UX_DEVICE_CLASS_PIMA_RC_STORE_FULL);
+
+}
+
+
+UINT pima_device_object_data_send (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle,
+ ULONG phase ,
+ UCHAR *object_buffer,
+ ULONG object_offset,
+ ULONG object_length)
+{
+
+UINT status;
+ULONG handle_index;
+UX_SLAVE_CLASS_PIMA_OBJECT *object;
+CHAR object_filename[64];
+
+ /* Check the object handle. It must be in the local array. */
+ status = pima_device_object_handle_check(object_handle, &object, &handle_index);
+
+ /* Does the object handle exist ? */
+ if (status == UX_SUCCESS)
+ {
+
+ /* Check the phase. Either Active or Complete. */
+ switch (phase)
+ {
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_TRANSFER_PHASE_ACTIVE :
+
+ /* We are either at the beginning of the transfer or continuing the transfer. */
+ if (object_offset == 0)
+ {
+
+ /* The object file name is in Unicode, decrypt it first because FileX is not using
+ unicode format. */
+ ux_utility_unicode_to_string(object -> ux_device_class_pima_object_filename, (UCHAR *) object_filename);
+
+ /* Open the file on the media since we expect a SendObject. */
+ status = fx_file_open(&ram_disk, &pima_device_object_filex_array[handle_index], object_filename, FX_OPEN_FOR_WRITE);
+ if (status != UX_SUCCESS)
+ return(UX_DEVICE_CLASS_PIMA_RC_OBJECT_NOT_OPENED);
+
+ /* Seek to the beginning of the object file. */
+ status = fx_file_seek(&pima_device_object_filex_array[handle_index], 0);
+ if (status != UX_SUCCESS)
+ return(UX_DEVICE_CLASS_PIMA_RC_OBJECT_NOT_OPENED);
+ }
+
+ /* We write the object data to the media. */
+ status = fx_file_write(&pima_device_object_filex_array[handle_index], object_buffer, object_length);
+
+ /* Check the status. */
+ if (status == UX_SUCCESS)
+
+ /* Done. Operation successful. */
+ return (UX_SUCCESS);
+
+ else
+ {
+
+ /* See what the error might be. */
+ switch (status)
+ {
+
+ case FX_MEDIA_NOT_OPEN :
+
+ /* Problem with media. */
+ status = UX_DEVICE_CLASS_PIMA_RC_STORE_NOT_AVAILABLE;
+ break;
+
+ case FX_NO_MORE_SPACE :
+
+ /* Media is full. */
+ status = UX_DEVICE_CLASS_PIMA_RC_STORE_FULL;
+ break;
+
+ case FX_WRITE_PROTECT :
+
+ /* Media is write protected. */
+ status = UX_DEVICE_CLASS_PIMA_RC_STORE_READ_ONLY;
+ break;
+
+ default :
+ status = UX_DEVICE_CLASS_PIMA_RC_ACCESS_DENIED;
+ break;
+
+ }
+ /* Return the error. */
+ return(status);
+
+ }
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_TRANSFER_PHASE_COMPLETED :
+
+ /* Save final object size. */
+ pima_device_object_info_array[handle_index].ux_device_class_pima_object_compressed_size =
+ pima_device_object_filex_array[handle_index].fx_file_current_file_size;
+
+ /* This is the end of the transfer for the object. Close it. */
+ status = fx_file_close(&pima_device_object_filex_array[handle_index]);
+ pima_device_object_filex_array[handle_index].fx_file_id = 0;
+
+ /* Check the status. */
+ if (status == UX_SUCCESS)
+
+ /* Done. Operation successful. */
+ return (UX_SUCCESS);
+
+ else
+ {
+
+ /* See what the error might be. */
+ switch (status)
+ {
+
+ case FX_MEDIA_NOT_OPEN :
+
+ /* Problem with media. */
+ status = UX_DEVICE_CLASS_PIMA_RC_STORE_NOT_AVAILABLE;
+ break;
+
+ default :
+ status = UX_DEVICE_CLASS_PIMA_RC_ACCESS_DENIED;
+ break;
+
+ }
+ /* Return the error. */
+ return(status);
+
+ }
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_TRANSFER_PHASE_COMPLETED_ERROR :
+
+ /* Close and delete the object. */
+ pima_device_object_delete(pima, object_handle);
+
+ /* We return OK no matter what. */
+ return(UX_SUCCESS);
+ }
+ }
+
+ /* Done here. Return error. */
+ return(UX_DEVICE_CLASS_PIMA_RC_INVALID_OBJECT_HANDLE);
+
+}
+
+UINT pima_device_object_delete(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle)
+{
+UX_SLAVE_CLASS_PIMA_OBJECT *object;
+ULONG handle_index;
+CHAR object_filename[64];
+UINT status;
+
+ /* Check the object handle. It must be in the local array. */
+ status = pima_device_object_handle_check(object_handle, &object, &handle_index);
+
+ /* Does the object handle exist ? */
+ if (status == UX_SUCCESS)
+ {
+
+ /* The object file name is in Unicode, decrypt it first because FileX is not using
+ unicode format. */
+ ux_utility_unicode_to_string(object -> ux_device_class_pima_object_filename, (UCHAR *) object_filename);
+
+ /* Yes, the handle is valid. The object pointer has been updated. */
+ /* The object may still be opened, try to close the handle first. */
+ status = fx_file_close(&pima_device_object_filex_array[handle_index]);
+
+ /* Delete the destination file. */
+ status = fx_file_delete(&ram_disk, object_filename);
+
+ /* Check if we had an error. */
+ if (status != UX_SUCCESS)
+ {
+
+ /* See what the error might be. */
+ switch (status)
+ {
+
+ case FX_MEDIA_NOT_OPEN :
+
+ /* Problem with media. */
+ status = UX_DEVICE_CLASS_PIMA_RC_STORE_NOT_AVAILABLE;
+ break;
+
+ case FX_WRITE_PROTECT :
+
+ /* Media is write protected. */
+ status = UX_DEVICE_CLASS_PIMA_RC_STORE_READ_ONLY;
+ break;
+
+ default :
+ status = UX_DEVICE_CLASS_PIMA_RC_ACCESS_DENIED;
+ break;
+ }
+
+ /* Return the error code. */
+ return(status);
+
+ }
+ else
+ {
+
+ /* The object was deleted on disk. Now update the internal application array tables. */
+ pima_device_object_number_handles_array[handle_index] = 0;
+
+ /* Update the number of handles in the system. */
+ pima_device_object_number_handles--;
+
+ /* We are done here. */
+ return(UX_SUCCESS);
+ }
+
+ }
+ else
+
+ /* Done here. Return error. */
+ return(UX_DEVICE_CLASS_PIMA_RC_INVALID_OBJECT_HANDLE);
+}
+
+
+UINT pima_device_object_prop_desc_get (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_property,
+ ULONG object_format_code,
+ UCHAR **object_prop_dataset,
+ ULONG *object_prop_dataset_length)
+{
+UINT status;
+UCHAR *object_property_dataset_data;
+ULONG object_property_dataset_data_length;
+
+ /* Check the object format belongs to the list. 3 categories : generic, audio, video */
+ switch (object_format_code)
+ {
+
+ case UX_DEVICE_CLASS_PIMA_OFC_UNDEFINED :
+ case UX_DEVICE_CLASS_PIMA_OFC_ASSOCIATION :
+ case UX_DEVICE_CLASS_PIMA_OFC_MP3 :
+ case UX_DEVICE_CLASS_PIMA_OFC_ASF :
+ case UX_DEVICE_CLASS_PIMA_OFC_WMA :
+ case UX_DEVICE_CLASS_PIMA_OFC_WMV :
+ case UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_AUDIO_ALBUM :
+ case UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_AUDIO_AND_VIDEO_PLAYLIST :
+
+ /* Set the pointer to the dataset_buffer. */
+ object_property_dataset_data = pima_device_object_property_dataset_data_buffer;
+
+ /* Isolate the property. That will determine the dataset header. */
+ switch (object_property)
+ {
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_STORAGEID :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_STORAGEID);
+
+ /* Data type is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT16);
+
+ /* GetSet value is GET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GET;
+
+ /* Default value is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+
+ /* Group code is NULL. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 2, 0);
+
+ /* Form Flag is not used. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 6) = 0;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 12;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FORMAT :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FORMAT);
+
+ /* Data type is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT16);
+
+ /* GetSet value is GET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GET;
+
+ /* Default value is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+
+ /* Group code is 3. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 2, 3);
+
+ /* Form Flag is not used. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 6) = 0;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 12;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PROTECTION_STATUS :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PROTECTION_STATUS);
+
+ /* Data type is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT16);
+
+ /* GetSet value is GET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GET;
+
+ /* Default value is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+
+ /* Group code is 4. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 2, 4);
+
+ /* Form Flag ENUM. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 6) = 2;
+
+ /* Number of elements in Enum array. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 7, 2);
+
+ /* Elements in Enum array. Here we store only No protection and Read-Only protection values. This can be extended with
+ Read-only data and Non transferrable data. Spec talks about MTP vendor extension range as well. Not used here. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 9, 0);
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 11, 1);
+
+ /* Set the length. */
+ object_property_dataset_data_length = 18;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_SIZE :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_SIZE);
+
+ /* Data type is UINT64. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT64);
+
+ /* GetSet value is GET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GET;
+
+ /* Default value is UINT64. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 4, 0);
+
+ /* Group code is NULL. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 8, 0);
+
+ /* Form Flag is not used. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 12) = 0;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 18;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FILE_NAME :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FILE_NAME);
+
+ /* Data type is STRING. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_STR);
+
+ /* GetSet value is GETSET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GETSET;
+
+ /* Store a empty Unicode string. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE) = 0;
+
+ /* Group code is NULL. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 1, 0);
+
+ /* Form Flag is not used. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 5) = 0;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 11;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PARENT_OBJECT :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PARENT_OBJECT);
+
+ /* Data type is UINT32. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT32);
+
+ /* GetSet value is GET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GET;
+
+ /* Default value is UINT32. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+
+ /* Group code is NULL. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 4, 0);
+
+ /* Form Flag is not used. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 8) = 0;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 14;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER);
+
+ /* Data type is UINT128. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT128);
+
+ /* GetSet value is GET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GET;
+
+ /* Default value is UINT128. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 4, 0);
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 8, 0);
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 12, 0);
+
+ /* Group code is NULL. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 16, 0);
+
+ /* Form Flag is not used. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 20) = 0;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 26;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NAME :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NAME);
+
+ /* Data type is STRING. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_STR);
+
+ /* GetSet value is GETSET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GETSET;
+
+ /* Store a empty Unicode string. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE) = 0;
+
+ /* Group code is 2. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 1, 2);
+
+ /* Form Flag is not used. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 5) = 0;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 11;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NON_CONSUMABLE :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NON_CONSUMABLE);
+
+ /* Data type is UINT8. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT8);
+
+ /* GetSet value is GET/SET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GETSET;
+
+ /* Default value is UINT8. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE) = 0;
+
+ /* Group code is 2. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 1, 2);
+
+ /* Form Flag ENUM. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 5) = 2;
+
+ /* Number of elements in Enum array. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 6, 2);
+
+ /* Elements in Enum array. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 8) = 0;
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 9) = 1;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 15;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ARTIST :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ARTIST);
+
+ /* Data type is STRING. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_STR);
+
+ /* GetSet value is GETSET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GETSET;
+
+ /* Store a empty Unicode string. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE) = 0;
+
+ /* Group code is NULL. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 1, 0);
+
+ /* Form Flag is not used. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 5) = 0;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 11;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_TRACK :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_TRACK);
+
+ /* Data type is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT16);
+
+ /* GetSet value is GET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GET;
+
+ /* Default value is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+
+ /* Group code is 3. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 2, 3);
+
+ /* Form Flag is not used. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 6) = 0;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 12;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_USE_COUNT :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_USE_COUNT);
+
+ /* Data type is UINT32. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT32);
+
+ /* GetSet value is GET/SET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GETSET;
+
+ /* Default value is UINT32. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+
+ /* Group code is 1. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 4, 0);
+
+ /* Form Flag is not used. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 8) = 0;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 14;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_DATE_AUTHORED :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_DATE_AUTHORED);
+
+ /* Data type is STRING. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_STR);
+
+ /* GetSet value is GETSET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GETSET;
+
+ /* Store a empty Unicode string. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE) = 0;
+
+ /* Group code is NULL. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 1, 0);
+
+ /* Form Flag is 3. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 5) = 3;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 11;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_GENRE :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_GENRE);
+
+ /* Data type is STRING. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_STR);
+
+ /* GetSet value is GETSET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GETSET;
+
+ /* Store a empty Unicode string. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE) = 0;
+
+ /* Group code is NULL. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 1, 0);
+
+ /* Form Flag is not used. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 5) = 0;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 11;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ALBUM_NAME :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ALBUM_NAME);
+
+ /* Data type is STRING. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_STR);
+
+ /* GetSet value is GETSET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GETSET;
+
+ /* Store a empty Unicode string. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE) = 0;
+
+ /* Group code is NULL. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 1, 0);
+
+ /* Form Flag is not used. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 5) = 0;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 11;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ALBUM_ARTIST :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ALBUM_ARTIST);
+
+ /* Data type is STRING. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_STR);
+
+ /* GetSet value is GETSET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GETSET;
+
+ /* Store a empty Unicode string. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE) = 0;
+
+ /* Group code is NULL. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 1, 0);
+
+ /* Form Flag is not used. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 5) = 0;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 11;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_SAMPLE_RATE :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_SAMPLE_RATE);
+
+ /* Data type is UINT32. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT32);
+
+ /* GetSet value is GET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GET;
+
+ /* Default value is UINT32. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+
+ /* Group code is 0. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 4, 0);
+
+ /* Form Flag RANGE. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 8) = 1;
+
+ /* Minimum range in array is 0KHZ. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 9, 0x00000000);
+
+ /* Maximum range in array is KHZ. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 13,0x0002EE00 );
+
+ /* Range step size is 32HZ. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 17,0x00000020 );
+
+ /* Set the length. */
+ object_property_dataset_data_length = 26;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NUMBER_OF_CHANNELS :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NUMBER_OF_CHANNELS);
+
+ /* Data type is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT16);
+
+ /* GetSet value is GET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GET;
+
+ /* Default value is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+
+ /* Group code is 0. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 2, 0);
+
+ /* Form Flag ENUM. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 6) = 2;
+
+ /* Number of elements in Enum array. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 7, 3);
+
+ /* Elements in Enum array. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 9, 0);
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 11, 1);
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 13, 2);
+
+ /* Set the length. */
+ object_property_dataset_data_length = 20;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_AUDIO_WAVE_CODEC :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_AUDIO_WAVE_CODEC);
+
+ /* Data type is UINT32. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT32);
+
+ /* GetSet value is GET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GET;
+
+ /* Default value is UINT32. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+
+ /* Group code is 0. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 4, 0);
+
+ /* Form Flag ENUM. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 8) = 2;
+
+ /* Number of elements in Enum array. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 9, 3);
+
+ /* Elements in Enum array. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 11, UX_TEST_AUDIO_CODEC_WAVE_FORMAT_MPEGLAYER3);
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 15, UX_TEST_AUDIO_CODEC_WAVE_FORMAT_MPEG);
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 19, UX_TEST_AUDIO_CODEC_WAVE_FORMAT_RAW_AAC1);
+
+ /* Set the length. */
+ object_property_dataset_data_length = 28;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_AUDIO_BITRATE :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_AUDIO_BITRATE);
+
+ /* Data type is UINT32. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT32);
+
+ /* GetSet value is GET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GET;
+
+ /* Default value is UINT32. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0x0000FA00);
+
+ /* Group code is 0. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 4, 0);
+
+ /* Form Flag RANGE. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 8) = 1;
+
+ /* Minimum range in array is 1 bit per second. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 9, 0x00000001);
+
+ /* Maximum range in array is 1,500,000 bit per second. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 13,0x0016E360 );
+
+ /* Range step size is 1 bit per second. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 17,0x00000001 );
+
+ /* Set the length. */
+ object_property_dataset_data_length = 26;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_DURATION :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_DURATION);
+
+ /* Data type is UINT32. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT32);
+
+ /* GetSet value is GET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GET;
+
+ /* Default value is UINT32. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+
+ /* Group code is NULL. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 4, 0);
+
+ /* Form Flag is 1. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 8) = 1;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 14;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_WIDTH :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_WIDTH);
+
+ /* Data type is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT16);
+
+ /* GetSet value is GET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GET;
+
+ /* Default value is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0x0000);
+
+ /* Group code is 0. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 2, 0);
+
+ /* Form Flag RANGE. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 4) = 1;
+
+ /* Minimum range in array is customer defined. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 5, 0x0000);
+
+ /* Maximum range in array is customer defined. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 7, 0x0000);
+
+ /* Range step size is customer defined. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 9, 0x0000);
+
+ /* Set the length. */
+ object_property_dataset_data_length = 11;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_HEIGHT :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_HEIGHT);
+
+ /* Data type is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT16);
+
+ /* GetSet value is GET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GET;
+
+ /* Default value is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0x0000);
+
+ /* Group code is 0. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 2, 0);
+
+ /* Form Flag RANGE. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 4) = 1;
+
+ /* Minimum range in array is customer defined. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 5, 0x0000);
+
+ /* Maximum range in array is customer defined. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 7, 0x0000);
+
+ /* Range step size is customer defined. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 9, 0x0000);
+
+ /* Set the length. */
+ object_property_dataset_data_length = 11;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_SCAN_TYPE :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_SCAN_TYPE);
+
+ /* Data type is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT16);
+
+ /* GetSet value is GET/SET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GETSET;
+
+ /* Default value is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+
+ /* Group code is 0. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 2, 2);
+
+ /* Form Flag ENUM. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 5) = 2;
+
+ /* Number of elements in Enum array. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 7, 8);
+
+ /* Elements in Enum array. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 9, 0x0000);
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 11, 0x0001);
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 13, 0x0002);
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 15, 0x0003);
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 17, 0x0004);
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 19, 0x0005);
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 21, 0x0006);
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 23, 0x0007);
+
+ /* Set the length. */
+ object_property_dataset_data_length = 29;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_VIDEO_FOURCC_CODEC :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_VIDEO_FOURCC_CODEC);
+
+ /* Data type is UINT32. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT32);
+
+ /* GetSet value is GET/SET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GETSET;
+
+ /* Default value is UINT32. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+
+ /* Group code is 0. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 4, 2);
+
+ /* Form Flag ENUM. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 8) = 2;
+
+ /* Number of elements in Enum array. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 9, 1);
+
+ /* Elements in Enum array. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 13, 0x00000000);
+
+ /* Set the length. */
+ object_property_dataset_data_length = 22;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_VIDEO_BITRATE :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_VIDEO_BITRATE);
+
+ /* Data type is UINT32. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT32);
+
+ /* GetSet value is GET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GET;
+
+ /* Default value is UINT32. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+
+ /* Group code is 0. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 4, 2);
+
+ /* Form Flag RANGE. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 8) = 1;
+
+ /* Minimum range in array is 0. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 9, 0x00000000);
+
+ /* Maximum range in array is 0xFFFFFFFF. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 13,0xFFFFFFFF );
+
+ /* Range step size is 1. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 17,0x00000001 );
+
+ /* Set the length. */
+ object_property_dataset_data_length = 26;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_FRAMES_PER_THOUSAND_SECONDS :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_FRAMES_PER_THOUSAND_SECONDS);
+
+ /* Data type is UINT32. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT32);
+
+ /* GetSet value is GET/SET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GETSET;
+
+ /* Default value is UINT32. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+
+ /* Group code is 0. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 4, 2);
+
+ /* Form Flag ENUM. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 8) = 2;
+
+ /* Number of elements in Enum array. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 9, 1);
+
+ /* Elements in Enum array. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 13, 0x00000000);
+
+ /* Set the length. */
+ object_property_dataset_data_length = 22;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_KEYFRAME_DISTANCE :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_KEYFRAME_DISTANCE);
+
+ /* Data type is UINT32. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT32);
+
+ /* GetSet value is GET/SET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GETSET;
+
+ /* Default value is UINT32. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+
+ /* Group code is 0. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 4, 2);
+
+ /* Form Flag RANGE. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 8) = 1;
+
+ /* Minimum range in array is 0. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 9, 0x00000000);
+
+ /* Maximum range in array is FFFFFFFF. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 13,0x0000FFFF );
+
+ /* Range step size is 1. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 17,0x00000001 );
+
+ /* Set the length. */
+ object_property_dataset_data_length = 26;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ENCODING_PROFILE :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ENCODING_PROFILE);
+
+ /* Data type is STRING. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_STR);
+
+ /* GetSet value is GETSET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GETSET;
+
+ /* Store a empty Unicode string. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE) = 0;
+
+ /* Group code is NULL. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 1, 0);
+
+ /* Form Flag is not used. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 5) = 0;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 11;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ default :
+
+ /* Error, prop code is not valid. */
+ status = UX_DEVICE_CLASS_PIMA_RC_INVALID_OBJECT_PROP_CODE;
+
+ }
+
+ /* Check the status of the operation. */
+ if (status == UX_SUCCESS)
+ {
+
+ /* The property exist and its dataset created. Return its pointer to MTP. */
+ *object_prop_dataset = object_property_dataset_data;
+
+ /* And the length of the dataset. */
+ *object_prop_dataset_length = object_property_dataset_data_length;
+
+ /* Done here. */
+ return(UX_SUCCESS);
+ }
+ else
+
+ /* Done here. Return error. */
+ return(UX_DEVICE_CLASS_PIMA_RC_INVALID_OBJECT_PROP_CODE);
+
+ break;
+
+ default :
+
+ /* We get here when we have the wrong format code. */
+ return(UX_DEVICE_CLASS_PIMA_RC_INVALID_OBJECT_FORMAT_CODE);
+ }
+
+}
+
+
+UINT pima_device_object_prop_value_get (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle,
+ ULONG object_property,
+ UCHAR **object_prop_value,
+ ULONG *object_prop_value_length)
+{
+
+ULONG handle_index;
+UINT status;
+UCHAR *object_property_dataset_data;
+ULONG object_property_value_data_length;
+UX_SLAVE_CLASS_PIMA_OBJECT *object;
+
+ /* Check the object handle. It must be in the local array. */
+ status = pima_device_object_handle_check(object_handle, &object, &handle_index);
+
+ /* Does the object handle exist ? */
+ if (status == UX_SUCCESS)
+ {
+
+ /* Set the pointer to the dataset_buffer. */
+ object_property_dataset_data = pima_device_object_property_dataset_data_buffer;
+
+ /* Isolate the property. That will determine were we fetch the value. We use the dataset storage area to build the value. */
+ switch (object_property)
+ {
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_STORAGEID :
+
+ /* Copy the value itself. */
+ ux_utility_long_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_storage_id);
+
+ /* Set the length. */
+ object_property_value_data_length = 4;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FORMAT :
+
+ /* Copy the value itself. */
+ ux_utility_short_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_object_format);
+
+ /* Set the length. */
+ object_property_value_data_length = 2;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PROTECTION_STATUS :
+
+ /* Copy the value itself. */
+ ux_utility_short_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_protection_status);
+
+ /* Set the length. */
+ object_property_value_data_length = 2;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_SIZE :
+
+ /* Copy the value itself. */
+ ux_utility_long_put(object_property_dataset_data , pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_object_size_low);
+ ux_utility_long_put(object_property_dataset_data + 4, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_object_size_high);
+
+ /* Set the length. */
+ object_property_value_data_length = 8;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FILE_NAME :
+
+ /* Store the file name in unicode format. */
+ ux_utility_string_to_unicode(pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_object_file_name, object_property_dataset_data);
+
+ /* Set the length. First Unicode string data. */
+ object_property_value_data_length = (ULONG) *(object_property_dataset_data) * 2 + 1;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PARENT_OBJECT :
+
+ /* Copy the value itself. */
+ ux_utility_long_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_parent_object);
+
+ /* Set the length. */
+ object_property_value_data_length = 4;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER :
+
+ /* Copy the value itself. */
+ ux_utility_memory_copy(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_persistent_unique_object_identifier,16);
+
+ /* Set the length. */
+ object_property_value_data_length = 16;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NAME :
+
+ /* Store the file name in unicode format. */
+ ux_utility_string_to_unicode(pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_name, object_property_dataset_data);
+
+ /* Set the length. First Unicode string data. */
+ object_property_value_data_length = (ULONG) *(object_property_dataset_data) * 2 + 1;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NON_CONSUMABLE :
+
+ /* Copy the value itself. */
+ *object_property_dataset_data = pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_non_consumable;
+
+ /* Set the length. */
+ object_property_value_data_length = 1;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ARTIST :
+
+ /* Store the file name in unicode format. */
+ ux_utility_string_to_unicode(pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_artist, object_property_dataset_data);
+
+ /* Set the length. First Unicode string data. */
+ object_property_value_data_length = (ULONG) *(object_property_dataset_data) * 2 + 1;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_TRACK :
+
+ /* Copy the value itself. */
+ ux_utility_short_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_track);
+
+ /* Set the length. */
+ object_property_value_data_length = 2;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_USE_COUNT :
+
+ /* Copy the value itself. */
+ ux_utility_short_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_use_count);
+
+ /* Set the length. */
+ object_property_value_data_length = 2;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_DATE_AUTHORED :
+
+ /* Store the file name in unicode format. */
+ ux_utility_string_to_unicode(pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_date_authored, object_property_dataset_data);
+
+ /* Set the length. First Unicode string data. */
+ object_property_value_data_length = (ULONG) *(object_property_dataset_data) * 2 + 1;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_GENRE :
+
+ /* Store the file name in unicode format. */
+ ux_utility_string_to_unicode(pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_genre, object_property_dataset_data);
+
+ /* Set the length. First Unicode string data. */
+ object_property_value_data_length = (ULONG) *(object_property_dataset_data) * 2 + 1;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ALBUM_NAME :
+
+ /* Store the file name in unicode format. */
+ ux_utility_string_to_unicode(pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_album_name, object_property_dataset_data);
+
+ /* Set the length. First Unicode string data. */
+ object_property_value_data_length = (ULONG) *(object_property_dataset_data) * 2 + 1;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ALBUM_ARTIST :
+
+ /* Store the file name in unicode format. */
+ ux_utility_string_to_unicode(pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_album_artist, object_property_dataset_data);
+
+ /* Set the length. First Unicode string data. */
+ object_property_value_data_length = (ULONG) *(object_property_dataset_data) * 2 + 1;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_SAMPLE_RATE :
+
+ /* Copy the value itself. */
+ ux_utility_short_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_sample_rate);
+
+ /* Set the length. */
+ object_property_value_data_length = 2;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NUMBER_OF_CHANNELS :
+
+ /* Copy the value itself. */
+ ux_utility_short_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_number_of_channels);
+
+ /* Set the length. */
+ object_property_value_data_length = 2;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_AUDIO_WAVE_CODEC :
+
+ /* Copy the value itself. */
+ ux_utility_long_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_audio_wave_codec);
+
+ /* Set the length. */
+ object_property_value_data_length = 4;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_AUDIO_BITRATE :
+
+ /* Copy the value itself. */
+ ux_utility_long_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_audio_bitrate);
+
+ /* Set the length. */
+ object_property_value_data_length = 4;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_DURATION :
+
+ /* Copy the value itself. */
+ ux_utility_long_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_duration);
+
+ /* Set the length. */
+ object_property_value_data_length = 4;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_WIDTH :
+
+ /* Copy the value itself. */
+ ux_utility_short_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_width);
+
+ /* Set the length. */
+ object_property_value_data_length = 2;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_HEIGHT :
+
+ /* Copy the value itself. */
+ ux_utility_short_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_height);
+
+ /* Set the length. */
+ object_property_value_data_length = 2;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_SCAN_TYPE :
+
+ /* Copy the value itself. */
+ ux_utility_short_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_scan_type);
+
+ /* Set the length. */
+ object_property_value_data_length = 2;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_VIDEO_FOURCC_CODEC :
+
+ /* Copy the value itself. */
+ ux_utility_long_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_fourcc_codec);
+
+ /* Set the length. */
+ object_property_value_data_length = 2;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_VIDEO_BITRATE :
+
+ /* Copy the value itself. */
+ ux_utility_long_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_video_bitrate);
+
+ /* Set the length. */
+ object_property_value_data_length = 4;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_FRAMES_PER_THOUSAND_SECONDS :
+
+ /* Copy the value itself. */
+ ux_utility_long_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_frames_per_thousand_seconds);
+
+ /* Set the length. */
+ object_property_value_data_length = 4;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_KEYFRAME_DISTANCE :
+
+ /* Copy the value itself. */
+ ux_utility_long_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_keyframe_distance);
+
+ /* Set the length. */
+ object_property_value_data_length = 4;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ENCODING_PROFILE :
+
+ /* Store the file name in unicode format. */
+ ux_utility_string_to_unicode(pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_encoding_profile, object_property_dataset_data);
+
+ /* Set the length. First Unicode string data. */
+ object_property_value_data_length = (ULONG) *(object_property_dataset_data) * 2 + 1;
+
+ /* Done here. */
+ break;
+
+ default :
+
+ /* Error, prop code is not valid. */
+ status = UX_DEVICE_CLASS_PIMA_RC_INVALID_OBJECT_PROP_CODE;
+
+ }
+
+ /* Check the status of the operation. */
+ if (status == UX_SUCCESS)
+ {
+
+ /* The property exist and its value created. Return its pointer to MTP. */
+ *object_prop_value = object_property_dataset_data;
+
+ /* And the length of the dataset. */
+ *object_prop_value_length = object_property_value_data_length;
+
+ /* Done here. */
+ return(UX_SUCCESS);
+ }
+ else
+
+ /* Done here. Return error. */
+ return(UX_DEVICE_CLASS_PIMA_RC_INVALID_OBJECT_PROP_CODE);
+ }
+ else
+
+ /* Done here. Return error. */
+ return(UX_DEVICE_CLASS_PIMA_RC_INVALID_OBJECT_HANDLE);
+}
+
+
+UINT pima_device_object_prop_value_set (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle,
+ ULONG object_property,
+ UCHAR *object_prop_value,
+ ULONG object_prop_value_length)
+{
+
+ULONG handle_index;
+UINT status;
+UX_SLAVE_CLASS_PIMA_OBJECT *object;
+
+ /* Check the object handle. It must be in the local array. */
+ status = pima_device_object_handle_check(object_handle, &object, &handle_index);
+
+ /* Does the object handle exist ? */
+ if (status == UX_SUCCESS)
+ {
+
+ /* Isolate the property. This is SET. So the properties that are GET only will not be changed. */
+ switch (object_property)
+ {
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_STORAGEID :
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FORMAT :
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_SIZE :
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PARENT_OBJECT :
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_DURATION :
+
+ /* Object is write protected. */
+ status = UX_DEVICE_CLASS_PIMA_RC_OBJECT_WRITE_PROTECTED;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FILE_NAME :
+
+ /* Copy the file name after translate from Unicode to ASCIIZ. */
+ ux_utility_unicode_to_string(object_prop_value, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_object_file_name);
+
+ /* We could set this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NAME :
+
+ /* Copy the name after translate from Unicode to ASCIIZ. */
+ ux_utility_unicode_to_string(object_prop_value, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_name);
+
+ /* We could set this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ARTIST :
+
+ /* Copy the artist name after translate from Unicode to ASCIIZ. */
+ ux_utility_unicode_to_string(object_prop_value, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_artist);
+
+ /* We could set this property. */
+ status = UX_SUCCESS;
+
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_DATE_AUTHORED :
+
+ /* Copy the date authored after translate from Unicode to ASCIIZ. */
+ ux_utility_unicode_to_string(object_prop_value, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_date_authored);
+
+ /* We could set this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_GENRE :
+
+ /* Copy the genre after translate from Unicode to ASCIIZ. */
+ ux_utility_unicode_to_string(object_prop_value, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_genre);
+
+ /* We could set this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ default :
+
+ /* Error, prop code is not valid. */
+ status = UX_DEVICE_CLASS_PIMA_RC_INVALID_OBJECT_PROP_CODE;
+ }
+
+
+ /* Done here. Return status. */
+ return(status);
+ }
+ else
+
+ /* Done here. Return error. */
+ return(UX_DEVICE_CLASS_PIMA_RC_INVALID_OBJECT_HANDLE);
+}
+
+
+UINT pima_device_object_references_get (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle,
+ UCHAR **object_references_array,
+ ULONG *object_references_array_length)
+{
+
+ULONG handle_index;
+UINT status;
+UX_SLAVE_CLASS_PIMA_OBJECT *object;
+ULONG references_array;
+
+ /* Check the object handle. It must be in the local array. */
+ status = pima_device_object_handle_check(object_handle, &object, &handle_index);
+
+ /* Does the object handle exist ? */
+ if (status == UX_SUCCESS)
+ {
+
+ /* The property exist. Not sure what to do with references in this release.
+ Here we simply create an empty array. */
+ references_array = 0;
+
+ /* Return its pointer to MTP. */
+ *object_references_array = (UCHAR *) &references_array;
+
+ /* And the length of the dataset. */
+ *object_references_array_length = sizeof(ULONG);
+
+ /* Done here. */
+ return(UX_SUCCESS);
+
+ }
+
+ else
+
+ /* Done here. Return error. */
+ return(UX_DEVICE_CLASS_PIMA_RC_INVALID_OBJECT_HANDLE);
+}
+
+
+UINT pima_device_object_references_set (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle,
+ UCHAR *object_references_array,
+ ULONG object_references_array_length)
+{
+
+ULONG handle_index;
+UINT status;
+UX_SLAVE_CLASS_PIMA_OBJECT *object;
+
+ /* Check the object handle. It must be in the local array. */
+ status = pima_device_object_handle_check(object_handle, &object, &handle_index);
+
+ /* Does the object handle exist ? */
+ if (status == UX_SUCCESS)
+ {
+
+ /* The property exist. Not sure what to do with references in this release. */
+
+ /* Done here. */
+ return(UX_SUCCESS);
+
+ }
+
+ else
+
+ /* Done here. Return error. */
+ return(UX_DEVICE_CLASS_PIMA_RC_INVALID_OBJECT_HANDLE);
+}
+
+
+UINT pima_device_object_handle_check(ULONG object_handle,
+ UX_SLAVE_CLASS_PIMA_OBJECT **object,
+ ULONG *caller_handle_index)
+{
+ULONG handle_index;
+
+ /* Parse all the handles we have in the media. */
+ for (handle_index = 0; handle_index < UX_TEST_MAX_HANDLES; handle_index++)
+ {
+
+ /* Check if we have the correct handle. */
+ if (pima_device_object_number_handles_array[handle_index] == object_handle)
+ {
+
+ /* We have found the right handle. Now retrieve its object info dataset. */
+ *object = &pima_device_object_info_array[handle_index];
+
+ /* Update the caller index. */
+ *caller_handle_index = handle_index;
+
+ /* We are done here. Return success. */
+ return(UX_SUCCESS);
+ }
+ }
+
+ /* We get here when the handle is unknown. Return error. */
+ return(UX_DEVICE_CLASS_PIMA_RC_INVALID_OBJECT_HANDLE);
+
+}
diff --git a/test/regression/usbx_ghsa_2ch9_host_pima_obj_handles_bound_test.c b/test/regression/usbx_ghsa_2ch9_host_pima_obj_handles_bound_test.c
new file mode 100644
index 000000000..c86ee0f56
--- /dev/null
+++ b/test/regression/usbx_ghsa_2ch9_host_pima_obj_handles_bound_test.c
@@ -0,0 +1,3943 @@
+/***************************************************************************
+ * Copyright (c) 2026 Eclipse ThreadX contributors
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the MIT License which is available at
+ * https://opensource.org/licenses/MIT.
+ *
+ * AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5).
+ * The AI-generated portions may be considered public domain (CC0-1.0)
+ * and not subject to the project's licence. The human contributor has
+ * reviewed and verified that the code is correct.
+ *
+ * SPDX-License-Identifier: MIT and CC0-1.0
+ **************************************************************************/
+
+/* This test drives the PIMA host GetObjectHandles unpack loop with a device that
+ declares more handles than the receive buffer was sized to hold. The buffer is
+ sized from the object count the session already carries, so a count between that
+ and the caller's array passes the caller side check and walks the source cursor
+ off the allocation. */
+
+#include
+#include "tx_api.h"
+#include "fx_api.h"
+#include "ux_api.h"
+#include "ux_system.h"
+#include "ux_utility.h"
+
+#include "ux_device_class_pima.h"
+#include "ux_host_class_pima.h"
+
+#include "ux_hcd_sim_host.h"
+#include "ux_device_stack.h"
+
+#include "ux_test_dcd_sim_slave.h"
+#include "ux_test_hcd_sim_host.h"
+#include "ux_test_utility_sim.h"
+
+
+/* Define constants. */
+#define UX_TEST_STACK_SIZE (2*1024)
+#define UX_TEST_MEMORY_SIZE (512*1024)
+
+#define UX_TEST_RAM_DISK_SIZE (128*1024)
+#define UX_TEST_RAM_DISK_LAST_LBA ((UX_TEST_RAM_DISK_SIZE / 512) - 1)
+
+#define UX_TEST_MAX_HANDLES 16
+#define UX_TEST_MAX_DATASET_HEADER 32
+#define UX_TEST_MAX_DATASET_SIZE 1024
+#define UX_TEST_PIMA_STORAGE_ID 1
+#define UX_TEST_VENDOR_REQUEST 0x54
+
+#define UX_TEST_CUSTOM_VID 0x0000
+#define UX_TEST_CUSTOM_PID 0x0000
+
+#define UX_TEST_AUDIO_CODEC_WAVE_FORMAT_MPEGLAYER3 0x00000055
+#define UX_TEST_AUDIO_CODEC_WAVE_FORMAT_MPEG 0x00000050
+#define UX_TEST_AUDIO_CODEC_WAVE_FORMAT_RAW_AAC1 0x000000FF
+
+
+/* Define local/extern function prototypes. */
+
+extern VOID _fx_ram_driver(FX_MEDIA *media_ptr);
+
+static void test_thread_entry(ULONG);
+
+static TX_THREAD test_thread_host_simulation;
+static TX_THREAD test_thread_device_simulation;
+static void test_thread_host_simulation_entry(ULONG);
+static void test_thread_device_simulation_entry(ULONG);
+
+static VOID test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params);
+static VOID test_hcd_entry_interaction_request_sem_put(UX_TEST_ACTION *action, VOID *params);
+static VOID test_hcd_entry_interaction_invoked(UX_TEST_ACTION *action, VOID *params);
+static VOID test_hcd_entry_interaction_wait_transfer_disconnection(UX_TEST_ACTION *action, VOID *params);
+
+static VOID test_pima_instance_activate(VOID *pima_instance);
+static VOID test_pima_instance_deactivate(VOID *pima_instance);
+
+UINT pima_device_device_reset();
+UINT pima_device_device_prop_desc_get(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG device_property,
+ UCHAR **device_prop_dataset,
+ ULONG *device_prop_dataset_length);
+UINT pima_device_device_prop_value_get(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG device_property,
+ UCHAR **device_prop_value,
+ ULONG *device_prop_value_length);
+UINT pima_device_device_prop_value_set(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG device_property,
+ UCHAR *device_prop_value,
+ ULONG device_prop_value_length);
+UINT pima_device_storage_format(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG storage_id);
+UINT pima_device_storage_info_get(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG storage_id);
+UINT pima_device_object_number_get(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_format_code,
+ ULONG object_association,
+ ULONG *object_number);
+UINT pima_device_object_handles_get (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handles_format_code,
+ ULONG object_handles_association,
+ ULONG *object_handles_array,
+ ULONG object_handles_max_number);
+UINT pima_device_object_info_get (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle,
+ UX_SLAVE_CLASS_PIMA_OBJECT **object);
+UINT pima_device_object_data_get (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle,
+ UCHAR *object_buffer,
+ ULONG object_offset,
+ ULONG object_length_requested,
+ ULONG *object_actual_length);
+UINT pima_device_object_info_send (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ UX_SLAVE_CLASS_PIMA_OBJECT *object,
+ ULONG storage_id,
+ ULONG parent_object_handle,
+ ULONG *object_handle);
+UINT pima_device_object_data_send (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle,
+ ULONG phase ,
+ UCHAR *object_buffer,
+ ULONG object_offset,
+ ULONG object_length);
+UINT pima_device_object_delete(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle);
+UINT pima_device_object_prop_desc_get (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_property,
+ ULONG object_format_code,
+ UCHAR **object_prop_dataset,
+ ULONG *object_prop_dataset_length);
+UINT pima_device_object_prop_value_get (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle,
+ ULONG object_property,
+ UCHAR **object_prop_value,
+ ULONG *object_prop_value_length);
+UINT pima_device_object_prop_value_set (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle,
+ ULONG object_property,
+ UCHAR *object_prop_value,
+ ULONG object_prop_value_length);
+UINT pima_device_object_references_get (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle,
+ UCHAR **object_references_array,
+ ULONG *object_references_array_length);
+UINT pima_device_object_references_set (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle,
+ UCHAR *object_references_array,
+ ULONG object_references_array_length);
+UINT pima_device_object_handle_check(ULONG object_handle,
+ UX_SLAVE_CLASS_PIMA_OBJECT **object,
+ ULONG *caller_handle_index);
+UINT pima_device_device_class_custom_entry(UX_SLAVE_CLASS_COMMAND *command);
+UINT pima_device_vendor_request(ULONG request, ULONG request_value, ULONG request_index, ULONG request_length,
+ UCHAR *transfer_request_buffer,
+ ULONG *transfer_request_length);
+
+
+/* Define global data structures. */
+static UCHAR usbx_memory[UX_TEST_MEMORY_SIZE + (UX_TEST_STACK_SIZE * 2)];
+
+static UX_SLAVE_CLASS_PIMA *pima_device;
+static UX_SLAVE_CLASS_PIMA_PARAMETER pima_device_parameter;
+
+static UX_HOST_CLASS_PIMA *pima_host;
+static UX_HOST_CLASS_PIMA_SESSION pima_host_session;
+static UX_HOST_CLASS_PIMA_DEVICE pima_host_device;
+static UX_HOST_CLASS_PIMA_OBJECT pima_host_object;
+
+static ULONG host_buffer[4096];
+static UCHAR *host_buffer8 = (UCHAR *)host_buffer;
+static USHORT *host_buffer16 = (USHORT *)host_buffer;
+static ULONG *host_buffer32 = (ULONG *)host_buffer;
+
+static FX_MEDIA ram_disk;
+static CHAR ram_disk_memory[UX_TEST_RAM_DISK_SIZE];
+static CHAR ram_disk_buffer[2048];
+
+
+static ULONG error_counter;
+
+static ULONG set_cfg_counter;
+
+static ULONG rsc_mem_free_on_set_cfg;
+static ULONG rsc_sem_on_set_cfg;
+static ULONG rsc_sem_get_on_set_cfg;
+static ULONG rsc_mutex_on_set_cfg;
+
+static ULONG rsc_enum_sem_usage;
+static ULONG rsc_enum_sem_get_count;
+static ULONG rsc_enum_mutex_usage;
+static ULONG rsc_enum_mem_usage;
+
+static ULONG rsc_cdc_sem_usage;
+static ULONG rsc_cdc_sem_get_count;
+static ULONG rsc_cdc_mutex_usage;
+static ULONG rsc_cdc_mem_usage;
+
+static ULONG interaction_count;
+
+static UCHAR error_callback_ignore = UX_TRUE;
+static ULONG error_callback_counter;
+
+
+/* Structure of the Object property dataset. This is specific to the local device. */
+typedef struct TEST_PIMA_OBJECT_PROP_DATASET_STRUCT
+{
+ ULONG test_pima_object_prop_dataset_storage_id;
+ ULONG test_pima_object_prop_dataset_object_format;
+ ULONG test_pima_object_prop_dataset_protection_status;
+ ULONG test_pima_object_prop_dataset_object_size_low;
+ ULONG test_pima_object_prop_dataset_object_size_high;
+ UCHAR test_pima_object_prop_dataset_object_file_name[128];
+ ULONG test_pima_object_prop_dataset_parent_object;
+ ULONG test_pima_object_prop_dataset_persistent_unique_object_identifier[4];
+ UCHAR test_pima_object_prop_dataset_name[128];
+ UCHAR test_pima_object_prop_dataset_non_consumable;
+ UCHAR test_pima_object_prop_dataset_artist[128];
+ ULONG test_pima_object_prop_dataset_track;
+ ULONG test_pima_object_prop_dataset_use_count;
+ UCHAR test_pima_object_prop_dataset_date_authored[16];
+ UCHAR test_pima_object_prop_dataset_genre[128];
+ UCHAR test_pima_object_prop_dataset_album_name[128];
+ UCHAR test_pima_object_prop_dataset_album_artist[128];
+ ULONG test_pima_object_prop_dataset_sample_rate;
+ ULONG test_pima_object_prop_dataset_number_of_channels;
+ ULONG test_pima_object_prop_dataset_audio_wave_codec;
+ ULONG test_pima_object_prop_dataset_audio_bitrate;
+ ULONG test_pima_object_prop_dataset_duration;
+ ULONG test_pima_object_prop_dataset_width;
+ ULONG test_pima_object_prop_dataset_height;
+ ULONG test_pima_object_prop_dataset_scan_type;
+ ULONG test_pima_object_prop_dataset_fourcc_codec;
+ ULONG test_pima_object_prop_dataset_video_bitrate;
+ ULONG test_pima_object_prop_dataset_frames_per_thousand_seconds;
+ ULONG test_pima_object_prop_dataset_keyframe_distance;
+ UCHAR test_pima_object_prop_dataset_encoding_profile[128];
+
+} TEST_PIMA_PROP_DATASET;
+
+
+/* Define device framework. */
+
+UCHAR device_framework_full_speed[] = {
+
+ /* Device descriptor */
+ 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08,
+ 0xE8, 0x04, 0xC5, 0x68, 0x00, 0x00, 0x01, 0x02,
+ 0x03, 0x01,
+
+ /* Configuration descriptor */
+ 0x09, 0x02, 0x27, 0x00, 0x01, 0x01, 0x00, 0xc0,
+ 0x32,
+
+ /* Interface descriptor */
+ 0x09, 0x04, 0x00, 0x00, 0x03, 0x06, 0x01, 0x01,
+ 0x00,
+
+ /* Endpoint descriptor (Bulk In) */
+ 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00,
+
+ /* Endpoint descriptor (Bulk Out) */
+ 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00,
+
+ /* Endpoint descriptor (Interrupt In) */
+ 0x07, 0x05, 0x83, 0x03, 0x40, 0x00, 0x04
+};
+#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed)
+
+UCHAR device_framework_high_speed[] = {
+
+ /* Device descriptor */
+ 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
+ 0xE8, 0x04, 0xC5, 0x68, 0x01, 0x00, 0x01, 0x02,
+ 0x03, 0x01,
+
+ /* Device qualifier descriptor */
+ 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
+ 0x01, 0x00,
+
+ /* Configuration descriptor */
+ 0x09, 0x02, 0x27, 0x00, 0x01, 0x01, 0x00, 0xc0,
+ 0x32,
+
+ /* Interface descriptor */
+ 0x09, 0x04, 0x00, 0x00, 0x03, 0x06, 0x01, 0x01,
+ 0x00,
+
+ /* Endpoint descriptor (Bulk In) */
+ 0x07, 0x05, 0x81, 0x02, 0x00, 0x02, 0x00,
+
+ /* Endpoint descriptor (Bulk Out) */
+ 0x07, 0x05, 0x02, 0x02, 0x00, 0x02, 0x00,
+
+ /* Endpoint descriptor (Interrupt In) */
+ 0x07, 0x05, 0x83, 0x03, 0x40, 0x00, 0x04
+};
+#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed)
+
+/* String Device Framework :
+ Byte 0 and 1 : Word containing the language ID : 0x0904 for US or 0x0000 for none.
+ Byte 2 : Byte containing the index of the descriptor
+ Byte 3 : Byte containing the length of the descriptor string
+
+ The last string entry can be the optional Microsoft String descriptor.
+*/
+UCHAR string_framework[] = {
+
+ /* Manufacturer string descriptor : Index 1 */
+ 0x09, 0x04, 0x01, 0x0c,
+ 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x20, 0x4c,
+ 0x6f, 0x67, 0x69, 0x63,
+
+ /* Product string descriptor : Index 2 */
+ 0x09, 0x04, 0x02, 0x0a,
+ 0x4d, 0x54, 0x50, 0x20, 0x70, 0x6c, 0x61, 0x79,
+ 0x65, 0x72,
+
+ /* Serial Number string descriptor : Index 3 */
+ 0x09, 0x04, 0x03, 0x04,
+ 0x30, 0x30, 0x30, 0x31,
+
+ /* Microsoft OS string descriptor : Index 0xEE. String is MSFT100.
+ The last byte is the vendor code used to filter Vendor specific commands.
+ The vendor commands will be executed in the class.
+ This code can be anything but must not be 0x66 or 0x67 which are PIMA class commands. */
+ 0x00, 0x00, 0xEE, 0x08,
+ 0x4D, 0x53, 0x46, 0x54,
+ 0x31, 0x30, 0x30,
+ UX_TEST_VENDOR_REQUEST
+
+};
+#define STRING_FRAMEWORK_LENGTH sizeof(string_framework)
+
+/* Multiple languages are supported on the device, to add
+ a language besides english, the unicode language code must
+ be appended to the language_id_framework array and the length
+ adjusted accordingly. */
+UCHAR language_id_framework[] = {
+
+ /* English. */
+ 0x09, 0x04
+};
+#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework)
+
+
+/* Define PIMA supported device properties. The last entry MUST be a zero. The DeviceInfoSet command
+ will parse this array and compute the number of functions supported and return it to the
+ host. For each declared device property, a dataset must be created in the application. */
+USHORT pima_device_prop_supported[] = {
+
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_UNDEFINED, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_BATTERY_LEVEL, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_FUNCTIONALMODE, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_IMAGE_SIZE, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_COMPRESSION_SETTING, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_WHITE_BALANCE, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_RGB_GAIN, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_F_NUMBER, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_FOCAL_LENGTH, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_FOCUS_DISTANCE, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_FOCUS_MODE, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_EXPOSURE_METERING_MODE, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_FLASH_MODE, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_EXPOSURE_TIME, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_EXPOSURE_PROGRAM_MODE, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_EXPOSURE_INDEX, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_EXPOSURE_BIAS_COMPENSATION, */
+ UX_DEVICE_CLASS_PIMA_DEV_PROP_DATE_TIME,
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_CAPTURE_DELAY, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_STILL_CAPTURE_MODE, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_CONTRAST, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_SHARPNESS, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_DIGITAL_ZOOM, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_EFFECT_MODE, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_BURST_NUMBER, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_BURST_INTERVAL, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_TIME_LAPSE_NUMBER, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_TIME_LAPSE_INTERVAL, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_FOCUS_METERING_MODE, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_UPLOAD_URL, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_ARTIST, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_COPYRIGHT_INFO, */
+#ifdef UX_PIMA_WITH_MTP_SUPPORT
+ UX_DEVICE_CLASS_PIMA_DEV_PROP_SYNCHRONIZATION_PARTNER,
+ UX_DEVICE_CLASS_PIMA_DEV_PROP_DEVICE_FRIENDLY_NAME,
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_VOLUME, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_SUPPORTED_FORMATS_ORDERED, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_DEVICE_ICON, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_PLAYBACK_RATE, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_PLAYBACK_OBJECT, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_PLAYBACK_CONTAINER, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_SESSION_INITIATOR_VERSION_INFO, */
+ /*UX_DEVICE_CLASS_PIMA_DEV_PROP_PERCEIVED_DEVICE_TYPE, */
+#endif
+ 0
+};
+
+/* Define PIMA supported capture formats. The last entry MUST be a zero. The DeviceInfoSet command
+ will parse this array and compute the number of functions supported and return it to the
+ host. */
+USHORT pima_device_supported_capture_formats[] = {
+ 0
+};
+
+/* Define PIMA supported image formats. The last entry MUST be a zero. The DeviceInfoSet command
+ will parse this array and compute the number of formats supported and return it to the
+ host. */
+USHORT pima_device_supported_image_formats[] = {
+ UX_DEVICE_CLASS_PIMA_OFC_UNDEFINED,
+ UX_DEVICE_CLASS_PIMA_OFC_ASSOCIATION,
+ /*UX_DEVICE_CLASS_PIMA_OFC_SCRIPT, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_EXECUTABLE, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_TEXT, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_HTML, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_DPOF, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_AIFF, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_WAV,*/
+ UX_DEVICE_CLASS_PIMA_OFC_MP3,
+ /*UX_DEVICE_CLASS_PIMA_OFC_AVI, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_MPEG, */
+ UX_DEVICE_CLASS_PIMA_OFC_ASF,
+ /*UX_DEVICE_CLASS_PIMA_OFC_DEFINED, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_EXIF_JPEG, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_TIFF_EP, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_FLASHPIX, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_BMP, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_CIFF, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_UNDEFINED, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_GIF, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_JFIF, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_CD, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_PICT, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_PNG, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_UNDEFINED, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_TIFF, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_TIFF_IT, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_JP2, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_JPX, */
+#ifdef UX_PIMA_WITH_MTP_SUPPORT
+ /*UX_DEVICE_CLASS_PIMA_OFC_UNDEFINED_FIRMWARE, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_WINDOWS_IMAGE_FORMAT, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_UNDEFINED_AUDIO, */
+ UX_DEVICE_CLASS_PIMA_OFC_WMA,
+ /*UX_DEVICE_CLASS_PIMA_OFC_OGG, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_AAC, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_AUDIBLE, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_FLAC, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_UNDEFINED_VIDEO, */
+ UX_DEVICE_CLASS_PIMA_OFC_WMV,
+ /*UX_DEVICE_CLASS_PIMA_OFC_MP4_CONTAINER, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_MP2, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_3GP_CONTAINER, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_UNDEFINED_COLLECTION, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_MULTIMEDIA_ALBUM, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_IMAGE_ALBUM, */
+ UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_AUDIO_ALBUM,
+ /*UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_VIDEO_ALBUM, */
+ UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_AUDIO_AND_VIDEO_PLAYLIST,
+ /*UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_CONTACT_GROUP, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_MESSAGE_FOLDER, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_CHAPTERED_PRODUCTION, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_AUDIO_PLAYLIST, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_VIDEO_PLAYLIST, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_MEDIACAST, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_WPL_PLAYLIST, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_M3U_PLAYLIST, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_MPL_PLAYLIST, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_ASX_PLAYLIST, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_PLS_PLAYLIST, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_UNDEFINED_DOCUMENT, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_DOCUMENT, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_XML_DOCUMENT, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_MICROSOFT_WORD_DOCUMENT, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_MHT_COMPILED_HTML_DOCUMENT, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_MICROSOFT_EXCEL_SPREADSHEET, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_MICROSOFT_POWERPOINT_PRESENTATION, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_UNDEFINED_MESSAGE, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_MESSAGE, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_UNDEFINED_CONTACT, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_CONTACT, */
+ /*UX_DEVICE_CLASS_PIMA_OFC_VCARD2, */
+#endif
+ 0
+};
+
+/* Device property dataset. Here we give the example of the Date/Time dataset. */
+UCHAR pima_device_prop_date_time_dataset[] = {
+
+ /* Device prop code : Date/Time. */
+ 0x11, 0x50, /* Prop code */
+ 0xff, 0xff, /* String */
+ 0x01, /* GET/SET */
+ 0x00, /* Default value : empty string. */
+ 0x10, /* Current value : length of the unicode string. */
+ 0x31, 0x00, 0x39, 0x00, 0x38, 0x00, 0x30, 0x00, /* YYYY */
+ 0x30, 0x00, 0x31, 0x00, /* MM */
+ 0x30, 0x00, 0x31, 0x00, /* DD */
+ 0x54, 0x00, /* T */
+ 0x30, 0x00, 0x30, 0x00, /* HH */
+ 0x30, 0x00, 0x30, 0x00, /* MM */
+ 0x30, 0x00, 0x30, 0x00, /* SS */
+ 0x00, 0x00, /* Unicode terminator. */
+ 0x00 /* Form Flag : None. */
+};
+#define DEVICE_PROP_DATE_TIME_DATASET_LENGTH sizeof(pima_device_prop_date_time_dataset) /* 40 */
+
+/* Device property dataset. Here we give the example of the synchronization partner dataset. */
+UCHAR pima_device_prop_synchronization_partner_dataset[] = {
+
+ /* Device prop code : Synchronization Partner. */
+ 0x01, 0xD4, /* Prop code */
+ 0xff, 0xff, /* String */
+ 0x01, /* GET/SET */
+ 0x00, /* Default value : empty string. */
+ 0x00, /* Current value : empty string. */
+ 0x00 /* Form Flag : None. */
+};
+#define DEVICE_PROP_SYNCHRONIZATION_PARTNER_DATASET_LENGTH sizeof(pima_device_prop_synchronization_partner_dataset) /* 8 */
+
+/* Device property dataset. Here we give the example of the device friendly name dataset. */
+UCHAR pima_device_prop_device_friendly_name_dataset[] = {
+
+ /* Device prop code : Device Friendly Name. */
+ 0x02, 0xD4, /* Prop code */
+ 0xff, 0xff, /* String */
+ 0x01, /* GET/SET */
+ 0x0E, /* Default value. Length of Unicode string. */
+ 0x45, 0x00, 0x4C, 0x00, 0x20, 0x00, 0x4D, 0x00, /* Unicode string. */
+ 0x54, 0x00, 0x50, 0x00, 0x20, 0x00, 0x44, 0x00,
+ 0x65, 0x00, 0x76, 0x00, 0x69, 0x00, 0x63, 0x00,
+ 0x65, 0x00,
+ 0x00, 0x00, /* Unicode terminator. */
+ 0x0E, /* Current value. Length of Unicode string. */
+ 0x45, 0x00, 0x4C, 0x00, 0x20, 0x00, 0x4D, 0x00,
+ 0x54, 0x00, 0x50, 0x00, 0x20, 0x00, 0x44, 0x00,
+ 0x65, 0x00, 0x76, 0x00, 0x69, 0x00, 0x63, 0x00, /* Unicode terminator. */
+ 0x65, 0x00,
+ 0x00, 0x00, /* Unicode terminator. */
+ 0x00 /* Form Flag : None. */
+};
+#define DEVICE_PROP_DEVICE_FRIENDLY_NAME_DATASET_LENGTH sizeof(pima_device_prop_device_friendly_name_dataset) /* 64 */
+
+/* Object property supported.
+ WORD 0 : Object Format Code
+ WORD 1 : Number of Prop codes for this Object format
+ WORD n : Prop Codes
+ WORD n+2 : Next Object Format code ....
+
+ This array is in whatever endinaness of the system and will be translated
+ by the PTP class in little endian.
+
+*/
+USHORT pima_device_object_prop_supported[] = {
+
+ /* Object format code : Undefined. */
+ UX_DEVICE_CLASS_PIMA_OFC_UNDEFINED,
+
+ /* NUmber of objects supported for this format. */
+ 9,
+ /* Mandatory objects for all formats. */
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_STORAGEID,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FORMAT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PROTECTION_STATUS,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_SIZE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FILE_NAME,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PARENT_OBJECT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NAME,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NON_CONSUMABLE,
+
+ /* Object format code : Association. */
+ UX_DEVICE_CLASS_PIMA_OFC_ASSOCIATION,
+
+ /* NUmber of objects supported for this format. */
+ 9,
+ /* Mandatory objects for all formats. */
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_STORAGEID,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FORMAT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PROTECTION_STATUS,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_SIZE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FILE_NAME,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PARENT_OBJECT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NAME,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NON_CONSUMABLE,
+
+ /* Object format code : Advanced System Format. */
+ UX_DEVICE_CLASS_PIMA_OFC_ASF,
+
+ /* NUmber of objects supported for this format. */
+ 9,
+ /* Mandatory objects for all formats. */
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_STORAGEID,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FORMAT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PROTECTION_STATUS,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_SIZE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FILE_NAME,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PARENT_OBJECT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NAME,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NON_CONSUMABLE,
+
+ /* Object format code : Audio Clip. */
+ UX_DEVICE_CLASS_PIMA_OFC_MP3,
+
+ /* NUmber of objects supported for this format. */
+ 20,
+ /* Mandatory objects for all formats. */
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_STORAGEID,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FORMAT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PROTECTION_STATUS,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_SIZE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FILE_NAME,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PARENT_OBJECT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NAME,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NON_CONSUMABLE,
+
+ /* Mandatory objects for all audio objects. */
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ARTIST,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_TRACK,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_DATE_AUTHORED,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_GENRE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_USE_COUNT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ALBUM_NAME,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ALBUM_ARTIST,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_SAMPLE_RATE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NUMBER_OF_CHANNELS,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_AUDIO_WAVE_CODEC,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_AUDIO_BITRATE,
+
+ /* Object format code : Windows Media Audio Clip. */
+ UX_DEVICE_CLASS_PIMA_OFC_WMA,
+
+ /* NUmber of objects supported for this format. */
+ 20,
+ /* Mandatory objects for all formats. */
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_STORAGEID,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FORMAT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PROTECTION_STATUS,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_SIZE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FILE_NAME,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PARENT_OBJECT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NAME,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NON_CONSUMABLE,
+
+ /* Mandatory objects for all audio objects. */
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ARTIST,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_TRACK,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_DATE_AUTHORED,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_GENRE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_USE_COUNT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ALBUM_NAME,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ALBUM_ARTIST,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_SAMPLE_RATE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NUMBER_OF_CHANNELS,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_AUDIO_WAVE_CODEC,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_AUDIO_BITRATE,
+
+ /* Object format code : Windows Media Video. */
+ UX_DEVICE_CLASS_PIMA_OFC_WMV,
+
+ /* NUmber of objects supported for this format. */
+ 24,
+ /* Mandatory objects for all formats. */
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_STORAGEID,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FORMAT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PROTECTION_STATUS,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_SIZE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FILE_NAME,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PARENT_OBJECT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NAME,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NON_CONSUMABLE,
+
+ /* Mandatory objects for all video objects. */
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_WIDTH,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_HEIGHT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_DATE_AUTHORED,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_GENRE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_USE_COUNT,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_SAMPLE_RATE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NUMBER_OF_CHANNELS,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_SCAN_TYPE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_AUDIO_WAVE_CODEC,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_AUDIO_BITRATE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_VIDEO_FOURCC_CODEC,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_VIDEO_BITRATE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_FRAMES_PER_THOUSAND_SECONDS,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_KEYFRAME_DISTANCE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ENCODING_PROFILE,
+
+ /* Object format code : Abstract Audio Album. */
+ UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_AUDIO_ALBUM,
+ 2,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_GENRE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ALBUM_ARTIST,
+
+ /* Object format code : Abstract Audio and Video Playlist. */
+ UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_AUDIO_AND_VIDEO_PLAYLIST,
+ 2,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_GENRE,
+ UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ALBUM_ARTIST,
+
+ 0
+};
+
+/* PIMA MTP names ... */
+UCHAR pima_device_info_vendor_name[] = "Microsoft AzureRTOS";
+UCHAR pima_device_info_product_name[] = "AzureRTOS MTP Device";
+UCHAR pima_device_info_serial_no[] = "1.1.1.1";
+UCHAR pima_device_info_version[] = "V1.0";
+
+/* PIMA MTP storage names. */
+UCHAR pima_parameter_volume_description[] = "MTP Client Storage Volume";
+UCHAR pima_parameter_volume_label[] = "MTP Client Storage Label";
+
+/* Array of handles for the demo. */
+ULONG pima_device_object_number_handles;
+ULONG pima_device_object_number_handles_array[UX_TEST_MAX_HANDLES];
+UX_SLAVE_CLASS_PIMA_OBJECT pima_device_object_info_array[UX_TEST_MAX_HANDLES];
+FX_FILE pima_device_object_filex_array[UX_TEST_MAX_HANDLES];
+TEST_PIMA_PROP_DATASET pima_device_object_property_array[UX_TEST_MAX_HANDLES];
+
+/* Local storage for one Object property. This is a temporary storage to create
+ the demanded dataset. The size of the dataset depends on the type and number of object properties. */
+UCHAR pima_device_object_property_dataset_data_buffer [UX_TEST_MAX_DATASET_SIZE];
+
+/* This is a 128 bit unique identifier. For the demo we make it 32 bits only as it is easier to manipulate. */
+ULONG pima_device_object_persistent_unique_identifier = 1;
+
+
+/* Prototype for test control return. */
+
+void test_control_return(UINT status);
+
+static VOID error_callback(UINT system_level, UINT system_context, UINT error_code)
+{
+
+ error_callback_counter ++;
+
+ if (!error_callback_ignore)
+ {
+ {
+ /* Failed test. */
+ printf("Error #%d, system_level: %d, system_context: %d, error_code: 0x%x\n", __LINE__, system_level, system_context, error_code);
+ test_control_return(1);
+ }
+ }
+}
+
+static UINT sleep_break_on_error(VOID)
+{
+
+ if (error_callback_counter >= 3)
+ return error_callback_counter;
+
+ return UX_SUCCESS;
+}
+
+/* Define the ISR dispatch routine. */
+
+static void test_isr(void)
+{
+
+ /* For further expansion of interrupt-level testing. */
+}
+
+
+
+static UINT test_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst)
+{
+ // printf("hChg:%lx, %p, %p\n", event, cls, inst);
+ switch(event)
+ {
+ case UX_DEVICE_INSERTION:
+ if (cls->ux_host_class_entry_function == ux_host_class_pima_entry)
+ {
+ pima_host = (UX_HOST_CLASS_PIMA *)inst;
+ }
+ break;
+
+ case UX_DEVICE_REMOVAL:
+ if (cls->ux_host_class_entry_function == ux_host_class_pima_entry)
+ {
+ if ((VOID*)pima_host == inst)
+ pima_host = UX_NULL;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+static VOID test_pima_instance_activate(VOID *instance)
+{
+ pima_device = (UX_SLAVE_CLASS_PIMA *)instance;
+}
+static VOID test_pima_instance_deactivate(VOID *instance)
+{
+ if ((VOID *)pima_device == instance)
+ pima_device = UX_NULL;
+}
+
+
+/* Define what the initial system looks like. */
+
+#ifdef CTEST
+void test_application_define(void *first_unused_memory)
+#else
+void usbx_ghsa_2ch9_pima_obj_handles_bound_test_application_define(void *first_unused_memory)
+#endif
+{
+
+UINT status;
+CHAR * stack_pointer;
+CHAR * memory_pointer;
+ULONG test_n;
+
+ /* Inform user. */
+ printf("Running GHSA 2ch9 PIMA obj handles bound Test...................... ");
+
+ /* Reset testing counts. */
+ ux_test_utility_sim_mutex_create_count_reset();
+ ux_test_utility_sim_sem_create_count_reset();
+ ux_test_utility_sim_sem_get_count_reset();
+ /* Reset error generations */
+ ux_test_utility_sim_sem_error_generation_stop();
+ ux_test_utility_sim_mutex_error_generation_stop();
+ ux_test_utility_sim_sem_get_error_generation_stop();
+
+ ux_utility_memory_set(ram_disk_memory, 0, UX_TEST_RAM_DISK_SIZE);
+ fx_system_initialize();
+ status = fx_media_format(&ram_disk, _fx_ram_driver, ram_disk_memory, ram_disk_buffer, 512, "RAM DISK", 2, 512, 0, (UX_TEST_RAM_DISK_SIZE / 512), 512, 4, 1, 1);
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d\n", __LINE__);
+ test_control_return(1);
+ }
+ status = fx_media_open(&ram_disk, "RAM DISK", _fx_ram_driver, ram_disk_memory, ram_disk_buffer, 512);
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d\n", __LINE__);
+ test_control_return(1);
+ }
+
+ /* Initialize the free memory pointer */
+ stack_pointer = (CHAR *) usbx_memory;
+ memory_pointer = stack_pointer + (UX_TEST_STACK_SIZE * 2);
+
+ /* Initialize USBX Memory */
+ status = ux_system_initialize(memory_pointer, UX_TEST_MEMORY_SIZE, UX_NULL,0);
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d\n", __LINE__);
+ test_control_return(1);
+ }
+
+ /* Register the error callback. */
+ _ux_utility_error_callback_register(error_callback);
+
+ /* The code below is required for installing the host portion of USBX */
+ status = ux_host_stack_initialize(test_system_host_change_function);
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d\n", __LINE__);
+ test_control_return(1);
+ }
+
+ /* Register PIMA class. */
+ status = ux_host_stack_class_register(_ux_system_host_class_pima_name, ux_host_class_pima_entry);
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d\n", __LINE__);
+ test_control_return(1);
+ }
+
+ /* The code below is required for installing the device portion of USBX. No call back for
+ device status change in this example. */
+ status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED,
+ device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED,
+ string_framework, STRING_FRAMEWORK_LENGTH,
+ language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH,UX_NULL);
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d\n", __LINE__);
+ test_control_return(1);
+ }
+
+ /* MTP requires MTP extensions. */
+ status = ux_device_stack_microsoft_extension_register(UX_TEST_VENDOR_REQUEST, pima_device_vendor_request);
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d\n", __LINE__);
+ test_control_return(1);
+ }
+
+ /* Set the parameters for PIMA device. */
+ pima_device_parameter.ux_device_class_pima_instance_activate = test_pima_instance_activate;
+ pima_device_parameter.ux_device_class_pima_instance_deactivate = test_pima_instance_deactivate;
+
+ /* Initialize the pima device parameter. */
+ pima_device_parameter.ux_device_class_pima_parameter_manufacturer = pima_device_info_vendor_name;
+ pima_device_parameter.ux_device_class_pima_parameter_model = pima_device_info_product_name;
+ pima_device_parameter.ux_device_class_pima_parameter_device_version = pima_device_info_version;
+ pima_device_parameter.ux_device_class_pima_parameter_serial_number = pima_device_info_serial_no;
+ pima_device_parameter.ux_device_class_pima_parameter_storage_id = UX_TEST_PIMA_STORAGE_ID;
+ pima_device_parameter.ux_device_class_pima_parameter_storage_type = UX_DEVICE_CLASS_PIMA_STC_FIXED_RAM;
+ pima_device_parameter.ux_device_class_pima_parameter_storage_file_system_type = UX_DEVICE_CLASS_PIMA_FSTC_GENERIC_FLAT;
+ pima_device_parameter.ux_device_class_pima_parameter_storage_access_capability = UX_DEVICE_CLASS_PIMA_AC_READ_WRITE;
+ pima_device_parameter.ux_device_class_pima_parameter_storage_max_capacity_low = ram_disk.fx_media_total_clusters * ram_disk.fx_media_sectors_per_cluster * ram_disk.fx_media_bytes_per_sector;
+ pima_device_parameter.ux_device_class_pima_parameter_storage_max_capacity_high = 0;
+ pima_device_parameter.ux_device_class_pima_parameter_storage_free_space_low = ram_disk.fx_media_available_clusters * ram_disk.fx_media_sectors_per_cluster * ram_disk.fx_media_bytes_per_sector;
+ pima_device_parameter.ux_device_class_pima_parameter_storage_free_space_high = 0;
+ pima_device_parameter.ux_device_class_pima_parameter_storage_free_space_image = 0xFFFFFFFF;
+ pima_device_parameter.ux_device_class_pima_parameter_storage_description = pima_parameter_volume_description;
+ pima_device_parameter.ux_device_class_pima_parameter_storage_volume_label = pima_parameter_volume_label;
+ pima_device_parameter.ux_device_class_pima_parameter_device_properties_list = pima_device_prop_supported;
+ pima_device_parameter.ux_device_class_pima_parameter_supported_capture_formats_list= pima_device_supported_capture_formats;
+ pima_device_parameter.ux_device_class_pima_parameter_supported_image_formats_list = pima_device_supported_image_formats;
+ pima_device_parameter.ux_device_class_pima_parameter_object_properties_list = pima_device_object_prop_supported;
+
+ /* Define the callbacks. */
+ pima_device_parameter.ux_device_class_pima_parameter_device_reset = pima_device_device_reset;
+ pima_device_parameter.ux_device_class_pima_parameter_device_prop_desc_get = pima_device_device_prop_desc_get;
+ pima_device_parameter.ux_device_class_pima_parameter_device_prop_value_get = pima_device_device_prop_value_get;
+ pima_device_parameter.ux_device_class_pima_parameter_device_prop_value_set = pima_device_device_prop_value_set;
+ pima_device_parameter.ux_device_class_pima_parameter_storage_format = pima_device_storage_format;
+ pima_device_parameter.ux_device_class_pima_parameter_storage_info_get = pima_device_storage_info_get;
+ pima_device_parameter.ux_device_class_pima_parameter_object_number_get = pima_device_object_number_get;
+ pima_device_parameter.ux_device_class_pima_parameter_object_handles_get = pima_device_object_handles_get;
+ pima_device_parameter.ux_device_class_pima_parameter_object_info_get = pima_device_object_info_get;
+ pima_device_parameter.ux_device_class_pima_parameter_object_data_get = pima_device_object_data_get;
+ pima_device_parameter.ux_device_class_pima_parameter_object_info_send = pima_device_object_info_send;
+ pima_device_parameter.ux_device_class_pima_parameter_object_data_send = pima_device_object_data_send;
+ pima_device_parameter.ux_device_class_pima_parameter_object_delete = pima_device_object_delete;
+ pima_device_parameter.ux_device_class_pima_parameter_object_prop_desc_get = pima_device_object_prop_desc_get;
+ pima_device_parameter.ux_device_class_pima_parameter_object_prop_value_get = pima_device_object_prop_value_get;
+ pima_device_parameter.ux_device_class_pima_parameter_object_prop_value_set = pima_device_object_prop_value_set;
+ pima_device_parameter.ux_device_class_pima_parameter_object_references_get = pima_device_object_references_get;
+ pima_device_parameter.ux_device_class_pima_parameter_object_references_set = pima_device_object_references_set;
+
+ /* Store the instance owner. */
+ pima_device_parameter.ux_device_class_pima_parameter_application = (VOID *) 0;
+
+ /* Initialize the device PIMA class. */
+ status = ux_device_stack_class_register(_ux_system_slave_class_pima_name, ux_device_class_pima_entry,
+ 1, 0, &pima_device_parameter);
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d\n", __LINE__);
+ test_control_return(1);
+ }
+
+ /* Initialize the simulated device controller. */
+ status = _ux_dcd_sim_slave_initialize();
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d\n", __LINE__);
+ test_control_return(1);
+ }
+
+ /* Register all the USB host controllers available in this system */
+ status = ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize,0,0);
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d\n", __LINE__);
+ test_control_return(1);
+ }
+
+ /* Create the main host simulation thread. */
+ status = tx_thread_create(&test_thread_host_simulation, "tx demo host simulation", test_thread_host_simulation_entry, 0,
+ stack_pointer, UX_TEST_STACK_SIZE,
+ 20, 20, 1, TX_AUTO_START);
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d\n", __LINE__);
+ test_control_return(1);
+ }
+
+ /* Create the main slave simulation thread. */
+ status = tx_thread_create(&test_thread_device_simulation, "tx demo device simulation", test_thread_device_simulation_entry, 0,
+ stack_pointer + UX_TEST_STACK_SIZE, UX_TEST_STACK_SIZE,
+ 20, 20, 1, TX_AUTO_START);
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d\n", __LINE__);
+ test_control_return(1);
+ }
+}
+
+static TX_THREAD replace_pima_cmd_thread;
+static UCHAR replace_pima_cmd_thread_stack[UX_TEST_STACK_SIZE];
+static TX_SEMAPHORE replace_pima_cmd_semaphore;
+static ULONG replace_pima_obj_n = 0;
+static ULONG replace_pima_container_l = UX_DEVICE_CLASS_PIMA_DATA_HEADER_SIZE;
+
+/* Send a GetObjectHandles data container that declares one handle count while
+ carrying another. The container is sized from what it carries, never from what it
+ declares, because the attack is precisely a count larger than the bytes the host
+ asked for and sized its receive buffer to hold. */
+static void test_pima_object_handles_send_declaring(UX_SLAVE_CLASS_PIMA *pima,
+ ULONG declared, ULONG carried)
+{
+UX_SLAVE_ENDPOINT *endpoint = pima -> ux_device_class_pima_bulk_in_endpoint;
+UX_SLAVE_TRANSFER *transfer = &endpoint -> ux_slave_endpoint_transfer_request;
+UCHAR *buffer = transfer -> ux_slave_transfer_request_data_pointer;
+ULONG *array;
+ULONG i;
+ULONG container_length;
+
+ container_length = UX_DEVICE_CLASS_PIMA_DATA_HEADER_SIZE + 4 + (carried * 4);
+
+ _ux_utility_short_put(buffer + UX_DEVICE_CLASS_PIMA_DATA_HEADER_TYPE,
+ UX_DEVICE_CLASS_PIMA_CT_DATA_BLOCK);
+ _ux_utility_short_put(buffer + UX_DEVICE_CLASS_PIMA_DATA_HEADER_CODE,
+ UX_DEVICE_CLASS_PIMA_OC_GET_OBJECT_HANDLES);
+ _ux_utility_long_put(buffer + UX_DEVICE_CLASS_PIMA_DATA_HEADER_TRANSACTION_ID,
+ pima -> ux_device_class_pima_transaction_id);
+
+ /* The count the host will believe, followed by however many handles are really
+ there. */
+ array = (ULONG*)(buffer + UX_DEVICE_CLASS_PIMA_DATA_HEADER_SIZE);
+ _ux_utility_long_put((UCHAR*)array, declared);
+ array ++;
+ for (i = 0; i < carried; i ++)
+ array[i] = i;
+
+ _ux_utility_long_put(buffer + UX_DEVICE_CLASS_PIMA_DATA_HEADER_LENGTH,
+ container_length);
+
+ _ux_device_stack_transfer_request(transfer, container_length, 0);
+ _ux_device_class_pima_response_send(pima, UX_DEVICE_CLASS_PIMA_RC_OK, 0, 0, 0, 0);
+}
+
+void replace_pima_cmd_thread_entry(ULONG arg)
+{
+ while(1)
+ {
+ tx_semaphore_get(&replace_pima_cmd_semaphore, TX_WAIT_FOREVER);
+ test_pima_object_handles_send_declaring(pima_device, replace_pima_obj_n, replace_pima_container_l);
+ }
+}
+
+static VOID ux_test_pima_command(UX_TEST_ACTION *action, VOID *params)
+{
+ tx_semaphore_put(&replace_pima_cmd_semaphore);
+ tx_semaphore_put(&pima_host -> ux_host_class_pima_bulk_out_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_semaphore);
+}
+
+static UX_TEST_HCD_SIM_ACTION replace_bulk_out_transfer[] = {
+/* function, request to match,
+ port action, port status,
+ request action, request EP, request data, request actual length, request status,
+ status, additional callback,
+ no_return */
+{ UX_HCD_TRANSFER_REQUEST, UX_NULL,
+ UX_FALSE, 0,
+ UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, 0,
+ UX_SUCCESS, ux_test_pima_command,
+ UX_FALSE},
+{ 0 }
+};
+
+#define UX_TEST_CALLER_ARRAY 64
+
+/* Free bytes across both pools. The receive buffer is cache safe memory, which some
+ configurations back with the regular pool, so both are counted and a shared pool is
+ simply counted twice on each side of the comparison. */
+static ULONG test_free_memory(void)
+{
+ return(_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available +
+ _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available);
+}
+
+/* The receive buffer holds one ULONG for the count plus one per object the session
+ knows about, so the session count is also the number of handles the buffer can
+ hold. Restore it before each hooked case so every case starts from the same
+ buffer size, then ask the device for the handles. */
+static UINT test_handles_get_declaring(ULONG capacity, ULONG declared)
+{
+
+ pima_host_session.ux_host_class_pima_session_nb_objects = capacity;
+ replace_pima_obj_n = declared;
+ replace_pima_container_l = capacity;
+
+ /* Re-arm: a matched action is spent, and every case needs its own response. */
+ ux_test_hcd_sim_host_set_actions(replace_bulk_out_transfer);
+
+ return(ux_host_class_pima_object_handles_get(pima_host, &pima_host_session, host_buffer32,
+ UX_TEST_CALLER_ARRAY, 0, UX_HOST_CLASS_PIMA_OFC_UNDEFINED, 0));
+}
+
+static void test_ghsa_2ch9_cases(void)
+{
+UINT status;
+ULONG capacity;
+ULONG free_before;
+ULONG free_after;
+
+ status = ux_host_class_pima_device_info_get(pima_host, &pima_host_device);
+ UX_TEST_CHECK_SUCCESS(status);
+
+ status = ux_host_class_pima_session_open(pima_host, &pima_host_session);
+ UX_TEST_CHECK_SUCCESS(status);
+
+ status = ux_host_class_pima_storage_ids_get(pima_host, &pima_host_session, host_buffer32, 64);
+ UX_TEST_CHECK_SUCCESS(status);
+
+ /* Let the real device establish the object count, then read the handles from it.
+ The device returns exactly as many handles as the buffer was sized for, which is
+ the boundary the new check has to admit. */
+ status = ux_host_class_pima_num_objects_get(pima_host, &pima_host_session, 0, UX_HOST_CLASS_PIMA_OFC_UNDEFINED);
+ UX_TEST_CHECK_SUCCESS(status);
+
+ capacity = pima_host_session.ux_host_class_pima_session_nb_objects;
+
+ status = ux_host_class_pima_object_handles_get(pima_host, &pima_host_session, host_buffer32,
+ UX_TEST_CALLER_ARRAY, 0, UX_HOST_CLASS_PIMA_OFC_UNDEFINED, 0);
+ UX_TEST_CHECK_SUCCESS(status);
+
+ /* Hook the device side so the declared handle count is set independently of the
+ handles actually sent. */
+ tx_semaphore_create(&replace_pima_cmd_semaphore, "cmd_sem", 0);
+ tx_thread_create(&replace_pima_cmd_thread, "cmd_thr, ", replace_pima_cmd_thread_entry, 0,
+ replace_pima_cmd_thread_stack, UX_TEST_STACK_SIZE,
+ 20, 20, 1, TX_AUTO_START);
+ ux_test_hcd_sim_host_set_actions(replace_bulk_out_transfer);
+
+ /* A device that declares exactly what its buffer holds is answered normally, at
+ both an empty and a populated session count. */
+ status = test_handles_get_declaring(0, 0);
+ UX_TEST_CHECK_SUCCESS(status);
+
+ status = test_handles_get_declaring(2, 2);
+ UX_TEST_CHECK_SUCCESS(status);
+
+ /* One handle past what the buffer holds is the smallest over-report, and the case
+ the caller side check never saw because the caller's array is larger. */
+ status = test_handles_get_declaring(2, 3);
+ UX_TEST_CHECK_NOT_SUCCESS(status);
+
+ /* An empty session buys a four byte buffer holding no handles at all, so any
+ handle the device claims is one too many. */
+ status = test_handles_get_declaring(0, 1);
+ UX_TEST_CHECK_NOT_SUCCESS(status);
+
+ /* A count that still fits the caller's array but far outruns the buffer. Before
+ the fix this unpacked sixteen ULONGs out of a twelve byte allocation. */
+ status = test_handles_get_declaring(2, 16);
+ UX_TEST_CHECK_NOT_SUCCESS(status);
+
+ /* A count filling the caller's array exactly, which the caller side check also
+ admits, while the buffer still holds only what the session knew about. */
+ status = test_handles_get_declaring(2, UX_TEST_CALLER_ARRAY);
+ UX_TEST_CHECK_NOT_SUCCESS(status);
+
+ /* The session count survives a refusal, so a later call still sizes its buffer
+ from a count the host established rather than one the device asserted. */
+ if (pima_host_session.ux_host_class_pima_session_nb_objects != 2)
+ {
+ printf("ERROR #%d: session count %lu after refusal, expected 2\n", __LINE__,
+ pima_host_session.ux_host_class_pima_session_nb_objects);
+ test_control_return(1);
+ }
+
+ /* A refused response must not keep the receive buffer. A device repeating the
+ request would otherwise drain the pool one buffer at a time. */
+ free_before = test_free_memory();
+ status = test_handles_get_declaring(2, 16);
+ UX_TEST_CHECK_NOT_SUCCESS(status);
+ free_after = test_free_memory();
+ if (free_before != free_after)
+ {
+ printf("ERROR #%d: leaked %lu bytes\n", __LINE__, free_before - free_after);
+ test_control_return(1);
+ }
+
+ /* Back to the real device, to show the refusals left the session usable. */
+ ux_test_hcd_sim_host_set_actions(UX_NULL);
+ pima_host_session.ux_host_class_pima_session_nb_objects = capacity;
+ status = ux_host_class_pima_object_handles_get(pima_host, &pima_host_session, host_buffer32,
+ UX_TEST_CALLER_ARRAY, 0, UX_HOST_CLASS_PIMA_OFC_UNDEFINED, 0);
+ UX_TEST_CHECK_SUCCESS(status);
+
+ status = ux_host_class_pima_session_close(pima_host, &pima_host_session);
+ UX_TEST_CHECK_SUCCESS(status);
+}
+
+void test_thread_host_simulation_entry(ULONG arg)
+{
+
+UINT status;
+INT i;
+
+ for (i = 0; i < 100; i ++)
+ {
+ if (pima_host && pima_device)
+ break;
+ ux_utility_delay_ms(1);
+ }
+ if (pima_host == UX_NULL || pima_device == UX_NULL)
+ {
+ printf("ERROR #%d\n", __LINE__);
+ test_control_return(1);
+ }
+
+ test_ghsa_2ch9_cases();
+
+ stepinfo(">>>>>>>>>>>> All Done\n");
+
+ /* Finally disconnect the device. */
+ ux_device_stack_disconnect();
+
+ /* And deinitialize the class. */
+ status = ux_device_stack_class_unregister(_ux_system_slave_class_pima_name, ux_device_class_pima_entry);
+
+ /* Deinitialize the device side of usbx. */
+ _ux_device_stack_uninitialize();
+
+ /* And finally the usbx system resources. */
+ _ux_system_uninitialize();
+
+ /* Successful test. */
+ printf("SUCCESS!\n");
+ test_control_return(0);
+
+}
+
+
+void test_thread_device_simulation_entry(ULONG arg)
+{
+
+UINT status;
+
+ while(1)
+ {
+
+ /* Sleep so ThreadX on Win32 will delete this thread. */
+ tx_thread_sleep(10);
+ }
+}
+
+
+UINT pima_device_vendor_request(ULONG request, ULONG request_value, ULONG request_index, ULONG request_length,
+ UCHAR *transfer_request_buffer,
+ ULONG *transfer_request_length)
+{
+UINT status;
+ULONG length;
+
+ /* Do some sanity check. The request must be our vendor request. */
+ if (request != UX_TEST_VENDOR_REQUEST)
+
+ /* Do not proceed. */
+ return(UX_ERROR);
+
+ /* Check the wIndex value. Values can be :
+ 0x0001 : Genre
+ 0x0004 : Extended compatible ID
+ 0x0005 : Extended properties */
+ switch (request_index)
+ {
+
+ case 0x0001 :
+
+ /* Not sure what this is for. Windows does not seem to request this. Drop it. */
+ status = UX_ERROR;
+ break;
+
+ case 0x0004 :
+ case 0x0005 :
+
+ /* Length to return. */
+ length = UX_MIN(0x28, request_length);
+
+ /* Length check. */
+ UX_ASSERT(*transfer_request_length >= length);
+
+ /* At least length should be returned. */
+ if (length < 4)
+ {
+ status = UX_ERROR;
+ break;
+ }
+ status = UX_SUCCESS;
+
+ /* Return the length. */
+ *transfer_request_length = length;
+
+ /* Reset returned bytes. */
+ ux_utility_memory_set(transfer_request_buffer, 0, length);
+
+ /* Build the descriptor to be returned. This is not a composite descriptor. Single MTP.
+ First dword is length of the descriptor. */
+ ux_utility_long_put(transfer_request_buffer, 0x0028);
+ length -= 4;
+
+ /* Then the version. fixed to 0x0100. */
+ if (length < 2)
+ break;
+ ux_utility_short_put(transfer_request_buffer + 4, 0x0100);
+ length -= 2;
+
+ /* Then the descriptor ID. Fixed to 0x0004. */
+ if (length < 2)
+ break;
+ ux_utility_short_put(transfer_request_buffer + 6, 0x0004);
+ length -= 2;
+
+ /* Then the bcount field. Fixed to 0x0001. */
+ if (length < 1)
+ break;
+ *(transfer_request_buffer + 8) = 0x01;
+ length -= 1;
+
+ /* Reset the next 7 bytes. */
+ if (length < 7)
+ break;
+ ux_utility_memory_set(transfer_request_buffer + 9, 0x00, 7);
+ length -= 7;
+
+ /* Last byte of header is the interface number, here 0. */
+ if (length < 1)
+ break;
+ *(transfer_request_buffer + 16) = 0x00;
+ length -= 1;
+
+ /* First byte of descriptor is set to 1. */
+ if (length < 1)
+ break;
+ *(transfer_request_buffer + 17) = 0x01;
+ length -= 1;
+
+ /* Reset the next 8 + 8 + 6 bytes. */
+ if (length < (8+8+6))
+ break;
+ ux_utility_memory_set(transfer_request_buffer + 18, 0x00, (8 + 8 + 6));
+ length -= 8+8+6;
+
+ /* Set the compatible ID to MTP. */
+ if (length < 3)
+ break;
+ ux_utility_memory_copy(transfer_request_buffer + 18, "MTP", 3);
+ length -= 3;
+
+ /* We are done here. */
+ status = UX_SUCCESS;
+ break;
+
+ default :
+ status = UX_ERROR;
+ break;
+
+ }
+ /* Return status to device stack. */
+ return(status);
+}
+
+UINT pima_device_device_reset()
+{
+
+ /* Do nothing here. Return Success. */
+ return(UX_SUCCESS);
+
+}
+
+UINT pima_device_device_prop_desc_get(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG device_property,
+ UCHAR **device_prop_dataset,
+ ULONG *device_prop_dataset_length)
+
+{
+UINT status;
+
+ /* We assume the worst. */
+ status = UX_DEVICE_CLASS_PIMA_RC_DEVICE_PROP_NOT_SUPPORTED;
+
+ /* Check which device property the host is inquiring. It needs
+ to be one that we have declared. */
+ switch (device_property)
+ {
+
+ case UX_DEVICE_CLASS_PIMA_DEV_PROP_DATE_TIME :
+
+ /* Buffer length validation. */
+ UX_ASSERT(*device_prop_dataset_length >= DEVICE_PROP_DATE_TIME_DATASET_LENGTH);
+
+ /* The host is inquiring about the date/time dataset. */
+ *device_prop_dataset = pima_device_prop_date_time_dataset;
+ *device_prop_dataset_length = DEVICE_PROP_DATE_TIME_DATASET_LENGTH;
+
+ /* We have a successful operation. */
+ status = UX_SUCCESS;
+
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_DEV_PROP_SYNCHRONIZATION_PARTNER :
+
+ /* Buffer length validation. */
+ UX_ASSERT(*device_prop_dataset_length >= DEVICE_PROP_SYNCHRONIZATION_PARTNER_DATASET_LENGTH);
+
+ /* The host is inquiring about the synchronization partner dataset. */
+ *device_prop_dataset = pima_device_prop_synchronization_partner_dataset;
+ *device_prop_dataset_length = DEVICE_PROP_SYNCHRONIZATION_PARTNER_DATASET_LENGTH;
+
+ /* We have a successful operation. */
+ status = UX_SUCCESS;
+
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_DEV_PROP_DEVICE_FRIENDLY_NAME :
+
+ /* Buffer length validation. */
+ UX_ASSERT(*device_prop_dataset_length >= DEVICE_PROP_DEVICE_FRIENDLY_NAME_DATASET_LENGTH);
+
+ /* The host is inquiring about the device friendly name dataset. */
+ *device_prop_dataset = pima_device_prop_device_friendly_name_dataset;
+ *device_prop_dataset_length = DEVICE_PROP_DEVICE_FRIENDLY_NAME_DATASET_LENGTH;
+
+ /* We have a successful operation. */
+ status = UX_SUCCESS;
+
+ break;
+
+ default :
+
+ /* We get here when the Initiator inquires about a property we don't know about.
+ That should never happen as the properties are declared to the initiator. */
+ status = UX_DEVICE_CLASS_PIMA_RC_DEVICE_PROP_NOT_SUPPORTED;
+
+ break;
+ }
+
+ /* Return what we found. */
+ return(status);
+
+}
+
+UINT pima_device_device_prop_value_get(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG device_property,
+ UCHAR **device_prop_value,
+ ULONG *device_prop_value_length)
+{
+
+UINT status;
+
+ /* We assume the worst. */
+ status = UX_DEVICE_CLASS_PIMA_RC_DEVICE_PROP_NOT_SUPPORTED;
+
+ /* Check which device property the host is inquiring. It needs
+ to be one that we have declared. */
+ switch (device_property)
+ {
+
+ case UX_DEVICE_CLASS_PIMA_DEV_PROP_DATE_TIME :
+
+ /* Buffer length validation. */
+ UX_ASSERT(*device_prop_value_length >= 33);
+
+ /* The host is inquiring about the date/time value. */
+ *device_prop_value = pima_device_prop_date_time_dataset + 6;
+ *device_prop_value_length = 33;
+
+ /* We have a successful operation. */
+ status = UX_SUCCESS;
+
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_DEV_PROP_SYNCHRONIZATION_PARTNER :
+
+ /* Buffer length validation. */
+ UX_ASSERT(*device_prop_value_length >= 1);
+
+ /* The host is inquiring about the synchronization name dataset. */
+ *device_prop_value = pima_device_prop_synchronization_partner_dataset + 6;
+ *device_prop_value_length = 1;
+
+ /* We have a successful operation. */
+ status = UX_SUCCESS;
+
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_DEV_PROP_DEVICE_FRIENDLY_NAME :
+
+ /* Buffer length validation. */
+ UX_ASSERT(*device_prop_value_length >= 29);
+
+ /* The host is inquiring about the device friendly name dataset. */
+ *device_prop_value = pima_device_prop_device_friendly_name_dataset + 6;
+ *device_prop_value_length = 29;
+
+ /* We have a successful operation. */
+ status = UX_SUCCESS;
+
+ break;
+
+ default :
+
+ /* We get here when the Initiator inquires about a property we don't know about.
+ That should never happen as the properties are declared to the initiator. */
+ status = UX_DEVICE_CLASS_PIMA_RC_DEVICE_PROP_NOT_SUPPORTED;
+
+ break;
+ }
+
+ /* Return what we found. */
+ return(status);
+
+}
+
+UINT pima_device_device_prop_value_set(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG device_property,
+ UCHAR *device_prop_value,
+ ULONG device_prop_value_length)
+{
+
+UINT status;
+
+ /* We assume the worst. */
+ status = UX_DEVICE_CLASS_PIMA_RC_DEVICE_PROP_NOT_SUPPORTED;
+
+ /* Check which device property the host wants to set. It needs
+ to be one that we have declared. */
+ switch (device_property)
+ {
+
+ case UX_DEVICE_CLASS_PIMA_DEV_PROP_DATE_TIME :
+
+ /* The host wants to set time and date value.
+ We only take the first 16 bytes of the Unicode string. */
+ ux_utility_memory_copy (pima_device_prop_date_time_dataset + 6, device_prop_value, 0x10);
+
+ /* We have a successful operation. */
+ status = UX_SUCCESS;
+
+ break;
+
+ }
+
+ /* Return what we found. */
+ return(status);
+
+
+}
+
+
+UINT pima_device_storage_format(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG storage_id)
+{
+
+UINT status;
+
+ /* Check the storage ID. */
+ if (storage_id == UX_TEST_PIMA_STORAGE_ID)
+ {
+
+ /* Format the ram drive. */
+ status = fx_media_format(&ram_disk, _fx_ram_driver, ram_disk_memory, ram_disk_buffer, 512, "RAM DISK", 2, 512, 0, UX_TEST_RAM_DISK_SIZE / 512, 512, 4, 1, 1);
+
+ /* Reset the handle counter. */
+ pima_device_object_number_handles = 0;
+
+ /* Is there an error ? */
+ if (status == UX_SUCCESS)
+
+ /* Success. */
+ return(status);
+
+ else
+
+ /* Error. */
+ return(UX_DEVICE_CLASS_PIMA_RC_ACCESS_DENIED);
+ }
+ else
+
+ /* Error, wrong storage ID. */
+ return(UX_DEVICE_CLASS_PIMA_RC_INVALID_STORAGE_ID);
+
+}
+
+
+UINT pima_device_storage_info_get(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG storage_id)
+{
+
+ /* Check the storage ID. */
+ if (storage_id == UX_TEST_PIMA_STORAGE_ID)
+ {
+
+ /* We come here when the Initiator needs to update the storage info dataset.
+ The PIMA structure has the storage info main dataset. This version only
+ support one storage container. */
+ pima -> ux_device_class_pima_storage_max_capacity_low = ram_disk.fx_media_total_clusters * ram_disk.fx_media_sectors_per_cluster * ram_disk.fx_media_bytes_per_sector;
+ pima -> ux_device_class_pima_storage_max_capacity_high = 0;
+ pima -> ux_device_class_pima_storage_free_space_low = ram_disk.fx_media_available_clusters * ram_disk.fx_media_sectors_per_cluster * ram_disk.fx_media_bytes_per_sector;
+ pima -> ux_device_class_pima_storage_free_space_high = 0;
+
+
+ /* Success. */
+ return( UX_SUCCESS);
+
+ }
+ else
+
+ /* Error, wrong storage ID. */
+ return(UX_DEVICE_CLASS_PIMA_RC_INVALID_STORAGE_ID);
+
+}
+
+UINT pima_device_object_number_get(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_format_code,
+ ULONG object_association,
+ ULONG *object_number)
+{
+
+ /* Return the object number. */
+ *object_number = pima_device_object_number_handles;
+
+ /* Return success. */
+ return(UX_SUCCESS);
+}
+
+UINT pima_device_object_handles_get (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handles_format_code,
+ ULONG object_handles_association,
+ ULONG *object_handles_array,
+ ULONG object_handles_max_number)
+{
+ULONG handle_index;
+ULONG number_handles;
+ULONG found_handles;
+ULONG *object_handles_array_pointer;
+
+ /* Number of max handles we can store in our demo. */
+ number_handles = UX_TEST_MAX_HANDLES;
+ if (number_handles > object_handles_max_number)
+ number_handles = object_handles_max_number;
+
+ /* We start with no handles found. */
+ found_handles = 0;
+
+ /* We store the handles in the array pointer, skipping the array count. */
+ object_handles_array_pointer = object_handles_array + 1;
+
+ /* Store all the handles we have in the media for the specific format code if utilized. */
+ for (handle_index = 0; handle_index < number_handles; handle_index++)
+ {
+
+ /* Check if this handle is valid. If 0, it may have been destroyed or unused yet. */
+ if (pima_device_object_number_handles_array[handle_index] != 0)
+ {
+
+ /* This handle is populated. Check the format code supplied by the app.
+ if 0 or -1, we discard the format code check. If not 0 or -1 check
+ it the stored object matches the format code. */
+ if ((object_handles_format_code == 0) || (object_handles_format_code == 0xFFFFFFFF) ||
+ pima_device_object_info_array[handle_index].ux_device_class_pima_object_format == object_handles_format_code)
+ {
+ /* We have a candidate. Store the handle. */
+ ux_utility_long_put((UCHAR *) object_handles_array_pointer, pima_device_object_number_handles_array[handle_index]);
+
+ /* Next array container. */
+ object_handles_array_pointer++;
+
+ /* We have found one handle more. */
+ found_handles++;
+
+ /* Check if we are reaching the max array of handles. */
+ if (found_handles == object_handles_max_number)
+ {
+
+ /* Array is saturated. Store what we have found. */
+ ux_utility_long_put((UCHAR *) object_handles_array, found_handles);
+
+ /* And return to the Pima class. */
+ return(UX_SUCCESS);
+
+ }
+ }
+ }
+
+ }
+
+ /* Array is populated. Store what we have found. */
+ ux_utility_long_put((UCHAR *) object_handles_array, found_handles);
+
+ /* And return to the Pima class. */
+ return(UX_SUCCESS);
+
+}
+
+UINT pima_device_object_info_get (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle,
+ UX_SLAVE_CLASS_PIMA_OBJECT **object)
+{
+UINT status;
+ULONG handle_index;
+
+ /* Check the object handle. It must be in the local array. */
+ status = pima_device_object_handle_check(object_handle, object, &handle_index);
+
+ /* Does the object handle exist ? */
+ if (status == UX_SUCCESS)
+ {
+
+ /* Yes, the handle is valid. The object pointer has been updated. */
+ return(UX_SUCCESS);
+ }
+ else
+
+ /* Done here. Return error. */
+ return(UX_DEVICE_CLASS_PIMA_RC_INVALID_OBJECT_HANDLE);
+
+}
+
+UINT pima_device_object_data_get (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle,
+ UCHAR *object_buffer,
+ ULONG object_offset,
+ ULONG object_length_requested,
+ ULONG *object_actual_length)
+
+{
+
+UINT status;
+UINT status_close;
+ULONG handle_index;
+UX_SLAVE_CLASS_PIMA_OBJECT *object;
+CHAR object_filename[64];
+
+
+ /* Check the object handle. It must be in the local array. */
+ status = pima_device_object_handle_check(object_handle, &object, &handle_index);
+
+ /* Does the object handle exist ? */
+ if (status != UX_SUCCESS)
+ return(status);
+
+ /* Check if entire file is read,
+ this could happen if last actual length equals to length requested. */
+ if (object_offset >= pima_device_object_filex_array[handle_index].fx_file_current_file_size)
+ {
+
+ /* Nothing to read. */
+ *object_actual_length = 0;
+ return(UX_SUCCESS);
+ }
+
+ /* We are either at the beginning of the transfer or continuing the transfer.
+ Check of the filex array handle exist already. */
+ if (pima_device_object_filex_array[handle_index].fx_file_id == 0)
+ {
+
+ /* The object file name is in Unicode, decrypt it first because FileX is not using
+ unicode format. */
+ _ux_utility_unicode_to_string(object -> ux_device_class_pima_object_filename, (UCHAR *) object_filename);
+
+ /* File not yet opened for this object. Open the file. */
+ status = fx_file_open(&ram_disk, &pima_device_object_filex_array[handle_index], (CHAR *) object_filename, FX_OPEN_FOR_READ);
+
+ /* Any problems with the opening ? */
+ if (status != UX_SUCCESS)
+ return(UX_DEVICE_CLASS_PIMA_RC_OBJECT_NOT_OPENED);
+
+ }
+
+ /* Seek to the offset of the object file. */
+ status = fx_file_seek(&pima_device_object_filex_array[handle_index], object_offset);
+ if (status != UX_SUCCESS)
+ return(UX_DEVICE_CLASS_PIMA_RC_INVALID_OBJECT_REFERENCE);
+
+ /* Read from the file into the media buffer. */
+ status = fx_file_read(&pima_device_object_filex_array[handle_index], object_buffer, object_length_requested, object_actual_length);
+
+ /* Check the status. */
+ if (status == UX_SUCCESS)
+
+ /* Done. Operation successful. */
+ status = UX_SUCCESS;
+
+ else
+ {
+
+ /* See what the error might be. */
+ switch (status)
+ {
+
+ case FX_MEDIA_NOT_OPEN :
+
+ /* Problem with media. */
+ status = UX_DEVICE_CLASS_PIMA_RC_STORE_NOT_AVAILABLE;
+ break;
+
+ case FX_NO_MORE_SPACE :
+
+ /* Media is full. */
+ status = UX_DEVICE_CLASS_PIMA_RC_STORE_FULL;
+ break;
+
+ default :
+ status = UX_DEVICE_CLASS_PIMA_RC_ACCESS_DENIED;
+ break;
+
+ }
+ }
+
+ /* Check if we have read the entire file. We compare the current position in the file with the file size. */
+ if (pima_device_object_filex_array[handle_index].fx_file_current_file_size == pima_device_object_filex_array[handle_index].fx_file_current_file_offset)
+ {
+
+ /* This is the end of the transfer for the object. Close it. */
+ status_close = fx_file_close(&pima_device_object_filex_array[handle_index]);
+
+ /* FX file id is not cleared by fx_file_close. */
+ pima_device_object_filex_array[handle_index].fx_file_id = 0;
+
+ /* Check the status. */
+ if (status_close == UX_SUCCESS && status == UX_SUCCESS)
+
+ /* Done. Operation successful. */
+ return (UX_SUCCESS);
+
+ else
+ {
+
+ /* See what the error might be. */
+ switch (status_close)
+ {
+
+ case FX_MEDIA_NOT_OPEN :
+
+ /* Problem with media. */
+ status_close = UX_DEVICE_CLASS_PIMA_RC_STORE_NOT_AVAILABLE;
+ break;
+
+ default :
+ status_close = UX_DEVICE_CLASS_PIMA_RC_ACCESS_DENIED;
+ break;
+
+ }
+
+ /* If status is error. we return status. If status_close is error we return status_close. */
+ if(status != UX_SUCCESS)
+
+ /* We return the status of read operation. */
+ return(status);
+
+ else
+
+ /* Return status from close operation. */
+ return(status_close);
+
+ }
+ }
+
+ /* Done here. Return status. */
+ return(status);
+}
+
+UINT pima_device_object_info_send (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ UX_SLAVE_CLASS_PIMA_OBJECT *object,
+ ULONG storage_id,
+ ULONG parent_object_handle,
+ ULONG *object_handle)
+{
+ULONG handle_index;
+CHAR object_filename[64];
+UINT status;
+
+ /* Make sure we can accommodate a new object here. */
+ if (pima_device_object_number_handles < UX_TEST_MAX_HANDLES)
+ {
+
+ /* The object file name is in Unicode, decrypt it first because FileX is not using
+ unicode format. */
+ ux_utility_unicode_to_string(object -> ux_device_class_pima_object_filename, (UCHAR *) object_filename);
+
+ /* The object can be either an association object (a directory) or a regular file such
+ a photo, music file, video file ... */
+ if (object -> ux_device_class_pima_object_format == UX_DEVICE_CLASS_PIMA_OFC_ASSOCIATION)
+ {
+
+ /* The object info refers to a association. We treat it as a folder. */
+ status = fx_directory_create(&ram_disk, object_filename);
+
+ /* Check status. If error, identify the problem and convert FileX error code into PIMA error code. */
+ if (status != UX_SUCCESS)
+ {
+
+ /* See what the error might be. */
+ switch (status)
+ {
+
+ case FX_MEDIA_NOT_OPEN :
+
+ /* Problem with media. */
+ status = UX_DEVICE_CLASS_PIMA_RC_STORE_NOT_AVAILABLE;
+ break;
+
+ case FX_NO_MORE_SPACE :
+
+ /* Media is full. */
+ status = UX_DEVICE_CLASS_PIMA_RC_STORE_FULL;
+ break;
+
+ case FX_WRITE_PROTECT :
+
+ /* Media is write protected. */
+ status = UX_DEVICE_CLASS_PIMA_RC_STORE_READ_ONLY;
+ break;
+
+ default :
+ status = UX_DEVICE_CLASS_PIMA_RC_ACCESS_DENIED;
+ break;
+
+ }
+
+ /* Could not create the object on the local media, return an error. */
+ return (status);
+ }
+ }
+ else
+ {
+ /* The format is for another object. */
+ /* Create the destination file. */
+ status = fx_file_create(&ram_disk, object_filename);
+
+ /* Check status. If error, identify the problem and convert FileX error code into PIMA error code. */
+ if (status != UX_SUCCESS)
+ {
+
+ /* See what the error might be. */
+ switch (status)
+ {
+
+ case FX_MEDIA_NOT_OPEN :
+
+ /* Problem with media. */
+ status = UX_DEVICE_CLASS_PIMA_RC_STORE_NOT_AVAILABLE;
+ break;
+
+ case FX_NO_MORE_SPACE :
+
+ /* Media is full. */
+ status = UX_DEVICE_CLASS_PIMA_RC_STORE_FULL;
+ break;
+
+ case FX_WRITE_PROTECT :
+
+ /* Media is write protected. */
+ status = UX_DEVICE_CLASS_PIMA_RC_STORE_READ_ONLY;
+ break;
+
+ default :
+ status = UX_DEVICE_CLASS_PIMA_RC_ACCESS_DENIED;
+ break;
+
+ }
+
+ /* Could not create the object on the local media, return an error. */
+ return (status);
+ }
+ }
+
+ /* The object is created. Store the object handle. Find a spot. */
+ for (handle_index = 0; handle_index < UX_TEST_MAX_HANDLES; handle_index++)
+ {
+
+ /* Check for an empty slot. */
+ if (pima_device_object_number_handles_array[handle_index] == 0)
+ {
+
+ /* We have found the place to store the handle and the object info. */
+ ux_utility_memory_copy(&pima_device_object_info_array[handle_index], object, sizeof(UX_SLAVE_CLASS_PIMA_OBJECT));
+ if (pima_device_object_info_array[handle_index].ux_device_class_pima_object_storage_id == 0)
+ pima_device_object_info_array[handle_index].ux_device_class_pima_object_storage_id = storage_id;
+ if (pima_device_object_info_array[handle_index].ux_device_class_pima_object_parent_object == 0xFFFFFFFF)
+ pima_device_object_info_array[handle_index].ux_device_class_pima_object_parent_object = 0;
+
+ /* Remember the object handle locally. */
+ pima_device_object_number_handles_array[handle_index] = handle_index + 1;
+
+ /* Extract from the object the MTP dataset information we need : StorageID.
+ if the storage id in the object info dataset is 0, the Initiator leaves it to the responder to store the object. */
+ if (object -> ux_device_class_pima_object_storage_id != 0)
+ pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_storage_id = object -> ux_device_class_pima_object_storage_id;
+ else
+ /* Take the storage ID given as a parameter by the function. */
+ pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_storage_id = storage_id;
+
+ /* Extract from the object the MTP dataset information we need : Format. */
+ pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_object_format = object -> ux_device_class_pima_object_format;
+
+ /* Extract from the object the MTP dataset information we need : Protection Status. */
+ pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_protection_status = object -> ux_device_class_pima_object_protection_status;
+
+ /* Extract from the object the MTP dataset information we need : Size. */
+ pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_object_size_low = object -> ux_device_class_pima_object_compressed_size;
+ pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_object_size_high = 0;
+
+ /* Extract from the object the MTP dataset information we need : Parent Object. */
+ if (object -> ux_device_class_pima_object_parent_object == 0xFFFFFFFF)
+ pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_parent_object = 0;
+ else
+ pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_parent_object = object -> ux_device_class_pima_object_parent_object;
+
+ /* Keep the file name in ASCIIZ. */
+ ux_utility_unicode_to_string(object -> ux_device_class_pima_object_filename, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_object_file_name);
+ ux_utility_unicode_to_string(object -> ux_device_class_pima_object_filename, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_name);
+
+ /* Keep the unique object identifier for this object. This is incremented each time we have a new object.
+ This number is unique to the MTP device for every object stored, even after being deleted.
+ There is a hack here. We only keep track of the first dword. A full implementation should ensure all 128 bits are used.
+ The identifier is incremented as soon as it is being used. */
+ pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_persistent_unique_object_identifier[0] = pima_device_object_persistent_unique_identifier++;
+
+ /* Return the object handle to the application. */
+ *object_handle = handle_index + 1;
+
+ /* Increment the number of known handles. */
+ pima_device_object_number_handles++;
+
+ /* We are done here. Return success. */
+ return(UX_SUCCESS);
+ }
+ }
+
+ /* We should never get here. */
+ return(UX_DEVICE_CLASS_PIMA_RC_STORE_FULL);
+
+ }
+
+ /* No more space for handle. Return storage full. */
+ return(UX_DEVICE_CLASS_PIMA_RC_STORE_FULL);
+
+}
+
+
+UINT pima_device_object_data_send (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle,
+ ULONG phase ,
+ UCHAR *object_buffer,
+ ULONG object_offset,
+ ULONG object_length)
+{
+
+UINT status;
+ULONG handle_index;
+UX_SLAVE_CLASS_PIMA_OBJECT *object;
+CHAR object_filename[64];
+
+ /* Check the object handle. It must be in the local array. */
+ status = pima_device_object_handle_check(object_handle, &object, &handle_index);
+
+ /* Does the object handle exist ? */
+ if (status == UX_SUCCESS)
+ {
+
+ /* Check the phase. Either Active or Complete. */
+ switch (phase)
+ {
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_TRANSFER_PHASE_ACTIVE :
+
+ /* We are either at the beginning of the transfer or continuing the transfer. */
+ if (object_offset == 0)
+ {
+
+ /* The object file name is in Unicode, decrypt it first because FileX is not using
+ unicode format. */
+ ux_utility_unicode_to_string(object -> ux_device_class_pima_object_filename, (UCHAR *) object_filename);
+
+ /* Open the file on the media since we expect a SendObject. */
+ status = fx_file_open(&ram_disk, &pima_device_object_filex_array[handle_index], object_filename, FX_OPEN_FOR_WRITE);
+ if (status != UX_SUCCESS)
+ return(UX_DEVICE_CLASS_PIMA_RC_OBJECT_NOT_OPENED);
+
+ /* Seek to the beginning of the object file. */
+ status = fx_file_seek(&pima_device_object_filex_array[handle_index], 0);
+ if (status != UX_SUCCESS)
+ return(UX_DEVICE_CLASS_PIMA_RC_OBJECT_NOT_OPENED);
+ }
+
+ /* We write the object data to the media. */
+ status = fx_file_write(&pima_device_object_filex_array[handle_index], object_buffer, object_length);
+
+ /* Check the status. */
+ if (status == UX_SUCCESS)
+
+ /* Done. Operation successful. */
+ return (UX_SUCCESS);
+
+ else
+ {
+
+ /* See what the error might be. */
+ switch (status)
+ {
+
+ case FX_MEDIA_NOT_OPEN :
+
+ /* Problem with media. */
+ status = UX_DEVICE_CLASS_PIMA_RC_STORE_NOT_AVAILABLE;
+ break;
+
+ case FX_NO_MORE_SPACE :
+
+ /* Media is full. */
+ status = UX_DEVICE_CLASS_PIMA_RC_STORE_FULL;
+ break;
+
+ case FX_WRITE_PROTECT :
+
+ /* Media is write protected. */
+ status = UX_DEVICE_CLASS_PIMA_RC_STORE_READ_ONLY;
+ break;
+
+ default :
+ status = UX_DEVICE_CLASS_PIMA_RC_ACCESS_DENIED;
+ break;
+
+ }
+ /* Return the error. */
+ return(status);
+
+ }
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_TRANSFER_PHASE_COMPLETED :
+
+ /* Save final object size. */
+ pima_device_object_info_array[handle_index].ux_device_class_pima_object_compressed_size =
+ pima_device_object_filex_array[handle_index].fx_file_current_file_size;
+
+ /* This is the end of the transfer for the object. Close it. */
+ status = fx_file_close(&pima_device_object_filex_array[handle_index]);
+ pima_device_object_filex_array[handle_index].fx_file_id = 0;
+
+ /* Check the status. */
+ if (status == UX_SUCCESS)
+
+ /* Done. Operation successful. */
+ return (UX_SUCCESS);
+
+ else
+ {
+
+ /* See what the error might be. */
+ switch (status)
+ {
+
+ case FX_MEDIA_NOT_OPEN :
+
+ /* Problem with media. */
+ status = UX_DEVICE_CLASS_PIMA_RC_STORE_NOT_AVAILABLE;
+ break;
+
+ default :
+ status = UX_DEVICE_CLASS_PIMA_RC_ACCESS_DENIED;
+ break;
+
+ }
+ /* Return the error. */
+ return(status);
+
+ }
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_TRANSFER_PHASE_COMPLETED_ERROR :
+
+ /* Close and delete the object. */
+ pima_device_object_delete(pima, object_handle);
+
+ /* We return OK no matter what. */
+ return(UX_SUCCESS);
+ }
+ }
+
+ /* Done here. Return error. */
+ return(UX_DEVICE_CLASS_PIMA_RC_INVALID_OBJECT_HANDLE);
+
+}
+
+UINT pima_device_object_delete(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle)
+{
+UX_SLAVE_CLASS_PIMA_OBJECT *object;
+ULONG handle_index;
+CHAR object_filename[64];
+UINT status;
+
+ /* Check the object handle. It must be in the local array. */
+ status = pima_device_object_handle_check(object_handle, &object, &handle_index);
+
+ /* Does the object handle exist ? */
+ if (status == UX_SUCCESS)
+ {
+
+ /* The object file name is in Unicode, decrypt it first because FileX is not using
+ unicode format. */
+ ux_utility_unicode_to_string(object -> ux_device_class_pima_object_filename, (UCHAR *) object_filename);
+
+ /* Yes, the handle is valid. The object pointer has been updated. */
+ /* The object may still be opened, try to close the handle first. */
+ status = fx_file_close(&pima_device_object_filex_array[handle_index]);
+
+ /* Delete the destination file. */
+ status = fx_file_delete(&ram_disk, object_filename);
+
+ /* Check if we had an error. */
+ if (status != UX_SUCCESS)
+ {
+
+ /* See what the error might be. */
+ switch (status)
+ {
+
+ case FX_MEDIA_NOT_OPEN :
+
+ /* Problem with media. */
+ status = UX_DEVICE_CLASS_PIMA_RC_STORE_NOT_AVAILABLE;
+ break;
+
+ case FX_WRITE_PROTECT :
+
+ /* Media is write protected. */
+ status = UX_DEVICE_CLASS_PIMA_RC_STORE_READ_ONLY;
+ break;
+
+ default :
+ status = UX_DEVICE_CLASS_PIMA_RC_ACCESS_DENIED;
+ break;
+ }
+
+ /* Return the error code. */
+ return(status);
+
+ }
+ else
+ {
+
+ /* The object was deleted on disk. Now update the internal application array tables. */
+ pima_device_object_number_handles_array[handle_index] = 0;
+
+ /* Update the number of handles in the system. */
+ pima_device_object_number_handles--;
+
+ /* We are done here. */
+ return(UX_SUCCESS);
+ }
+
+ }
+ else
+
+ /* Done here. Return error. */
+ return(UX_DEVICE_CLASS_PIMA_RC_INVALID_OBJECT_HANDLE);
+}
+
+
+UINT pima_device_object_prop_desc_get (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_property,
+ ULONG object_format_code,
+ UCHAR **object_prop_dataset,
+ ULONG *object_prop_dataset_length)
+{
+UINT status;
+UCHAR *object_property_dataset_data;
+ULONG object_property_dataset_data_length;
+
+ /* Check the object format belongs to the list. 3 categories : generic, audio, video */
+ switch (object_format_code)
+ {
+
+ case UX_DEVICE_CLASS_PIMA_OFC_UNDEFINED :
+ case UX_DEVICE_CLASS_PIMA_OFC_ASSOCIATION :
+ case UX_DEVICE_CLASS_PIMA_OFC_MP3 :
+ case UX_DEVICE_CLASS_PIMA_OFC_ASF :
+ case UX_DEVICE_CLASS_PIMA_OFC_WMA :
+ case UX_DEVICE_CLASS_PIMA_OFC_WMV :
+ case UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_AUDIO_ALBUM :
+ case UX_DEVICE_CLASS_PIMA_OFC_ABSTRACT_AUDIO_AND_VIDEO_PLAYLIST :
+
+ /* Set the pointer to the dataset_buffer. */
+ object_property_dataset_data = pima_device_object_property_dataset_data_buffer;
+
+ /* Isolate the property. That will determine the dataset header. */
+ switch (object_property)
+ {
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_STORAGEID :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_STORAGEID);
+
+ /* Data type is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT16);
+
+ /* GetSet value is GET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GET;
+
+ /* Default value is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+
+ /* Group code is NULL. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 2, 0);
+
+ /* Form Flag is not used. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 6) = 0;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 12;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FORMAT :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FORMAT);
+
+ /* Data type is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT16);
+
+ /* GetSet value is GET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GET;
+
+ /* Default value is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+
+ /* Group code is 3. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 2, 3);
+
+ /* Form Flag is not used. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 6) = 0;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 12;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PROTECTION_STATUS :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PROTECTION_STATUS);
+
+ /* Data type is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT16);
+
+ /* GetSet value is GET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GET;
+
+ /* Default value is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+
+ /* Group code is 4. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 2, 4);
+
+ /* Form Flag ENUM. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 6) = 2;
+
+ /* Number of elements in Enum array. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 7, 2);
+
+ /* Elements in Enum array. Here we store only No protection and Read-Only protection values. This can be extended with
+ Read-only data and Non transferrable data. Spec talks about MTP vendor extension range as well. Not used here. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 9, 0);
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 11, 1);
+
+ /* Set the length. */
+ object_property_dataset_data_length = 18;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_SIZE :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_SIZE);
+
+ /* Data type is UINT64. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT64);
+
+ /* GetSet value is GET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GET;
+
+ /* Default value is UINT64. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 4, 0);
+
+ /* Group code is NULL. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 8, 0);
+
+ /* Form Flag is not used. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 12) = 0;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 18;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FILE_NAME :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FILE_NAME);
+
+ /* Data type is STRING. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_STR);
+
+ /* GetSet value is GETSET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GETSET;
+
+ /* Store a empty Unicode string. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE) = 0;
+
+ /* Group code is NULL. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 1, 0);
+
+ /* Form Flag is not used. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 5) = 0;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 11;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PARENT_OBJECT :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PARENT_OBJECT);
+
+ /* Data type is UINT32. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT32);
+
+ /* GetSet value is GET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GET;
+
+ /* Default value is UINT32. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+
+ /* Group code is NULL. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 4, 0);
+
+ /* Form Flag is not used. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 8) = 0;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 14;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER);
+
+ /* Data type is UINT128. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT128);
+
+ /* GetSet value is GET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GET;
+
+ /* Default value is UINT128. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 4, 0);
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 8, 0);
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 12, 0);
+
+ /* Group code is NULL. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 16, 0);
+
+ /* Form Flag is not used. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 20) = 0;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 26;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NAME :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NAME);
+
+ /* Data type is STRING. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_STR);
+
+ /* GetSet value is GETSET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GETSET;
+
+ /* Store a empty Unicode string. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE) = 0;
+
+ /* Group code is 2. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 1, 2);
+
+ /* Form Flag is not used. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 5) = 0;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 11;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NON_CONSUMABLE :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NON_CONSUMABLE);
+
+ /* Data type is UINT8. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT8);
+
+ /* GetSet value is GET/SET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GETSET;
+
+ /* Default value is UINT8. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE) = 0;
+
+ /* Group code is 2. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 1, 2);
+
+ /* Form Flag ENUM. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 5) = 2;
+
+ /* Number of elements in Enum array. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 6, 2);
+
+ /* Elements in Enum array. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 8) = 0;
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 9) = 1;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 15;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ARTIST :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ARTIST);
+
+ /* Data type is STRING. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_STR);
+
+ /* GetSet value is GETSET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GETSET;
+
+ /* Store a empty Unicode string. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE) = 0;
+
+ /* Group code is NULL. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 1, 0);
+
+ /* Form Flag is not used. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 5) = 0;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 11;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_TRACK :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_TRACK);
+
+ /* Data type is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT16);
+
+ /* GetSet value is GET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GET;
+
+ /* Default value is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+
+ /* Group code is 3. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 2, 3);
+
+ /* Form Flag is not used. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 6) = 0;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 12;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_USE_COUNT :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_USE_COUNT);
+
+ /* Data type is UINT32. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT32);
+
+ /* GetSet value is GET/SET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GETSET;
+
+ /* Default value is UINT32. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+
+ /* Group code is 1. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 4, 0);
+
+ /* Form Flag is not used. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 8) = 0;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 14;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_DATE_AUTHORED :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_DATE_AUTHORED);
+
+ /* Data type is STRING. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_STR);
+
+ /* GetSet value is GETSET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GETSET;
+
+ /* Store a empty Unicode string. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE) = 0;
+
+ /* Group code is NULL. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 1, 0);
+
+ /* Form Flag is 3. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 5) = 3;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 11;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_GENRE :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_GENRE);
+
+ /* Data type is STRING. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_STR);
+
+ /* GetSet value is GETSET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GETSET;
+
+ /* Store a empty Unicode string. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE) = 0;
+
+ /* Group code is NULL. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 1, 0);
+
+ /* Form Flag is not used. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 5) = 0;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 11;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ALBUM_NAME :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ALBUM_NAME);
+
+ /* Data type is STRING. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_STR);
+
+ /* GetSet value is GETSET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GETSET;
+
+ /* Store a empty Unicode string. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE) = 0;
+
+ /* Group code is NULL. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 1, 0);
+
+ /* Form Flag is not used. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 5) = 0;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 11;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ALBUM_ARTIST :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ALBUM_ARTIST);
+
+ /* Data type is STRING. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_STR);
+
+ /* GetSet value is GETSET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GETSET;
+
+ /* Store a empty Unicode string. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE) = 0;
+
+ /* Group code is NULL. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 1, 0);
+
+ /* Form Flag is not used. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 5) = 0;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 11;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_SAMPLE_RATE :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_SAMPLE_RATE);
+
+ /* Data type is UINT32. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT32);
+
+ /* GetSet value is GET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GET;
+
+ /* Default value is UINT32. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+
+ /* Group code is 0. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 4, 0);
+
+ /* Form Flag RANGE. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 8) = 1;
+
+ /* Minimum range in array is 0KHZ. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 9, 0x00000000);
+
+ /* Maximum range in array is KHZ. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 13,0x0002EE00 );
+
+ /* Range step size is 32HZ. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 17,0x00000020 );
+
+ /* Set the length. */
+ object_property_dataset_data_length = 26;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NUMBER_OF_CHANNELS :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NUMBER_OF_CHANNELS);
+
+ /* Data type is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT16);
+
+ /* GetSet value is GET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GET;
+
+ /* Default value is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+
+ /* Group code is 0. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 2, 0);
+
+ /* Form Flag ENUM. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 6) = 2;
+
+ /* Number of elements in Enum array. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 7, 3);
+
+ /* Elements in Enum array. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 9, 0);
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 11, 1);
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 13, 2);
+
+ /* Set the length. */
+ object_property_dataset_data_length = 20;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_AUDIO_WAVE_CODEC :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_AUDIO_WAVE_CODEC);
+
+ /* Data type is UINT32. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT32);
+
+ /* GetSet value is GET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GET;
+
+ /* Default value is UINT32. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+
+ /* Group code is 0. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 4, 0);
+
+ /* Form Flag ENUM. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 8) = 2;
+
+ /* Number of elements in Enum array. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 9, 3);
+
+ /* Elements in Enum array. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 11, UX_TEST_AUDIO_CODEC_WAVE_FORMAT_MPEGLAYER3);
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 15, UX_TEST_AUDIO_CODEC_WAVE_FORMAT_MPEG);
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 19, UX_TEST_AUDIO_CODEC_WAVE_FORMAT_RAW_AAC1);
+
+ /* Set the length. */
+ object_property_dataset_data_length = 28;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_AUDIO_BITRATE :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_AUDIO_BITRATE);
+
+ /* Data type is UINT32. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT32);
+
+ /* GetSet value is GET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GET;
+
+ /* Default value is UINT32. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0x0000FA00);
+
+ /* Group code is 0. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 4, 0);
+
+ /* Form Flag RANGE. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 8) = 1;
+
+ /* Minimum range in array is 1 bit per second. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 9, 0x00000001);
+
+ /* Maximum range in array is 1,500,000 bit per second. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 13,0x0016E360 );
+
+ /* Range step size is 1 bit per second. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 17,0x00000001 );
+
+ /* Set the length. */
+ object_property_dataset_data_length = 26;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_DURATION :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_DURATION);
+
+ /* Data type is UINT32. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT32);
+
+ /* GetSet value is GET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GET;
+
+ /* Default value is UINT32. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+
+ /* Group code is NULL. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 4, 0);
+
+ /* Form Flag is 1. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 8) = 1;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 14;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_WIDTH :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_WIDTH);
+
+ /* Data type is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT16);
+
+ /* GetSet value is GET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GET;
+
+ /* Default value is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0x0000);
+
+ /* Group code is 0. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 2, 0);
+
+ /* Form Flag RANGE. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 4) = 1;
+
+ /* Minimum range in array is customer defined. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 5, 0x0000);
+
+ /* Maximum range in array is customer defined. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 7, 0x0000);
+
+ /* Range step size is customer defined. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 9, 0x0000);
+
+ /* Set the length. */
+ object_property_dataset_data_length = 11;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_HEIGHT :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_HEIGHT);
+
+ /* Data type is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT16);
+
+ /* GetSet value is GET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GET;
+
+ /* Default value is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0x0000);
+
+ /* Group code is 0. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 2, 0);
+
+ /* Form Flag RANGE. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 4) = 1;
+
+ /* Minimum range in array is customer defined. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 5, 0x0000);
+
+ /* Maximum range in array is customer defined. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 7, 0x0000);
+
+ /* Range step size is customer defined. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 9, 0x0000);
+
+ /* Set the length. */
+ object_property_dataset_data_length = 11;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_SCAN_TYPE :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_SCAN_TYPE);
+
+ /* Data type is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT16);
+
+ /* GetSet value is GET/SET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GETSET;
+
+ /* Default value is UINT16. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+
+ /* Group code is 0. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 2, 2);
+
+ /* Form Flag ENUM. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 5) = 2;
+
+ /* Number of elements in Enum array. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 7, 8);
+
+ /* Elements in Enum array. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 9, 0x0000);
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 11, 0x0001);
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 13, 0x0002);
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 15, 0x0003);
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 17, 0x0004);
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 19, 0x0005);
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 21, 0x0006);
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 23, 0x0007);
+
+ /* Set the length. */
+ object_property_dataset_data_length = 29;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_VIDEO_FOURCC_CODEC :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_VIDEO_FOURCC_CODEC);
+
+ /* Data type is UINT32. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT32);
+
+ /* GetSet value is GET/SET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GETSET;
+
+ /* Default value is UINT32. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+
+ /* Group code is 0. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 4, 2);
+
+ /* Form Flag ENUM. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 8) = 2;
+
+ /* Number of elements in Enum array. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 9, 1);
+
+ /* Elements in Enum array. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 13, 0x00000000);
+
+ /* Set the length. */
+ object_property_dataset_data_length = 22;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_VIDEO_BITRATE :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_VIDEO_BITRATE);
+
+ /* Data type is UINT32. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT32);
+
+ /* GetSet value is GET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GET;
+
+ /* Default value is UINT32. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+
+ /* Group code is 0. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 4, 2);
+
+ /* Form Flag RANGE. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 8) = 1;
+
+ /* Minimum range in array is 0. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 9, 0x00000000);
+
+ /* Maximum range in array is 0xFFFFFFFF. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 13,0xFFFFFFFF );
+
+ /* Range step size is 1. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 17,0x00000001 );
+
+ /* Set the length. */
+ object_property_dataset_data_length = 26;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_FRAMES_PER_THOUSAND_SECONDS :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_FRAMES_PER_THOUSAND_SECONDS);
+
+ /* Data type is UINT32. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT32);
+
+ /* GetSet value is GET/SET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GETSET;
+
+ /* Default value is UINT32. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+
+ /* Group code is 0. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 4, 2);
+
+ /* Form Flag ENUM. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 8) = 2;
+
+ /* Number of elements in Enum array. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 9, 1);
+
+ /* Elements in Enum array. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 13, 0x00000000);
+
+ /* Set the length. */
+ object_property_dataset_data_length = 22;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_KEYFRAME_DISTANCE :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_KEYFRAME_DISTANCE);
+
+ /* Data type is UINT32. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_UINT32);
+
+ /* GetSet value is GET/SET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GETSET;
+
+ /* Default value is UINT32. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE, 0);
+
+ /* Group code is 0. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 4, 2);
+
+ /* Form Flag RANGE. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 8) = 1;
+
+ /* Minimum range in array is 0. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 9, 0x00000000);
+
+ /* Maximum range in array is FFFFFFFF. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 13,0x0000FFFF );
+
+ /* Range step size is 1. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 17,0x00000001 );
+
+ /* Set the length. */
+ object_property_dataset_data_length = 26;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ENCODING_PROFILE :
+
+ /* Add the property code. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_CODE, UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ENCODING_PROFILE);
+
+ /* Data type is STRING. */
+ ux_utility_short_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_DATATYPE, UX_DEVICE_CLASS_PIMA_TYPES_STR);
+
+ /* GetSet value is GETSET. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_GETSET) = UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE_GETSET;
+
+ /* Store a empty Unicode string. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE) = 0;
+
+ /* Group code is NULL. */
+ ux_utility_long_put(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 1, 0);
+
+ /* Form Flag is not used. */
+ *(object_property_dataset_data + UX_DEVICE_CLASS_PIMA_OBJECT_PROPERTY_DATASET_VALUE + 5) = 0;
+
+ /* Set the length. */
+ object_property_dataset_data_length = 11;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ default :
+
+ /* Error, prop code is not valid. */
+ status = UX_DEVICE_CLASS_PIMA_RC_INVALID_OBJECT_PROP_CODE;
+
+ }
+
+ /* Check the status of the operation. */
+ if (status == UX_SUCCESS)
+ {
+
+ /* The property exist and its dataset created. Return its pointer to MTP. */
+ *object_prop_dataset = object_property_dataset_data;
+
+ /* And the length of the dataset. */
+ *object_prop_dataset_length = object_property_dataset_data_length;
+
+ /* Done here. */
+ return(UX_SUCCESS);
+ }
+ else
+
+ /* Done here. Return error. */
+ return(UX_DEVICE_CLASS_PIMA_RC_INVALID_OBJECT_PROP_CODE);
+
+ break;
+
+ default :
+
+ /* We get here when we have the wrong format code. */
+ return(UX_DEVICE_CLASS_PIMA_RC_INVALID_OBJECT_FORMAT_CODE);
+ }
+
+}
+
+
+UINT pima_device_object_prop_value_get (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle,
+ ULONG object_property,
+ UCHAR **object_prop_value,
+ ULONG *object_prop_value_length)
+{
+
+ULONG handle_index;
+UINT status;
+UCHAR *object_property_dataset_data;
+ULONG object_property_value_data_length;
+UX_SLAVE_CLASS_PIMA_OBJECT *object;
+
+ /* Check the object handle. It must be in the local array. */
+ status = pima_device_object_handle_check(object_handle, &object, &handle_index);
+
+ /* Does the object handle exist ? */
+ if (status == UX_SUCCESS)
+ {
+
+ /* Set the pointer to the dataset_buffer. */
+ object_property_dataset_data = pima_device_object_property_dataset_data_buffer;
+
+ /* Isolate the property. That will determine were we fetch the value. We use the dataset storage area to build the value. */
+ switch (object_property)
+ {
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_STORAGEID :
+
+ /* Copy the value itself. */
+ ux_utility_long_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_storage_id);
+
+ /* Set the length. */
+ object_property_value_data_length = 4;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FORMAT :
+
+ /* Copy the value itself. */
+ ux_utility_short_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_object_format);
+
+ /* Set the length. */
+ object_property_value_data_length = 2;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PROTECTION_STATUS :
+
+ /* Copy the value itself. */
+ ux_utility_short_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_protection_status);
+
+ /* Set the length. */
+ object_property_value_data_length = 2;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_SIZE :
+
+ /* Copy the value itself. */
+ ux_utility_long_put(object_property_dataset_data , pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_object_size_low);
+ ux_utility_long_put(object_property_dataset_data + 4, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_object_size_high);
+
+ /* Set the length. */
+ object_property_value_data_length = 8;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FILE_NAME :
+
+ /* Store the file name in unicode format. */
+ ux_utility_string_to_unicode(pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_object_file_name, object_property_dataset_data);
+
+ /* Set the length. First Unicode string data. */
+ object_property_value_data_length = (ULONG) *(object_property_dataset_data) * 2 + 1;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PARENT_OBJECT :
+
+ /* Copy the value itself. */
+ ux_utility_long_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_parent_object);
+
+ /* Set the length. */
+ object_property_value_data_length = 4;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER :
+
+ /* Copy the value itself. */
+ ux_utility_memory_copy(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_persistent_unique_object_identifier,16);
+
+ /* Set the length. */
+ object_property_value_data_length = 16;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NAME :
+
+ /* Store the file name in unicode format. */
+ ux_utility_string_to_unicode(pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_name, object_property_dataset_data);
+
+ /* Set the length. First Unicode string data. */
+ object_property_value_data_length = (ULONG) *(object_property_dataset_data) * 2 + 1;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NON_CONSUMABLE :
+
+ /* Copy the value itself. */
+ *object_property_dataset_data = pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_non_consumable;
+
+ /* Set the length. */
+ object_property_value_data_length = 1;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ARTIST :
+
+ /* Store the file name in unicode format. */
+ ux_utility_string_to_unicode(pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_artist, object_property_dataset_data);
+
+ /* Set the length. First Unicode string data. */
+ object_property_value_data_length = (ULONG) *(object_property_dataset_data) * 2 + 1;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_TRACK :
+
+ /* Copy the value itself. */
+ ux_utility_short_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_track);
+
+ /* Set the length. */
+ object_property_value_data_length = 2;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_USE_COUNT :
+
+ /* Copy the value itself. */
+ ux_utility_short_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_use_count);
+
+ /* Set the length. */
+ object_property_value_data_length = 2;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_DATE_AUTHORED :
+
+ /* Store the file name in unicode format. */
+ ux_utility_string_to_unicode(pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_date_authored, object_property_dataset_data);
+
+ /* Set the length. First Unicode string data. */
+ object_property_value_data_length = (ULONG) *(object_property_dataset_data) * 2 + 1;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_GENRE :
+
+ /* Store the file name in unicode format. */
+ ux_utility_string_to_unicode(pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_genre, object_property_dataset_data);
+
+ /* Set the length. First Unicode string data. */
+ object_property_value_data_length = (ULONG) *(object_property_dataset_data) * 2 + 1;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ALBUM_NAME :
+
+ /* Store the file name in unicode format. */
+ ux_utility_string_to_unicode(pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_album_name, object_property_dataset_data);
+
+ /* Set the length. First Unicode string data. */
+ object_property_value_data_length = (ULONG) *(object_property_dataset_data) * 2 + 1;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ALBUM_ARTIST :
+
+ /* Store the file name in unicode format. */
+ ux_utility_string_to_unicode(pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_album_artist, object_property_dataset_data);
+
+ /* Set the length. First Unicode string data. */
+ object_property_value_data_length = (ULONG) *(object_property_dataset_data) * 2 + 1;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_SAMPLE_RATE :
+
+ /* Copy the value itself. */
+ ux_utility_short_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_sample_rate);
+
+ /* Set the length. */
+ object_property_value_data_length = 2;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NUMBER_OF_CHANNELS :
+
+ /* Copy the value itself. */
+ ux_utility_short_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_number_of_channels);
+
+ /* Set the length. */
+ object_property_value_data_length = 2;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_AUDIO_WAVE_CODEC :
+
+ /* Copy the value itself. */
+ ux_utility_long_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_audio_wave_codec);
+
+ /* Set the length. */
+ object_property_value_data_length = 4;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_AUDIO_BITRATE :
+
+ /* Copy the value itself. */
+ ux_utility_long_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_audio_bitrate);
+
+ /* Set the length. */
+ object_property_value_data_length = 4;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_DURATION :
+
+ /* Copy the value itself. */
+ ux_utility_long_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_duration);
+
+ /* Set the length. */
+ object_property_value_data_length = 4;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_WIDTH :
+
+ /* Copy the value itself. */
+ ux_utility_short_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_width);
+
+ /* Set the length. */
+ object_property_value_data_length = 2;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_HEIGHT :
+
+ /* Copy the value itself. */
+ ux_utility_short_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_height);
+
+ /* Set the length. */
+ object_property_value_data_length = 2;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_SCAN_TYPE :
+
+ /* Copy the value itself. */
+ ux_utility_short_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_scan_type);
+
+ /* Set the length. */
+ object_property_value_data_length = 2;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_VIDEO_FOURCC_CODEC :
+
+ /* Copy the value itself. */
+ ux_utility_long_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_fourcc_codec);
+
+ /* Set the length. */
+ object_property_value_data_length = 2;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_VIDEO_BITRATE :
+
+ /* Copy the value itself. */
+ ux_utility_long_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_video_bitrate);
+
+ /* Set the length. */
+ object_property_value_data_length = 4;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_FRAMES_PER_THOUSAND_SECONDS :
+
+ /* Copy the value itself. */
+ ux_utility_long_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_frames_per_thousand_seconds);
+
+ /* Set the length. */
+ object_property_value_data_length = 4;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_KEYFRAME_DISTANCE :
+
+ /* Copy the value itself. */
+ ux_utility_long_put(object_property_dataset_data, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_keyframe_distance);
+
+ /* Set the length. */
+ object_property_value_data_length = 4;
+
+ /* We could create this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ENCODING_PROFILE :
+
+ /* Store the file name in unicode format. */
+ ux_utility_string_to_unicode(pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_encoding_profile, object_property_dataset_data);
+
+ /* Set the length. First Unicode string data. */
+ object_property_value_data_length = (ULONG) *(object_property_dataset_data) * 2 + 1;
+
+ /* Done here. */
+ break;
+
+ default :
+
+ /* Error, prop code is not valid. */
+ status = UX_DEVICE_CLASS_PIMA_RC_INVALID_OBJECT_PROP_CODE;
+
+ }
+
+ /* Check the status of the operation. */
+ if (status == UX_SUCCESS)
+ {
+
+ /* The property exist and its value created. Return its pointer to MTP. */
+ *object_prop_value = object_property_dataset_data;
+
+ /* And the length of the dataset. */
+ *object_prop_value_length = object_property_value_data_length;
+
+ /* Done here. */
+ return(UX_SUCCESS);
+ }
+ else
+
+ /* Done here. Return error. */
+ return(UX_DEVICE_CLASS_PIMA_RC_INVALID_OBJECT_PROP_CODE);
+ }
+ else
+
+ /* Done here. Return error. */
+ return(UX_DEVICE_CLASS_PIMA_RC_INVALID_OBJECT_HANDLE);
+}
+
+
+UINT pima_device_object_prop_value_set (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle,
+ ULONG object_property,
+ UCHAR *object_prop_value,
+ ULONG object_prop_value_length)
+{
+
+ULONG handle_index;
+UINT status;
+UX_SLAVE_CLASS_PIMA_OBJECT *object;
+
+ /* Check the object handle. It must be in the local array. */
+ status = pima_device_object_handle_check(object_handle, &object, &handle_index);
+
+ /* Does the object handle exist ? */
+ if (status == UX_SUCCESS)
+ {
+
+ /* Isolate the property. This is SET. So the properties that are GET only will not be changed. */
+ switch (object_property)
+ {
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_STORAGEID :
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FORMAT :
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_SIZE :
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_PARENT_OBJECT :
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_DURATION :
+
+ /* Object is write protected. */
+ status = UX_DEVICE_CLASS_PIMA_RC_OBJECT_WRITE_PROTECTED;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_OBJECT_FILE_NAME :
+
+ /* Copy the file name after translate from Unicode to ASCIIZ. */
+ ux_utility_unicode_to_string(object_prop_value, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_object_file_name);
+
+ /* We could set this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_NAME :
+
+ /* Copy the name after translate from Unicode to ASCIIZ. */
+ ux_utility_unicode_to_string(object_prop_value, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_name);
+
+ /* We could set this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_ARTIST :
+
+ /* Copy the artist name after translate from Unicode to ASCIIZ. */
+ ux_utility_unicode_to_string(object_prop_value, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_artist);
+
+ /* We could set this property. */
+ status = UX_SUCCESS;
+
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_DATE_AUTHORED :
+
+ /* Copy the date authored after translate from Unicode to ASCIIZ. */
+ ux_utility_unicode_to_string(object_prop_value, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_date_authored);
+
+ /* We could set this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ case UX_DEVICE_CLASS_PIMA_OBJECT_PROP_GENRE :
+
+ /* Copy the genre after translate from Unicode to ASCIIZ. */
+ ux_utility_unicode_to_string(object_prop_value, pima_device_object_property_array[handle_index].test_pima_object_prop_dataset_genre);
+
+ /* We could set this property. */
+ status = UX_SUCCESS;
+
+ /* Done here. */
+ break;
+
+ default :
+
+ /* Error, prop code is not valid. */
+ status = UX_DEVICE_CLASS_PIMA_RC_INVALID_OBJECT_PROP_CODE;
+ }
+
+
+ /* Done here. Return status. */
+ return(status);
+ }
+ else
+
+ /* Done here. Return error. */
+ return(UX_DEVICE_CLASS_PIMA_RC_INVALID_OBJECT_HANDLE);
+}
+
+
+UINT pima_device_object_references_get (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle,
+ UCHAR **object_references_array,
+ ULONG *object_references_array_length)
+{
+
+ULONG handle_index;
+UINT status;
+UX_SLAVE_CLASS_PIMA_OBJECT *object;
+ULONG references_array;
+
+ /* Check the object handle. It must be in the local array. */
+ status = pima_device_object_handle_check(object_handle, &object, &handle_index);
+
+ /* Does the object handle exist ? */
+ if (status == UX_SUCCESS)
+ {
+
+ /* The property exist. Not sure what to do with references in this release.
+ Here we simply create an empty array. */
+ references_array = 0;
+
+ /* Return its pointer to MTP. */
+ *object_references_array = (UCHAR *) &references_array;
+
+ /* And the length of the dataset. */
+ *object_references_array_length = sizeof(ULONG);
+
+ /* Done here. */
+ return(UX_SUCCESS);
+
+ }
+
+ else
+
+ /* Done here. Return error. */
+ return(UX_DEVICE_CLASS_PIMA_RC_INVALID_OBJECT_HANDLE);
+}
+
+
+UINT pima_device_object_references_set (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima,
+ ULONG object_handle,
+ UCHAR *object_references_array,
+ ULONG object_references_array_length)
+{
+
+ULONG handle_index;
+UINT status;
+UX_SLAVE_CLASS_PIMA_OBJECT *object;
+
+ /* Check the object handle. It must be in the local array. */
+ status = pima_device_object_handle_check(object_handle, &object, &handle_index);
+
+ /* Does the object handle exist ? */
+ if (status == UX_SUCCESS)
+ {
+
+ /* The property exist. Not sure what to do with references in this release. */
+
+ /* Done here. */
+ return(UX_SUCCESS);
+
+ }
+
+ else
+
+ /* Done here. Return error. */
+ return(UX_DEVICE_CLASS_PIMA_RC_INVALID_OBJECT_HANDLE);
+}
+
+
+UINT pima_device_object_handle_check(ULONG object_handle,
+ UX_SLAVE_CLASS_PIMA_OBJECT **object,
+ ULONG *caller_handle_index)
+{
+ULONG handle_index;
+
+ /* Parse all the handles we have in the media. */
+ for (handle_index = 0; handle_index < UX_TEST_MAX_HANDLES; handle_index++)
+ {
+
+ /* Check if we have the correct handle. */
+ if (pima_device_object_number_handles_array[handle_index] == object_handle)
+ {
+
+ /* We have found the right handle. Now retrieve its object info dataset. */
+ *object = &pima_device_object_info_array[handle_index];
+
+ /* Update the caller index. */
+ *caller_handle_index = handle_index;
+
+ /* We are done here. Return success. */
+ return(UX_SUCCESS);
+ }
+ }
+
+ /* We get here when the handle is unknown. Return error. */
+ return(UX_DEVICE_CLASS_PIMA_RC_INVALID_OBJECT_HANDLE);
+
+}
diff --git a/test/regression/usbx_ux_device_class_hid_descriptor_send_test.c b/test/regression/usbx_ux_device_class_hid_descriptor_send_test.c
index b86bb29c9..1fdb2ce48 100644
--- a/test/regression/usbx_ux_device_class_hid_descriptor_send_test.c
+++ b/test/regression/usbx_ux_device_class_hid_descriptor_send_test.c
@@ -8,8 +8,10 @@
/* */
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+/* Portions of this file were generated with AI assistance. */
#include "usbx_test_common_hid.h"
+#include "ux_host_stack.h"
#include "ux_host_class_hid_keyboard.h"
@@ -651,7 +653,7 @@ ALIGN_TYPE tmp;
/** Test case: 'if (hid_descriptor_length > UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH)' **/
/**************************************************/
#if UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH > 255
-#warning (hid_descriptor_length > UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH) not tested due to buffer size too big
+#pragma message("warning: (hid_descriptor_length > UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH) not tested due to buffer size too big")
#else
/* Create a transfer request for the HID class descriptor. */
diff --git a/test/regression/usbx_ux_device_class_video_basic_tests.c b/test/regression/usbx_ux_device_class_video_basic_tests.c
index 27c3c6215..ef1a3bd02 100644
--- a/test/regression/usbx_ux_device_class_video_basic_tests.c
+++ b/test/regression/usbx_ux_device_class_video_basic_tests.c
@@ -8,6 +8,7 @@
/* */
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+// Portions of this file were generated with AI assistance.
/* This test is designed to test the simple video host/device class operation. */
@@ -690,7 +691,7 @@ CHAR * memory_pointer;
#if !UX_TEST_MULTI_IFC_ON || !UX_TEST_MULTI_ALT_ON || !UX_TEST_MULTI_CLS_ON || \
(_CONFIGURE_DESCRIPTORS_LEN > UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH)
-#warning Tests skipped due to compile option!
+#pragma message("warning: Tests skipped due to compile option!")
printf("SKIP SUCCESS!\n");
test_control_return(0);
return;
diff --git a/test/regression/usbx_ux_device_stack_descriptor_send_test.c b/test/regression/usbx_ux_device_stack_descriptor_send_test.c
index 6de7006cd..985fb9a24 100644
--- a/test/regression/usbx_ux_device_stack_descriptor_send_test.c
+++ b/test/regression/usbx_ux_device_stack_descriptor_send_test.c
@@ -8,6 +8,7 @@
/* */
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+// Portions of this file were generated with AI assistance.
#include "usbx_test_common_hid.h"
#include "ux_host_class_hid_keyboard.h"
@@ -435,7 +436,7 @@ UCHAR *hid_class_descriptor = device_framework_high_spe
* Test case: string descriptor is too large for device to send.
**************************************************/
#if UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH > 255
-#warning String descriptor too large not tested due to control buffer too big
+#pragma message("warning: String descriptor too large not tested due to control buffer too big")
#else
/* Make the language ID framework too large. */
diff --git a/test/regression/usbx_ux_host_class_hid_logitech_pro_x_superlight_test.c b/test/regression/usbx_ux_host_class_hid_logitech_pro_x_superlight_test.c
index 79e3ff1b9..481f73cae 100644
--- a/test/regression/usbx_ux_host_class_hid_logitech_pro_x_superlight_test.c
+++ b/test/regression/usbx_ux_host_class_hid_logitech_pro_x_superlight_test.c
@@ -9,6 +9,8 @@
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************/
/** Test case: The default case of switch (item -> ux_host_class_hid_item_report_tag). **/
/**************************************************/
@@ -364,6 +366,7 @@ UINT status;
UX_HOST_CLASS_HID_REPORT *hid_report;
UX_HOST_CLASS_HID_FIELD *hid_field;
get_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT;
+ get_id.ux_host_class_hid_report_get_report = UX_NULL;
status = ux_host_class_hid_report_id_get(hid, &get_id);
hid_report = get_id.ux_host_class_hid_report_get_report;
while(hid_report != UX_NULL)
diff --git a/test/regression/usbx_ux_host_class_hid_report_item_bounds_test.c b/test/regression/usbx_ux_host_class_hid_report_item_bounds_test.c
new file mode 100644
index 000000000..3a8b131c9
--- /dev/null
+++ b/test/regression/usbx_ux_host_class_hid_report_item_bounds_test.c
@@ -0,0 +1,146 @@
+/***************************************************************************
+ * Copyright (c) 2026 Eclipse ThreadX contributors
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the MIT License which is available at
+ * https://opensource.org/licenses/MIT.
+ *
+ * AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5).
+ * The AI-generated portions may be considered public domain (CC0-1.0)
+ * and not subject to the project's licence. The human contributor has
+ * reviewed and verified that the code is correct.
+ *
+ * SPDX-License-Identifier: MIT and CC0-1.0
+ **************************************************************************/
+
+/* This tests the bounds applied when a HID report descriptor item is analysed.
+
+ An item declares how many data bytes follow its header. The report descriptor
+ walk advances by that declaration and parses the data before it checks the
+ remaining length, so the analysis itself has to refuse an item whose header
+ and data do not fit in what is left of the descriptor. */
+
+#include
+#include "tx_api.h"
+#include "ux_api.h"
+#include "ux_system.h"
+#include "ux_utility.h"
+#include "ux_host_class_hid.h"
+
+extern void test_control_return(UINT status);
+
+#define UX_TEST_MEMORY_SIZE (64 * 1024)
+
+static UCHAR test_memory[UX_TEST_MEMORY_SIZE];
+
+/* A short item declaring four data bytes, with nothing behind its header. */
+static UCHAR short_item_overrun[] = { 0x07 };
+
+/* A long item: its header alone is three bytes and it declares four more. */
+static UCHAR long_item_overrun[] = { 0xF4, 0x04, 0x00 };
+
+/* A well formed USAGE_PAGE item: one header byte and the two bytes it declares. */
+static UCHAR short_item_exact[] = { 0x06, 0x01, 0xFF };
+
+/* A well formed long item: a three byte header and the two bytes it declares. */
+static UCHAR long_item_exact[] = { 0xF4, 0x02, 0x00, 0xAA, 0xBB };
+
+
+/* Define what the initial system looks like. */
+
+#ifdef CTEST
+void test_application_define(void *first_unused_memory)
+#else
+void usbx_ux_host_class_hid_report_item_bounds_test_application_define(void *first_unused_memory)
+#endif
+{
+
+UINT status;
+UX_HOST_CLASS_HID_ITEM item;
+
+ UX_PARAMETER_NOT_USED(first_unused_memory);
+
+ /* Inform user. */
+ printf("Running ux_host_class_hid report item bounds Test.................... ");
+
+ /* The analysis reports corruption through the system error handler. */
+ status = ux_system_initialize(test_memory, UX_TEST_MEMORY_SIZE, UX_NULL, 0);
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d: system initialize failed (%u)\n", __LINE__, status);
+ test_control_return(1);
+ return;
+ }
+
+ /* A one byte descriptor declaring four data bytes must be refused, otherwise
+ the walk advances past the buffer and reads the data that is not there. */
+ status = _ux_host_class_hid_report_item_analyse(short_item_overrun,
+ sizeof(short_item_overrun), &item);
+ if (status != UX_DESCRIPTOR_CORRUPTED)
+ {
+ printf("ERROR #%d: short item overrun accepted (%u)\n", __LINE__, status);
+ test_control_return(1);
+ return;
+ }
+
+ /* The same holds for a long item, whose header is larger again. */
+ status = _ux_host_class_hid_report_item_analyse(long_item_overrun,
+ sizeof(long_item_overrun), &item);
+ if (status != UX_DESCRIPTOR_CORRUPTED)
+ {
+ printf("ERROR #%d: long item overrun accepted (%u)\n", __LINE__, status);
+ test_control_return(1);
+ return;
+ }
+
+ /* An item that fits exactly is still accepted. */
+ status = _ux_host_class_hid_report_item_analyse(short_item_exact,
+ sizeof(short_item_exact), &item);
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d: well formed item refused (%u)\n", __LINE__, status);
+ test_control_return(1);
+ return;
+ }
+
+ if (item.ux_host_class_hid_item_report_length != 2)
+ {
+ printf("ERROR #%d: wrong item report length %u\n", __LINE__,
+ item.ux_host_class_hid_item_report_length);
+ test_control_return(1);
+ return;
+ }
+
+ /* A long item that fits is accepted, and its header is the three bytes it
+ occupies. Reporting the tag mask here instead would have the walks advance
+ 240 bytes to clear a three byte header. */
+ status = _ux_host_class_hid_report_item_analyse(long_item_exact,
+ sizeof(long_item_exact), &item);
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d: well formed long item refused (%u)\n", __LINE__, status);
+ test_control_return(1);
+ return;
+ }
+
+ if (item.ux_host_class_hid_item_report_format != 3)
+ {
+ printf("ERROR #%d: long item header size %u, expected 3\n", __LINE__,
+ item.ux_host_class_hid_item_report_format);
+ test_control_return(1);
+ return;
+ }
+
+ /* An empty descriptor has no item in it at all. */
+ status = _ux_host_class_hid_report_item_analyse(short_item_exact, 0, &item);
+ if (status != UX_DESCRIPTOR_CORRUPTED)
+ {
+ printf("ERROR #%d: empty descriptor accepted (%u)\n", __LINE__, status);
+ test_control_return(1);
+ return;
+ }
+
+ /* Successful test. */
+ printf("SUCCESS!\n");
+ test_control_return(0);
+}
diff --git a/test/regression/usbx_ux_host_class_hid_report_walk_bounds_test.c b/test/regression/usbx_ux_host_class_hid_report_walk_bounds_test.c
new file mode 100644
index 000000000..960e6aa63
--- /dev/null
+++ b/test/regression/usbx_ux_host_class_hid_report_walk_bounds_test.c
@@ -0,0 +1,347 @@
+/***************************************************************************
+ * Copyright (c) 2026 Eclipse ThreadX contributors
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the MIT License which is available at
+ * https://opensource.org/licenses/MIT.
+ *
+ * AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5).
+ * The AI-generated portions may be considered public domain (CC0-1.0)
+ * and not subject to the project's licence. The human contributor has
+ * reviewed and verified that the code is correct.
+ *
+ * SPDX-License-Identifier: MIT and CC0-1.0
+ **************************************************************************/
+
+/* This test ensures the report descriptor walk stops when an item is refused.
+
+ The item analysis sets the item's declared header and data sizes before it
+ decides the item does not fit. The walk has to leave the loop on that verdict:
+ carrying on advances the cursor by sizes that were never in the descriptor, and
+ the per type parse that follows overwrites the failure with its own status. */
+
+#include "usbx_test_common_hid.h"
+#include "ux_host_class_hid_keyboard.h"
+
+
+static UCHAR hid_report_descriptor[] = {
+
+ 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
+ 0x09, 0x06, // USAGE (Keyboard)
+ 0xa1, 0x01, // COLLECTION (Application)
+ 0x95, 0x01, // REPORT_COUNT (1)
+ 0x75, 0x02, // REPORT_SIZE (2)
+ 0x81, 0x02, // INPUT (Data,Var,Abs)
+ 0xc0, // END_COLLECTION
+
+ /* A USAGE_PAGE header declaring two data
+ bytes, with the descriptor ending here. */
+ 0x06,
+};
+
+#define HID_REPORT_LENGTH sizeof(hid_report_descriptor)/sizeof(hid_report_descriptor[0])
+
+
+#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 52
+static UCHAR device_framework_full_speed[DEVICE_FRAMEWORK_LENGTH_FULL_SPEED] = {
+
+ /* Device descriptor */
+ 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08,
+ 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01,
+
+ /* Configuration descriptor */
+ 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0,
+ 0x32,
+
+ /* Interface descriptor */
+ 0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00,
+ 0x00,
+
+ /* HID descriptor */
+ 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_REPORT_LENGTH),
+ MSB(HID_REPORT_LENGTH),
+
+ /* Endpoint descriptor (Interrupt) */
+ 0x07, 0x05, 0x82, 0x03, 0x08, 0x00, 0x08
+
+ };
+
+
+#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 62
+static UCHAR device_framework_high_speed[DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED] = {
+
+ /* Device descriptor */
+ 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
+ 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02,
+ 0x03, 0x01,
+
+ /* Device qualifier descriptor */
+ 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
+ 0x01, 0x00,
+
+ /* Configuration descriptor */
+ 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0,
+ 0x32,
+
+ /* Interface descriptor */
+ 0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00,
+ 0x00,
+
+ /* HID descriptor */
+ 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_REPORT_LENGTH),
+ MSB(HID_REPORT_LENGTH),
+
+ /* Endpoint descriptor (Interrupt) */
+ 0x07, 0x05, 0x82, 0x03, 0x08, 0x00, 0x08
+
+ };
+
+
+ /* String Device Framework :
+ Byte 0 and 1 : Word containing the language ID : 0x0904 for US
+ Byte 2 : Byte containing the index of the descriptor
+ Byte 3 : Byte containing the length of the descriptor string
+ */
+
+#define STRING_FRAMEWORK_LENGTH 40
+static UCHAR string_framework[] = {
+
+ /* Manufacturer string descriptor : Index 1 */
+ 0x09, 0x04, 0x01, 0x0c,
+ 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c,
+ 0x6f, 0x67, 0x69, 0x63,
+
+ /* Product string descriptor : Index 2 */
+ 0x09, 0x04, 0x02, 0x0c,
+ 0x55, 0x53, 0x42, 0x20, 0x4b, 0x65, 0x79, 0x62,
+ 0x6f, 0x61, 0x72, 0x64,
+
+ /* Serial Number string descriptor : Index 3 */
+ 0x09, 0x04, 0x03, 0x04,
+ 0x30, 0x30, 0x30, 0x31
+ };
+
+
+ /* Multiple languages are supported on the device, to add
+ a language besides english, the unicode language code must
+ be appended to the language_id_framework array and the length
+ adjusted accordingly. */
+#define LANGUAGE_ID_FRAMEWORK_LENGTH 2
+static UCHAR language_id_framework[] = {
+
+ /* English. */
+ 0x09, 0x04
+ };
+
+
+
+/* One refusal per walk of the descriptor. The two host paths differ in how often
+ they walk it during a failing enumeration: the standalone state machine parses
+ once and stops, the RTOS path retries the whole enumeration. */
+#if defined(UX_HOST_STANDALONE)
+#define UX_TEST_EXPECTED_REFUSALS 1
+#else
+#define UX_TEST_EXPECTED_REFUSALS (2 * UX_RH_ENUMERATION_RETRY)
+#endif
+
+/* The walk reports a refused item through the error handler. Counting those is the
+ only way to see whether it stopped there: a walk that carries on is caught by the
+ length check at the bottom of the loop one item later, so the status the caller
+ sees is the same either way, and the over-read in between leaves no other trace. */
+static ULONG corrupted_descriptor_errors;
+
+static VOID error_callback(UINT system_level, UINT system_context, UINT error_code)
+{
+
+ if (error_code == UX_DESCRIPTOR_CORRUPTED)
+ corrupted_descriptor_errors++;
+
+
+ if (error_code != UX_HOST_CLASS_HID_COLLECTION_OVERFLOW &&
+ error_code != UX_DESCRIPTOR_CORRUPTED &&
+ error_code != UX_DEVICE_ENUMERATION_FAILURE)
+ {
+
+ /* Something went wrong. */
+ printf("Error on line %d\n", __LINE__);
+ test_control_return(1);
+ }
+}
+
+/* Define what the initial system looks like. */
+
+#ifdef CTEST
+void test_application_define(void *first_unused_memory)
+#else
+void usbx_ux_host_class_hid_report_walk_bounds_test_application_define(void *first_unused_memory)
+#endif
+{
+
+UINT status;
+CHAR * stack_pointer;
+CHAR * memory_pointer;
+UINT descriptor_size = HID_REPORT_LENGTH;
+
+
+ /* Inform user. */
+ printf("Running HID report descriptor walk bounds Test..................... ");
+
+ /* Initialize the free memory pointer */
+ stack_pointer = (CHAR *) usbx_memory;
+ memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 2);
+
+ /* Initialize USBX. Memory */
+ status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL,0);
+
+ /* Check for error. */
+ if (status != UX_SUCCESS)
+ {
+
+ printf("Error on line %d\n", __LINE__);
+ test_control_return(1);
+ }
+
+ /* Register the error callback. */
+ _ux_utility_error_callback_register(error_callback);
+
+ /* The code below is required for installing the host portion of USBX */
+ status = ux_host_stack_initialize(UX_NULL);
+ if (status != UX_SUCCESS)
+ {
+
+ printf("Error on line %d\n", __LINE__);
+ test_control_return(1);
+ }
+
+ status = ux_host_stack_class_register(_ux_system_host_class_hid_name, ux_host_class_hid_entry);
+ if (status != UX_SUCCESS)
+ {
+
+ printf("Error on line %d\n", __LINE__);
+ test_control_return(1);
+ }
+
+ /* Register the HID client(s). */
+ status = ux_host_class_hid_client_register(_ux_system_host_class_hid_client_keyboard_name, ux_host_class_hid_keyboard_entry);
+ if (status != UX_SUCCESS)
+ {
+
+ printf("Error on line %d, error code: %d\n", __LINE__, status);
+ test_control_return(1);
+ }
+
+ /* The code below is required for installing the device portion of USBX. No call back for
+ device status change in this example. */
+ status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED,
+ device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED,
+ string_framework, STRING_FRAMEWORK_LENGTH,
+ language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH,UX_NULL);
+ if(status!=UX_SUCCESS)
+ {
+
+ printf("Error on line %d\n", __LINE__);
+ test_control_return(1);
+ }
+
+ /* Initialize the hid class parameters. */
+ hid_parameter.ux_device_class_hid_parameter_report_address = hid_report_descriptor;
+ hid_parameter.ux_device_class_hid_parameter_report_length = HID_REPORT_LENGTH;
+ hid_parameter.ux_device_class_hid_parameter_callback = demo_thread_hid_callback;
+
+ /* Initilize the device hid class. The class is connected with interface 2 */
+ status = ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry,
+ 1,2, (VOID *)&hid_parameter);
+ if(status!=UX_SUCCESS)
+ {
+
+ printf("Error on line %d\n", __LINE__);
+ test_control_return(1);
+ }
+
+
+ /* Initialize the simulated device controller. */
+ status = _ux_dcd_sim_slave_initialize();
+
+ /* Check for error. */
+ if (status != UX_SUCCESS)
+ {
+
+ printf("Error on line %d\n", __LINE__);
+ test_control_return(1);
+ }
+
+ /* Register all the USB host controllers available in this system */
+ status = ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, ux_hcd_sim_host_initialize,0,0);
+
+ /* Check for error. */
+ if (status != UX_SUCCESS)
+ {
+
+ printf("Error on line %d\n", __LINE__);
+ test_control_return(1);
+ }
+
+ /* Create the main host simulation thread. */
+ status = tx_thread_create(&tx_demo_thread_host_simulation, "tx demo host simulation", tx_demo_thread_host_simulation_entry, 0,
+ stack_pointer, UX_DEMO_STACK_SIZE,
+ 20, 20, 1, TX_AUTO_START);
+
+ /* Check for error. */
+ if (status != TX_SUCCESS)
+ {
+
+ printf("Error on line %d\n", __LINE__);
+ test_control_return(1);
+ }
+}
+
+static void tx_demo_thread_host_simulation_entry(ULONG arg)
+{
+
+UINT status;
+
+
+ /* Find the HID class */
+ status = demo_class_hid_get();
+ if (status == UX_SUCCESS)
+ {
+
+ printf("Error on line %d, error code: %d\n", __LINE__, status);
+ test_control_return(1);
+ }
+
+ /* The host attempts enumeration UX_RH_ENUMERATION_RETRY times, and each attempt
+ must refuse the trailing item exactly once. One refusal per attempt more than
+ that is the walk parsing an item it had already rejected, which reads past the
+ descriptor before the loop's own length check stops it. */
+ if (corrupted_descriptor_errors != UX_TEST_EXPECTED_REFUSALS)
+ {
+
+ printf("ERROR #%d: %lu refusals, expected %u\n", __LINE__,
+ corrupted_descriptor_errors, UX_TEST_EXPECTED_REFUSALS);
+ test_control_return(1);
+ }
+
+ /* Now disconnect the device. */
+ _ux_device_stack_disconnect();
+
+ /* And deinitialize the class. */
+ status = ux_device_stack_class_unregister(_ux_system_slave_class_hid_name, ux_device_class_hid_entry);
+
+ /* Deinitialize the device side of usbx. */
+ _ux_device_stack_uninitialize();
+
+ /* And finally the usbx system resources. */
+ _ux_system_uninitialize();
+
+ /* Successful test. */
+ printf("SUCCESS!\n");
+ test_control_return(0);
+}
+
+
+static UINT demo_thread_hid_callback(UX_SLAVE_CLASS_HID *class, UX_SLAVE_CLASS_HID_EVENT *event)
+{
+ return(UX_SUCCESS);
+}
diff --git a/test/regression/usbx_ux_host_class_storage_media_get_test.c b/test/regression/usbx_ux_host_class_storage_media_get_test.c
index 5c9dd0f6a..7b4cc5581 100644
--- a/test/regression/usbx_ux_host_class_storage_media_get_test.c
+++ b/test/regression/usbx_ux_host_class_storage_media_get_test.c
@@ -8,6 +8,7 @@
/* */
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+// Portions of this file were generated with AI assistance.
/* This test is designed to test the storage host/device class operation. */
@@ -590,7 +591,7 @@ INT media_index;
test_control_return(1);
}
#if UX_MAX_HOST_LUN < 2 || UX_HOST_CLASS_STORAGE_MAX_MEDIA < 2
-#warning Increase UX_MAX_HOST_LUN and UX_HOST_CLASS_STORAGE_MAX_MEDIA for coverage test
+#pragma message("warning: Increase UX_MAX_HOST_LUN and UX_HOST_CLASS_STORAGE_MAX_MEDIA for coverage test")
#else
stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_media_get(0) - SUCCESS\n");
storage_medias[0].ux_host_class_storage_media_storage = UX_NULL;
@@ -698,4 +699,4 @@ static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_block
ram_disk_flush = UX_TRUE;
return ram_disk_flush_status;
-}
\ No newline at end of file
+}
diff --git a/test/regression/usbx_ux_host_class_video_format_walk_bounds_test.c b/test/regression/usbx_ux_host_class_video_format_walk_bounds_test.c
new file mode 100644
index 000000000..d12f19f73
--- /dev/null
+++ b/test/regression/usbx_ux_host_class_video_format_walk_bounds_test.c
@@ -0,0 +1,353 @@
+/***************************************************************************
+ * Copyright (c) 2026 Eclipse ThreadX contributors
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the MIT License which is available at
+ * https://opensource.org/licenses/MIT.
+ *
+ * AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5).
+ * The AI-generated portions may be considered public domain (CC0-1.0)
+ * and not subject to the project's licence. The human contributor has
+ * reviewed and verified that the code is correct.
+ *
+ * SPDX-License-Identifier: MIT and CC0-1.0
+ **************************************************************************/
+
+/* This tests the bounds on the VideoStreaming format/frame descriptor walks.
+
+ wTotalLength counts the class-specific block from the input header, and the
+ walks that serve frame queries start at the selected format instead. The
+ budget therefore has to be the block that is left behind that format, held to
+ the configuration buffer as well, because both quantities come off the device. */
+
+#include
+#include "tx_api.h"
+#include "ux_api.h"
+#include "ux_system.h"
+#include "ux_utility.h"
+#include "ux_host_class_video.h"
+
+extern void test_control_return(UINT status);
+
+/* Offsets into the streaming block built below. */
+#define VS_INPUT_HEADER_LENGTH 14
+#define VS_FORMAT_LENGTH 11
+#define VS_FRAME_LENGTH 30
+#define VS_FORMAT_1_OFFSET VS_INPUT_HEADER_LENGTH
+#define VS_FORMAT_2_OFFSET (VS_FORMAT_1_OFFSET + VS_FORMAT_LENGTH + VS_FRAME_LENGTH)
+#define VS_BLOCK_LENGTH (VS_FORMAT_2_OFFSET + VS_FORMAT_LENGTH + VS_FRAME_LENGTH)
+
+/* Bytes sitting behind the configuration, standing in for whatever the heap holds
+ there. A walk that honours the device's reported length instead of the buffer
+ reaches them, and they are shaped so that it finds something. */
+#define VS_BEYOND_LENGTH 32
+#define VS_PLANTED_FORMAT_INDEX 99
+#define VS_PLANTED_FRAME_COUNT 7
+
+/* A VideoStreaming block holding two formats, each with one frame. The block
+ runs to the very end of the configuration, which is what makes the walk from
+ the second format shorter than wTotalLength. */
+static UCHAR streaming_block[VS_BLOCK_LENGTH + VS_BEYOND_LENGTH] = {
+
+ /* VS_INPUT_HEADER: 2 formats, wTotalLength covers the whole block. */
+ VS_INPUT_HEADER_LENGTH, UX_HOST_CLASS_VIDEO_CS_INTERFACE, UX_HOST_CLASS_VIDEO_VS_INPUT_HEADER,
+ 2, (UCHAR)VS_BLOCK_LENGTH, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ /* VS_FORMAT_MJPEG, format index 1, one frame descriptor. */
+ VS_FORMAT_LENGTH, UX_HOST_CLASS_VIDEO_CS_INTERFACE, UX_HOST_CLASS_VIDEO_VS_FORMAT_MJPEG,
+ 1, 1, 0, 0, 0, 0, 0, 0,
+
+ /* VS_FRAME_MJPEG, frame index 1, 640x480. */
+ VS_FRAME_LENGTH, UX_HOST_CLASS_VIDEO_CS_INTERFACE, UX_HOST_CLASS_VIDEO_VS_FRAME_MJPEG,
+ 1, 0, 0x80, 0x02, 0xE0, 0x01, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
+
+ /* VS_FORMAT_MJPEG, format index 2, one frame descriptor. */
+ VS_FORMAT_LENGTH, UX_HOST_CLASS_VIDEO_CS_INTERFACE, UX_HOST_CLASS_VIDEO_VS_FORMAT_MJPEG,
+ 2, 1, 0, 0, 0, 0, 0, 0,
+
+ /* VS_FRAME_MJPEG, frame index 1, 320x240. */
+ VS_FRAME_LENGTH, UX_HOST_CLASS_VIDEO_CS_INTERFACE, UX_HOST_CLASS_VIDEO_VS_FRAME_MJPEG,
+ 1, 0, 0x40, 0x01, 0xF0, 0x00, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
+
+ /* Past the configuration: a well formed format descriptor that no walk should
+ ever reach. Finding it is the over-read. */
+ VS_FORMAT_LENGTH, UX_HOST_CLASS_VIDEO_CS_INTERFACE, UX_HOST_CLASS_VIDEO_VS_FORMAT_MJPEG,
+ VS_PLANTED_FORMAT_INDEX, VS_PLANTED_FRAME_COUNT, 0, 0, 0, 0, 0, 0
+};
+
+#define UX_TEST_MEMORY_SIZE (64 * 1024)
+
+static UX_HOST_CLASS_VIDEO video_instance;
+static UCHAR test_memory[UX_TEST_MEMORY_SIZE];
+
+/* A configuration descriptor holding the Video Streaming interface and its input
+ header. _ux_host_class_video_input_format_get scans for the interface, then
+ takes the formats length out of the header, so the length has to be reached
+ through a walk rather than planted on the instance. */
+#define VS_CFG_INTERFACE_LENGTH 9
+#define VS_CFG_HEADER_OFFSET VS_CFG_INTERFACE_LENGTH
+#define VS_CFG_LENGTH (VS_CFG_INTERFACE_LENGTH + VS_INPUT_HEADER_LENGTH)
+
+static UCHAR streaming_configuration[VS_CFG_LENGTH] = {
+
+ /* Standard interface descriptor, Video class, Streaming subclass. */
+ VS_CFG_INTERFACE_LENGTH, UX_INTERFACE_DESCRIPTOR_ITEM, 1, 0, 1,
+ UX_HOST_CLASS_VIDEO_CLASS, UX_HOST_CLASS_VIDEO_SUBCLASS_STREAMING, 0, 0,
+
+ /* VS_INPUT_HEADER. wTotalLength is patched per case. */
+ VS_INPUT_HEADER_LENGTH, UX_HOST_CLASS_VIDEO_CS_INTERFACE, UX_HOST_CLASS_VIDEO_VS_INPUT_HEADER,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+
+/* A parse callback that reports the descriptor corrupted, which is what an
+ entity parser does when the device's own numbers do not add up. */
+static UINT parse_reports_corrupted(VOID *arg, UCHAR *packed_interface_descriptor,
+ UCHAR *packed_entity_descriptor)
+{
+ UX_PARAMETER_NOT_USED(arg);
+ UX_PARAMETER_NOT_USED(packed_interface_descriptor);
+ UX_PARAMETER_NOT_USED(packed_entity_descriptor);
+ return(UX_DESCRIPTOR_CORRUPTED);
+}
+
+/* The entity walk checks the device is configured and matches the streaming
+ interface number before it reaches a parser, so both have to exist. */
+static UX_DEVICE video_device;
+static UX_INTERFACE video_streaming_interface;
+
+/* Point the instance at that configuration and declare a formats length. */
+static VOID configuration_setup(ULONG total_length)
+{
+
+UCHAR *instance_bytes = (UCHAR *)&video_instance;
+ULONG i;
+
+ for (i = 0; i < (ULONG)sizeof(video_instance); i++)
+ instance_bytes[i] = 0;
+
+ video_device.ux_device_state = UX_DEVICE_CONFIGURED;
+ video_streaming_interface.ux_interface_descriptor.bInterfaceNumber = 1;
+ video_instance.ux_host_class_video_device = &video_device;
+ video_instance.ux_host_class_video_streaming_interface = &video_streaming_interface;
+
+ streaming_configuration[VS_CFG_HEADER_OFFSET + 4] = (UCHAR)(total_length & 0xFF);
+ streaming_configuration[VS_CFG_HEADER_OFFSET + 5] = (UCHAR)((total_length >> 8) & 0xFF);
+
+ video_instance.ux_host_class_video_configuration_descriptor = streaming_configuration;
+ video_instance.ux_host_class_video_configuration_descriptor_length = VS_CFG_LENGTH;
+}
+
+
+
+/* Point the instance at the streaming block, selecting one of its formats. */
+static VOID video_instance_setup(ULONG format_offset, ULONG length_formats)
+{
+
+UCHAR *instance_bytes = (UCHAR *)&video_instance;
+ULONG i;
+
+ for (i = 0; i < (ULONG)sizeof(video_instance); i++)
+ instance_bytes[i] = 0;
+
+ video_instance.ux_host_class_video_configuration_descriptor = streaming_block;
+ video_instance.ux_host_class_video_configuration_descriptor_length = VS_BLOCK_LENGTH;
+ video_instance.ux_host_class_video_format_address = streaming_block;
+ video_instance.ux_host_class_video_length_formats = length_formats;
+ video_instance.ux_host_class_video_current_format_address = streaming_block + format_offset;
+}
+
+
+/* Define what the initial system looks like. */
+
+#ifdef CTEST
+void test_application_define(void *first_unused_memory)
+#else
+void usbx_ux_host_class_video_format_walk_bounds_test_application_define(void *first_unused_memory)
+#endif
+{
+
+UINT status;
+UX_HOST_CLASS_VIDEO_PARAMETER_FORMAT_DATA format_parameter;
+UX_HOST_CLASS_VIDEO_PARAMETER_FRAME_DATA frame_parameter;
+UX_HOST_CLASS_VIDEO_PARAMETER_FRAME_INTERVAL
+ interval_parameter;
+
+ UX_PARAMETER_NOT_USED(first_unused_memory);
+
+ /* Inform user. */
+ printf("Running ux_host_class_video format walk bounds Test.................. ");
+
+ /* The walks report corruption through the system error handler, so the system
+ has to be up before any of them runs. */
+ status = ux_system_initialize(test_memory, UX_TEST_MEMORY_SIZE, UX_NULL, 0);
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d: system initialize failed (%u)\n", __LINE__, status);
+ test_control_return(1);
+ return;
+ }
+
+ /* The second format sits well inside the block, and the block ends with the
+ configuration. Its frame still has to be found: the budget is the block
+ behind the format, not the whole reported formats length. */
+ video_instance_setup(VS_FORMAT_2_OFFSET, VS_BLOCK_LENGTH);
+ frame_parameter.ux_host_class_video_parameter_frame_requested = 1;
+ status = _ux_host_class_video_frame_data_get(&video_instance, &frame_parameter);
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d: frame data get refused a valid second format\n", __LINE__);
+ test_control_return(1);
+ return;
+ }
+
+ if (frame_parameter.ux_host_class_video_parameter_frame_width != 320)
+ {
+ printf("ERROR #%d: wrong frame width %lu\n", __LINE__,
+ frame_parameter.ux_host_class_video_parameter_frame_width);
+ test_control_return(1);
+ return;
+ }
+
+ /* The same holds for the interval query. */
+ video_instance_setup(VS_FORMAT_2_OFFSET, VS_BLOCK_LENGTH);
+ interval_parameter.ux_host_class_video_parameter_frame_requested = 1;
+ interval_parameter.ux_host_class_video_parameter_frame_interval_buffer = UX_NULL;
+ interval_parameter.ux_host_class_video_parameter_frame_interval_buffer_length = 0;
+ status = _ux_host_class_video_frame_interval_get(&video_instance, &interval_parameter);
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d: frame interval get refused a valid second format\n", __LINE__);
+ test_control_return(1);
+ return;
+ }
+
+ /* A device reporting a formats length past the configuration buffer must be
+ refused rather than walked. */
+ video_instance_setup(VS_FORMAT_1_OFFSET, VS_BLOCK_LENGTH * 4);
+ frame_parameter.ux_host_class_video_parameter_frame_requested = 99;
+ status = _ux_host_class_video_frame_data_get(&video_instance, &frame_parameter);
+ if (status != UX_DESCRIPTOR_CORRUPTED)
+ {
+ printf("ERROR #%d: oversized formats length was not refused (%u)\n", __LINE__, status);
+ test_control_return(1);
+ return;
+ }
+
+ /* A current format sitting past the reported block is equally corrupt. */
+ video_instance_setup(VS_FORMAT_2_OFFSET, VS_FORMAT_1_OFFSET);
+ frame_parameter.ux_host_class_video_parameter_frame_requested = 1;
+ status = _ux_host_class_video_frame_data_get(&video_instance, &frame_parameter);
+ if (status != UX_DESCRIPTOR_CORRUPTED)
+ {
+ printf("ERROR #%d: format past the formats block was not refused (%u)\n", __LINE__, status);
+ test_control_return(1);
+ return;
+ }
+
+ /* The interval query owns the same budget as the frame query, so it has to
+ refuse the same two shapes. */
+ video_instance_setup(VS_FORMAT_1_OFFSET, VS_BLOCK_LENGTH * 4);
+ interval_parameter.ux_host_class_video_parameter_frame_requested = 99;
+ interval_parameter.ux_host_class_video_parameter_frame_interval_buffer = UX_NULL;
+ interval_parameter.ux_host_class_video_parameter_frame_interval_buffer_length = 0;
+ status = _ux_host_class_video_frame_interval_get(&video_instance, &interval_parameter);
+ if (status != UX_DESCRIPTOR_CORRUPTED)
+ {
+ printf("ERROR #%d: interval get accepted an oversized formats length (%u)\n", __LINE__, status);
+ test_control_return(1);
+ return;
+ }
+
+ video_instance_setup(VS_FORMAT_2_OFFSET, VS_FORMAT_1_OFFSET);
+ interval_parameter.ux_host_class_video_parameter_frame_requested = 1;
+ interval_parameter.ux_host_class_video_parameter_frame_interval_buffer = UX_NULL;
+ interval_parameter.ux_host_class_video_parameter_frame_interval_buffer_length = 0;
+ status = _ux_host_class_video_frame_interval_get(&video_instance, &interval_parameter);
+ if (status != UX_DESCRIPTOR_CORRUPTED)
+ {
+ printf("ERROR #%d: interval get accepted a format past the block (%u)\n", __LINE__, status);
+ test_control_return(1);
+ return;
+ }
+
+ /* The format query walks from the start of the block rather than from the
+ selected format, so its budget is the reported length held to the
+ configuration buffer. A block that ends with the configuration is valid. */
+ video_instance_setup(VS_FORMAT_1_OFFSET, VS_BLOCK_LENGTH);
+ format_parameter.ux_host_class_video_parameter_format_requested = 2;
+ status = _ux_host_class_video_format_data_get(&video_instance, &format_parameter);
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d: format data get refused a valid block (%u)\n", __LINE__, status);
+ test_control_return(1);
+ return;
+ }
+
+ if (format_parameter.ux_host_class_video_parameter_number_frame_descriptors != 1)
+ {
+ printf("ERROR #%d: wrong frame descriptor count %lu\n", __LINE__,
+ format_parameter.ux_host_class_video_parameter_number_frame_descriptors);
+ test_control_return(1);
+ return;
+ }
+
+ /* A reported length past the configuration buffer must be refused before the
+ walk dereferences anything. The format asked for exists only in the bytes
+ behind the configuration, so a walk that reaches it reports success and
+ hands back a descriptor count it read out of bounds. */
+ video_instance_setup(VS_FORMAT_1_OFFSET, VS_BLOCK_LENGTH + VS_BEYOND_LENGTH);
+ format_parameter.ux_host_class_video_parameter_format_requested = VS_PLANTED_FORMAT_INDEX;
+ format_parameter.ux_host_class_video_parameter_number_frame_descriptors = 0;
+ status = _ux_host_class_video_format_data_get(&video_instance, &format_parameter);
+ if (status != UX_DESCRIPTOR_CORRUPTED)
+ {
+ printf("ERROR #%d: format data get reached past the configuration (%u, frames %lu)\n",
+ __LINE__, status,
+ format_parameter.ux_host_class_video_parameter_number_frame_descriptors);
+ test_control_return(1);
+ return;
+ }
+
+ /* The input header's own length field is the one the device controls. A
+ header declaring more formats bytes than the configuration holds behind it
+ must be refused; before the fix it was taken at face value and the formats
+ address published, so every later walk ran on an oversized budget. */
+ configuration_setup(VS_CFG_LENGTH + 0x100);
+ status = _ux_host_class_video_input_format_get(&video_instance);
+ if (status != UX_DESCRIPTOR_CORRUPTED)
+ {
+ printf("ERROR #%d: oversized input header accepted (%u)\n", __LINE__, status);
+ test_control_return(1);
+ return;
+ }
+
+ /* A length that fits is still accepted, and publishes the formats address. */
+ configuration_setup(VS_CFG_LENGTH - VS_CFG_HEADER_OFFSET);
+ status = _ux_host_class_video_input_format_get(&video_instance);
+ if (status != UX_SUCCESS)
+ {
+ printf("ERROR #%d: well formed input header refused (%u)\n", __LINE__, status);
+ test_control_return(1);
+ return;
+ }
+
+ /* A parser that reports corruption has to fail the walk, not merely end it.
+ Before the fix any non-zero status stopped the loop and the caller was told
+ the parse had succeeded, so a descriptor the parser had already rejected
+ went on to be used. */
+ configuration_setup(VS_CFG_LENGTH - VS_CFG_HEADER_OFFSET);
+ status = _ux_host_class_video_entities_parse(&video_instance, parse_reports_corrupted, UX_NULL);
+ if (status != UX_DESCRIPTOR_CORRUPTED)
+ {
+ printf("ERROR #%d: a corrupted parse was reported as success (%u)\n", __LINE__, status);
+ test_control_return(1);
+ return;
+ }
+
+ /* Successful test. */
+ printf("SUCCESS!\n");
+ test_control_return(0);
+}
diff --git a/test/regression/usbx_ux_host_stack_device_configuration_get_test.c b/test/regression/usbx_ux_host_stack_device_configuration_get_test.c
index 1655076c7..97e71cf7e 100644
--- a/test/regression/usbx_ux_host_stack_device_configuration_get_test.c
+++ b/test/regression/usbx_ux_host_stack_device_configuration_get_test.c
@@ -8,6 +8,7 @@
/* */
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+/* Portions of this file were generated with AI assistance. */
/* This test is designed to test the ux_host_stack_device_configuration_get. */
@@ -15,6 +16,7 @@
#include "tx_api.h"
#include "ux_api.h"
#include "ux_system.h"
+#include "ux_host_stack.h"
#include "ux_utility.h"
#include "ux_host_class_dpump.h"
#include "ux_device_class_dpump.h"
diff --git a/test/regression/usbx_ux_utility_descriptor_struct_test.c b/test/regression/usbx_ux_utility_descriptor_struct_test.c
index 67a83c9a9..cfe8b2186 100644
--- a/test/regression/usbx_ux_utility_descriptor_struct_test.c
+++ b/test/regression/usbx_ux_utility_descriptor_struct_test.c
@@ -8,6 +8,7 @@
/* */
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+/* Portions of this file were generated with AI assistance. */
/* This test is designed to test the ux_utility_descriptor_parse. */
@@ -144,6 +145,19 @@ CHAR *memory_pointer;
static void ux_test_thread_simulation_0_entry(ULONG arg)
{
+UCHAR invalid_zero[] = {0};
+UCHAR invalid_three[] = {1, 3};
+UCHAR invalid_eight[] = {8};
+UCHAR aligned_fields[] = {1, 2, 4};
+
+ /* Reject unsupported field sizes and align valid descriptor layouts. */
+ UX_TEST_ASSERT(_ux_utility_descriptor_parse_size(invalid_zero, 1, 3u) == 0);
+ UX_TEST_ASSERT(_ux_utility_descriptor_parse_size(invalid_three, 2, 3u) == 0);
+ UX_TEST_ASSERT(_ux_utility_descriptor_parse_size(invalid_eight, 1, 3u) == 0);
+ UX_TEST_ASSERT(_ux_utility_descriptor_parse_size(aligned_fields, 0, 3u) == 0);
+ UX_TEST_ASSERT(_ux_utility_descriptor_parse_size(aligned_fields, 3, 3u) == 8);
+ UX_TEST_ASSERT(_ux_utility_descriptor_parse_size(aligned_fields, 3, 15u) == 16);
+
/* Print STD framework descriptor's sizes */
printf("\n");
printf("Descriptor %7s %7s %7s\n", "nFields", "Size4", "SizeNew");
diff --git a/test/regression/usbx_uxe_device_audio_test.c b/test/regression/usbx_uxe_device_audio_test.c
index 153653b6a..d2d3c425a 100644
--- a/test/regression/usbx_uxe_device_audio_test.c
+++ b/test/regression/usbx_uxe_device_audio_test.c
@@ -8,6 +8,7 @@
/* */
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+// Portions of this file were generated with AI assistance.
/* This test is designed to test the ux_utility_descriptor_pack. */
@@ -409,7 +410,7 @@ CHAR *memory_pointer;
/* Inform user. */
printf("Running uxe_device_audio APIs Test.................................. ");
#if !defined(UX_DEVICE_CLASS_AUDIO_ENABLE_ERROR_CHECKING)
-#warning Tests skipped due to compile option!
+#pragma message("warning: Tests skipped due to compile option!")
printf("SKIP SUCCESS!\n");
test_control_return(0);
return;
diff --git a/test/regression/usbx_uxe_device_ccid_test.c b/test/regression/usbx_uxe_device_ccid_test.c
index e7b8e2056..115ee213e 100644
--- a/test/regression/usbx_uxe_device_ccid_test.c
+++ b/test/regression/usbx_uxe_device_ccid_test.c
@@ -8,6 +8,7 @@
/* */
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+// Portions of this file were generated with AI assistance.
/* This test is designed to test the ux_utility_descriptor_pack. */
@@ -170,7 +171,7 @@ CHAR *memory_pointer;
/* Inform user. */
printf("Running uxe_device_printer APIs Test.................................. ");
#if !defined(UX_DEVICE_CLASS_CCID_ENABLE_ERROR_CHECKING)
-#warning Tests skipped due to compile option!
+#pragma message("warning: Tests skipped due to compile option!")
printf("SKIP SUCCESS!\n");
test_control_return(0);
return;
diff --git a/test/regression/usbx_uxe_device_cdc_acm_test.c b/test/regression/usbx_uxe_device_cdc_acm_test.c
index 2ec30e00e..38a70ad98 100644
--- a/test/regression/usbx_uxe_device_cdc_acm_test.c
+++ b/test/regression/usbx_uxe_device_cdc_acm_test.c
@@ -8,6 +8,7 @@
/* */
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+// Portions of this file were generated with AI assistance.
/* This test is designed to test the ux_utility_descriptor_pack. */
@@ -64,7 +65,7 @@ CHAR *memory_pointer;
/* Inform user. */
printf("Running uxe_device_cdc_acm APIs Test.................................. ");
#if !defined(UX_DEVICE_CLASS_CDC_ACM_ENABLE_ERROR_CHECKING)
-#warning Tests skipped due to compile option!
+#pragma message("warning: Tests skipped due to compile option!")
printf("SKIP SUCCESS!\n");
test_control_return(0);
return;
diff --git a/test/regression/usbx_uxe_device_dfu_test.c b/test/regression/usbx_uxe_device_dfu_test.c
index cc322078f..5bedf6d59 100644
--- a/test/regression/usbx_uxe_device_dfu_test.c
+++ b/test/regression/usbx_uxe_device_dfu_test.c
@@ -8,6 +8,7 @@
/* */
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+// Portions of this file were generated with AI assistance.
/* This test is designed to test the simple dpump host/device class operation. */
@@ -265,7 +266,7 @@ ULONG test_n;
/* Inform user. */
printf("Running uxe_device_dfu APIs Test.................................... ");
#if !defined(UX_DEVICE_CLASS_DFU_ENABLE_ERROR_CHECKING)
-#warning Tests skipped due to compile option!
+#pragma message("warning: Tests skipped due to compile option!")
printf("SKIP SUCCESS!\n");
test_control_return(0);
return;
diff --git a/test/regression/usbx_uxe_device_hid_test.c b/test/regression/usbx_uxe_device_hid_test.c
index cc0225e23..b3ba91fa7 100644
--- a/test/regression/usbx_uxe_device_hid_test.c
+++ b/test/regression/usbx_uxe_device_hid_test.c
@@ -8,6 +8,7 @@
/* */
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+// Portions of this file were generated with AI assistance.
/* This test is designed to test the ux_utility_descriptor_pack. */
@@ -73,7 +74,7 @@ CHAR *memory_pointer;
/* Inform user. */
printf("Running uxe_device_hid APIs Test.................................... ");
#if !defined(UX_DEVICE_CLASS_HID_ENABLE_ERROR_CHECKING)
-#warning Tests skipped due to compile option!
+#pragma message("warning: Tests skipped due to compile option!")
printf("SKIP SUCCESS!\n");
test_control_return(0);
return;
diff --git a/test/regression/usbx_uxe_device_pima_test.c b/test/regression/usbx_uxe_device_pima_test.c
index b9796ea80..aa832e214 100644
--- a/test/regression/usbx_uxe_device_pima_test.c
+++ b/test/regression/usbx_uxe_device_pima_test.c
@@ -8,6 +8,7 @@
/* */
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+// Portions of this file were generated with AI assistance.
/* This test is designed to test the ux_utility_descriptor_pack. */
@@ -463,7 +464,7 @@ CHAR *memory_pointer;
/* Inform user. */
printf("Running uxe_device_pima APIs Test................................... ");
#if !defined(UX_DEVICE_CLASS_PRINTER_ENABLE_ERROR_CHECKING)
-#warning Tests skipped due to compile option!
+#pragma message("warning: Tests skipped due to compile option!")
printf("SKIP SUCCESS!\n");
test_control_return(0);
return;
diff --git a/test/regression/usbx_uxe_device_printer_test.c b/test/regression/usbx_uxe_device_printer_test.c
index cd81c0c30..d80b9a853 100644
--- a/test/regression/usbx_uxe_device_printer_test.c
+++ b/test/regression/usbx_uxe_device_printer_test.c
@@ -8,6 +8,7 @@
/* */
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+// Portions of this file were generated with AI assistance.
/* This test is designed to test the ux_utility_descriptor_pack. */
@@ -65,7 +66,7 @@ CHAR *memory_pointer;
/* Inform user. */
printf("Running uxe_device_printer APIs Test.................................. ");
#if !defined(UX_DEVICE_CLASS_PRINTER_ENABLE_ERROR_CHECKING)
-#warning Tests skipped due to compile option!
+#pragma message("warning: Tests skipped due to compile option!")
printf("SKIP SUCCESS!\n");
test_control_return(0);
return;
diff --git a/test/regression/usbx_uxe_device_stack_test.c b/test/regression/usbx_uxe_device_stack_test.c
index 0a47e86f9..17726e55b 100644
--- a/test/regression/usbx_uxe_device_stack_test.c
+++ b/test/regression/usbx_uxe_device_stack_test.c
@@ -8,6 +8,7 @@
/* */
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+// Portions of this file were generated with AI assistance.
/* This test is designed to test the ux_utility_descriptor_pack. */
@@ -74,7 +75,7 @@ CHAR *memory_pointer;
/* Inform user. */
printf("Running uxe_system APIs Test........................................ ");
#if !defined(UX_DEVICE_CLASS_AUDIO_ENABLE_ERROR_CHECKING)
-#warning Tests skipped due to compile option!
+#pragma message("warning: Tests skipped due to compile option!")
printf("SKIP SUCCESS!\n");
test_control_return(0);
return;
diff --git a/test/regression/usbx_uxe_device_storage_test.c b/test/regression/usbx_uxe_device_storage_test.c
index d68504dce..0650abf6e 100644
--- a/test/regression/usbx_uxe_device_storage_test.c
+++ b/test/regression/usbx_uxe_device_storage_test.c
@@ -8,6 +8,7 @@
/* */
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+// Portions of this file were generated with AI assistance.
/* This test is designed to test the ux_utility_descriptor_pack. */
@@ -73,7 +74,7 @@ CHAR *memory_pointer;
/* Inform user. */
printf("Running uxe_device_storage APIs Test................................ ");
#if !defined(UX_DEVICE_CLASS_STORAGE_ENABLE_ERROR_CHECKING)
-#warning Tests skipped due to compile option!
+#pragma message("warning: Tests skipped due to compile option!")
printf("SKIP SUCCESS!\n");
test_control_return(0);
return;
diff --git a/test/regression/usbx_uxe_device_video_test.c b/test/regression/usbx_uxe_device_video_test.c
index 9a4a3f00c..9be268288 100644
--- a/test/regression/usbx_uxe_device_video_test.c
+++ b/test/regression/usbx_uxe_device_video_test.c
@@ -8,6 +8,7 @@
/* */
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+/* Portions of this file were generated with AI assistance. */
/* This test is designed to test the ux_utility_descriptor_pack. */
@@ -451,7 +452,7 @@ CHAR *memory_pointer;
/* Inform user. */
printf("Running uxe_device_video APIs Test.................................. ");
#if !defined(UX_DEVICE_CLASS_VIDEO_ENABLE_ERROR_CHECKING)
-#warning Tests skipped due to compile option!
+#pragma message("warning: Tests skipped due to compile option!")
printf("SKIP SUCCESS!\n");
test_control_return(0);
return;
@@ -559,9 +560,10 @@ static void ux_test_thread_simulation_0_entry(ULONG arg)
UINT status;
UX_DEVICE_CLASS_VIDEO_STREAM dummy_video_stream;
ULONG dummy_length;
-UCHAR payload_data[64];
-ULONG payload_length;
-UCHAR **dummy_payload = &payload_data;
+UCHAR payload_data[64];
+ULONG payload_length;
+UCHAR *payload = payload_data;
+UCHAR **dummy_payload = &payload;
dummy_length = ux_device_class_video_max_payload_length(UX_NULL);
if (dummy_length != 0)
diff --git a/test/regression/usbx_uxe_host_audio_test.c b/test/regression/usbx_uxe_host_audio_test.c
index a2544d25b..8827ac0db 100644
--- a/test/regression/usbx_uxe_host_audio_test.c
+++ b/test/regression/usbx_uxe_host_audio_test.c
@@ -8,6 +8,7 @@
/* */
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+// Portions of this file were generated with AI assistance.
/* This test is designed to test the ux_utility_descriptor_pack. */
@@ -65,7 +66,7 @@ CHAR *memory_pointer;
/* Inform user. */
printf("Running uxe_host_audio APIs Test.................................... ");
#if !defined(UX_HOST_CLASS_AUDIO_ENABLE_ERROR_CHECKING)
-#warning Tests skipped due to compile option!
+#pragma message("warning: Tests skipped due to compile option!")
printf("SKIP SUCCESS!\n");
test_control_return(0);
return;
diff --git a/test/regression/usbx_uxe_host_cdc_acm_test.c b/test/regression/usbx_uxe_host_cdc_acm_test.c
index cd369b0bf..dd5aab4c2 100644
--- a/test/regression/usbx_uxe_host_cdc_acm_test.c
+++ b/test/regression/usbx_uxe_host_cdc_acm_test.c
@@ -8,6 +8,7 @@
/* */
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+// Portions of this file were generated with AI assistance.
/* This test is designed to test the ux_utility_descriptor_pack. */
@@ -65,7 +66,7 @@ CHAR *memory_pointer;
/* Inform user. */
printf("Running uxe_host_cdc_acm APIs Test.................................. ");
#if !defined(UX_HOST_CLASS_CDC_ACM_ENABLE_ERROR_CHECKING)
-#warning Tests skipped due to compile option!
+#pragma message("warning: Tests skipped due to compile option!")
printf("SKIP SUCCESS!\n");
test_control_return(0);
return;
diff --git a/test/regression/usbx_uxe_host_gser_test.c b/test/regression/usbx_uxe_host_gser_test.c
index 4862f4cd0..507bc1b6c 100644
--- a/test/regression/usbx_uxe_host_gser_test.c
+++ b/test/regression/usbx_uxe_host_gser_test.c
@@ -8,6 +8,7 @@
/* */
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+// Portions of this file were generated with AI assistance.
/* This test is designed to test the ux_utility_descriptor_pack. */
@@ -65,7 +66,7 @@ CHAR *memory_pointer;
/* Inform user. */
printf("Running uxe_host_gser APIs Test..................................... ");
#if !defined(UX_HOST_CLASS_GSER_ENABLE_ERROR_CHECKING)
-#warning Tests skipped due to compile option!
+#pragma message("warning: Tests skipped due to compile option!")
printf("SKIP SUCCESS!\n");
test_control_return(0);
return;
diff --git a/test/regression/usbx_uxe_host_hid_test.c b/test/regression/usbx_uxe_host_hid_test.c
index ad89b9813..bcbc03bf4 100644
--- a/test/regression/usbx_uxe_host_hid_test.c
+++ b/test/regression/usbx_uxe_host_hid_test.c
@@ -8,6 +8,7 @@
/* */
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+// Portions of this file were generated with AI assistance.
/* This test is designed to test the ux_utility_descriptor_pack. */
@@ -79,7 +80,7 @@ CHAR *memory_pointer;
!defined(UX_DEVICE_CLASS_HID_KEYBOARD_ENABLE_ERROR_CHECKING) ||\
!defined(UX_DEVICE_CLASS_HID_MOUSE_ENABLE_ERROR_CHECKING) ||\
!defined(UX_DEVICE_CLASS_HID_REMOTE_CONTROL_ENABLE_ERROR_CHECKING)
-#warning Tests skipped due to compile option!
+#pragma message("warning: Tests skipped due to compile option!")
printf("SKIP SUCCESS!\n");
test_control_return(0);
return;
diff --git a/test/regression/usbx_uxe_host_pima_test.c b/test/regression/usbx_uxe_host_pima_test.c
index e22a69fb5..5f61ddd4a 100644
--- a/test/regression/usbx_uxe_host_pima_test.c
+++ b/test/regression/usbx_uxe_host_pima_test.c
@@ -8,6 +8,7 @@
/* */
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+/* Portions of this file were generated with AI assistance. */
/* This test is designed to test the ux_utility_descriptor_pack. */
@@ -64,7 +65,7 @@ CHAR *memory_pointer;
/* Inform user. */
printf("Running uxe_host_pima APIs Test.................................... ");
#if !defined(UX_HOST_CLASS_PIMA_ENABLE_ERROR_CHECKING)
-#warning Tests skipped due to compile option!
+#pragma message("warning: Tests skipped due to compile option!")
printf("SKIP SUCCESS!\n");
test_control_return(0);
return;
@@ -105,6 +106,7 @@ UINT status;
UX_HOST_CLASS_PIMA dummy_pima_inst;
UX_HOST_CLASS_PIMA *dummy_pima = &dummy_pima_inst;
UX_HOST_CLASS_PIMA_SESSION pima_session;
+UX_HOST_CLASS_PIMA_DEVICE pima_device;
UCHAR object_buffer[64];
UX_HOST_CLASS_PIMA_OBJECT object;
ULONG object_actual_length;
@@ -113,7 +115,7 @@ UX_HOST_CLASS_PIMA_STORAGE storage;
ULONG object_handles_array[32];
/* Unit test for function ux_host_class_pima_device_info_get() */
- status = ux_host_class_pima_device_info_get(NX_NULL, &pima_session);
+ status = ux_host_class_pima_device_info_get(NX_NULL, &pima_device);
UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status);
status = ux_host_class_pima_device_info_get(dummy_pima, NX_NULL);
diff --git a/test/regression/usbx_uxe_host_printer_test.c b/test/regression/usbx_uxe_host_printer_test.c
index 77d961956..4a752b29d 100644
--- a/test/regression/usbx_uxe_host_printer_test.c
+++ b/test/regression/usbx_uxe_host_printer_test.c
@@ -8,6 +8,7 @@
/* */
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+// Portions of this file were generated with AI assistance.
/* This test is designed to test the ux_utility_descriptor_pack. */
@@ -65,7 +66,7 @@ CHAR *memory_pointer;
/* Inform user. */
printf("Running uxe_host_printer APIs Test.................................... ");
#if !defined(UX_HOST_CLASS_PRINTER_ENABLE_ERROR_CHECKING)
-#warning Tests skipped due to compile option!
+#pragma message("warning: Tests skipped due to compile option!")
printf("SKIP SUCCESS!\n");
test_control_return(0);
return;
diff --git a/test/regression/usbx_uxe_host_prolific_test.c b/test/regression/usbx_uxe_host_prolific_test.c
index 1967bcf30..d56c325e7 100644
--- a/test/regression/usbx_uxe_host_prolific_test.c
+++ b/test/regression/usbx_uxe_host_prolific_test.c
@@ -8,6 +8,7 @@
/* */
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+// Portions of this file were generated with AI assistance.
/* This test is designed to test the ux_utility_descriptor_pack. */
@@ -65,7 +66,7 @@ CHAR *memory_pointer;
/* Inform user. */
printf("Running uxe_host_prolific APIs Test................................. ");
#if !defined(UX_HOST_CLASS_PROLIFIC_ENABLE_ERROR_CHECKING)
-#warning Tests skipped due to compile option!
+#pragma message("warning: Tests skipped due to compile option!")
printf("SKIP SUCCESS!\n");
test_control_return(0);
return;
diff --git a/test/regression/usbx_uxe_host_stack_test.c b/test/regression/usbx_uxe_host_stack_test.c
index 175b3c854..43b357326 100644
--- a/test/regression/usbx_uxe_host_stack_test.c
+++ b/test/regression/usbx_uxe_host_stack_test.c
@@ -8,6 +8,7 @@
/* */
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+// Portions of this file were generated with AI assistance.
/* This test is designed to test the ux_utility_descriptor_pack. */
@@ -75,7 +76,7 @@ CHAR *memory_pointer;
/* Inform user. */
printf("Running uxe_system APIs Test........................................ ");
#if !defined(UX_DEVICE_CLASS_AUDIO_ENABLE_ERROR_CHECKING)
-#warning Tests skipped due to compile option!
+#pragma message("warning: Tests skipped due to compile option!")
printf("SKIP SUCCESS!\n");
test_control_return(0);
return;
diff --git a/test/regression/usbx_uxe_host_storage_test.c b/test/regression/usbx_uxe_host_storage_test.c
index 490509ab3..563330696 100644
--- a/test/regression/usbx_uxe_host_storage_test.c
+++ b/test/regression/usbx_uxe_host_storage_test.c
@@ -8,6 +8,7 @@
/* */
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+// Portions of this file were generated with AI assistance.
/* This test is designed to test the ux_utility_descriptor_pack. */
@@ -65,7 +66,7 @@ CHAR *memory_pointer;
/* Inform user. */
printf("Running uxe_host_storage APIs Test.................................... ");
#if !defined(UX_HOST_CLASS_STORAGE_ENABLE_ERROR_CHECKING)
-#warning Tests skipped due to compile option!
+#pragma message("warning: Tests skipped due to compile option!")
printf("SKIP SUCCESS!\n");
test_control_return(0);
return;
diff --git a/test/regression/usbx_uxe_host_swar_test.c b/test/regression/usbx_uxe_host_swar_test.c
index 3deddddf0..7ef0a232e 100644
--- a/test/regression/usbx_uxe_host_swar_test.c
+++ b/test/regression/usbx_uxe_host_swar_test.c
@@ -8,6 +8,7 @@
/* */
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+// Portions of this file were generated with AI assistance.
/* This test is designed to test the ux_utility_descriptor_pack. */
@@ -65,7 +66,7 @@ CHAR *memory_pointer;
/* Inform user. */
printf("Running uxe_host_swar APIs Test..................................... ");
#if !defined(UX_HOST_CLASS_SWAR_ENABLE_ERROR_CHECKING)
-#warning Tests skipped due to compile option!
+#pragma message("warning: Tests skipped due to compile option!")
printf("SKIP SUCCESS!\n");
test_control_return(0);
return;
diff --git a/test/regression/usbx_uxe_host_video_test.c b/test/regression/usbx_uxe_host_video_test.c
index 23d4ef114..9338a1392 100644
--- a/test/regression/usbx_uxe_host_video_test.c
+++ b/test/regression/usbx_uxe_host_video_test.c
@@ -8,6 +8,7 @@
/* */
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+/* Portions of this file were generated with AI assistance. */
/* This test is designed to test the ux_utility_descriptor_pack. */
@@ -64,7 +65,7 @@ CHAR *memory_pointer;
/* Inform user. */
printf("Running uxe_host_video APIs Test.................................... ");
#if !defined(UX_HOST_CLASS_VIDEO_ENABLE_ERROR_CHECKING)
-#warning Tests skipped due to compile option!
+#pragma message("warning: Tests skipped due to compile option!")
printf("SKIP SUCCESS!\n");
test_control_return(0);
return;
@@ -105,6 +106,7 @@ UINT status;
UX_HOST_CLASS_VIDEO dummy_video_inst;
UX_HOST_CLASS_VIDEO *dummy_video = &dummy_video_inst;
UCHAR dummy_buffer[64];
+UCHAR *buffer = dummy_buffer;
UX_HOST_CLASS_VIDEO_CONTROL dummy_video_control;
UX_HOST_CLASS_VIDEO_TRANSFER_REQUEST dummy_video_request;
ULONG max_payload = 0xff;
@@ -160,11 +162,11 @@ ULONG max_payload = 0xff;
UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status);
/* ux_host_class_video_transfer_buffers_add() */
- status = ux_host_class_video_transfer_buffers_add(UX_NULL, &dummy_buffer, 1);
+ status = ux_host_class_video_transfer_buffers_add(UX_NULL, &buffer, 1);
UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status);
status = ux_host_class_video_transfer_buffers_add(dummy_video, UX_NULL, 1);
UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status);
- status = ux_host_class_video_transfer_buffers_add(dummy_video, &dummy_buffer, 0);
+ status = ux_host_class_video_transfer_buffers_add(dummy_video, &buffer, 0);
UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status);
/* ux_host_class_video_transfer_callback_set() */
diff --git a/test/regression/usbx_uxe_system_test.c b/test/regression/usbx_uxe_system_test.c
index 2ac99c7b9..05a32a92e 100644
--- a/test/regression/usbx_uxe_system_test.c
+++ b/test/regression/usbx_uxe_system_test.c
@@ -8,6 +8,7 @@
/* */
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+// Portions of this file were generated with AI assistance.
/* This test is designed to test the ux_utility_descriptor_pack. */
@@ -72,7 +73,7 @@ CHAR *memory_pointer;
/* Inform user. */
printf("Running uxe_system APIs Test........................................ ");
#if !defined(UX_DEVICE_CLASS_AUDIO_ENABLE_ERROR_CHECKING)
-#warning Tests skipped due to compile option!
+#pragma message("warning: Tests skipped due to compile option!")
printf("SKIP SUCCESS!\n");
test_control_return(0);
return;
diff --git a/test/regression/ux_host_class_dummy.c b/test/regression/ux_host_class_dummy.c
index 1bfea99fa..86b07e3b0 100644
--- a/test/regression/ux_host_class_dummy.c
+++ b/test/regression/ux_host_class_dummy.c
@@ -9,12 +9,20 @@
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+// Portions of this file were generated with AI assistance.
+
#include "ux_test.h"
#include "ux_api.h"
#include "ux_host_class_dummy.h"
#include "ux_host_stack.h"
+/* Overridable deactivation wait so the Win64 simulator can reduce
+ the 200-tick default without affecting Linux/hardware targets. */
+#ifndef UX_TEST_DUMMY_DEACTIVATE_WAIT
+#define UX_TEST_DUMMY_DEACTIVATE_WAIT UX_ENUMERATION_THREAD_WAIT
+#endif
+
static UINT _ux_host_class_dummy_activate(UX_HOST_CLASS_COMMAND *command);
static UINT _ux_host_class_dummy_deactivate(UX_HOST_CLASS_COMMAND *command);
@@ -217,7 +225,7 @@ UX_ENDPOINT *endpoint;
}
/* If the class instance was busy, let it finish properly and not return. */
- _ux_host_thread_sleep(UX_ENUMERATION_THREAD_WAIT);
+ _ux_host_thread_sleep(UX_TEST_DUMMY_DEACTIVATE_WAIT);
/* Destroy the instance. */
_ux_host_stack_class_instance_destroy(dummy -> ux_host_class_dummy_class, (VOID *) dummy);
@@ -347,7 +355,7 @@ UX_ENDPOINT *endpoint;
}
/* If the class instance was busy, let it finish properly and not return. */
- _ux_host_thread_sleep(UX_ENUMERATION_THREAD_WAIT);
+ _ux_host_thread_sleep(UX_TEST_DUMMY_DEACTIVATE_WAIT);
/* Destroy the instance. */
_ux_host_stack_class_instance_destroy(dummy -> ux_host_class_dummy_class, (VOID *) dummy);
diff --git a/test/regression/ux_test.c b/test/regression/ux_test.c
index f8cfdc110..c6cff1288 100644
--- a/test/regression/ux_test.c
+++ b/test/regression/ux_test.c
@@ -8,11 +8,21 @@
/* */
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+// Portions of this file were generated with AI assistance.
-#include "ux_test.h"
+#include "ux_test.h"
#include "ux_test_hcd_sim_host.h"
#include "ux_test_dcd_sim_slave.h"
+/* Scale factor for tick-based timeouts in ux_test_sleep_break_if().
+ On ports where ThreadX ticks advance faster than 1ms/tick (e.g. Win64 with
+ tick batching TX_WIN32_TICKS_PER_INTERRUPT=5), set this to the batch factor
+ so that ux_test_sleep_break_if(N, ...) waits N*scale ticks — the same real
+ time as N ticks would give on Linux (1ms/tick). */
+#ifndef UX_TEST_TICK_SCALE
+#define UX_TEST_TICK_SCALE 1
+#endif
+
#define UX_TEST_TIMEOUT_MS 3000
static UX_TEST_ACTION ux_test_action_handler_check(UX_TEST_ACTION *action, UX_TEST_FUNCTION usbx_function, void *params, UCHAR advance);
@@ -1312,7 +1322,7 @@ UINT status;
}
}
t1 = tx_time_get();
- if (_ux_utility_time_elapsed(t0, t1) >= tick)
+ if (_ux_utility_time_elapsed(t0, t1) >= (tick * UX_TEST_TICK_SCALE))
{
return(UX_TIMEOUT);
}
diff --git a/test/regression/ux_test_hcd_sim_host.c b/test/regression/ux_test_hcd_sim_host.c
index 04f18a6ed..8071d0ae2 100644
--- a/test/regression/ux_test_hcd_sim_host.c
+++ b/test/regression/ux_test_hcd_sim_host.c
@@ -9,11 +9,26 @@
/* SPDX-License-Identifier: MIT */
/***************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/* This test simulator is designed to simulate ux_hcd_ APIs for test. */
#include "tx_api.h"
#include "tx_thread.h"
+/* Number of ticks for enum thread to process connect/disconnect.
+ Override via compile flags for ports where ticks fire faster than 1ms
+ (e.g. Win64 tick batching with TX_WIN32_TICKS_PER_INTERRUPT=5).
+ Connect sleep must be long enough for full enumeration to complete.
+ Disconnect sleep must be short enough that device structures are not
+ freed before tests that intentionally use them after disconnect. */
+#ifndef UX_TEST_HCD_CONNECT_SLEEP
+#define UX_TEST_HCD_CONNECT_SLEEP 100
+#endif
+#ifndef UX_TEST_HCD_DISCONNECT_SLEEP
+#define UX_TEST_HCD_DISCONNECT_SLEEP 100
+#endif
+
#include "ux_api.h"
#include "ux_hcd_sim_host.h"
@@ -74,7 +89,7 @@ VOID ux_test_hcd_sim_host_disconnect(VOID)
#else
/* Sleep current thread for enum thread to run. */
- tx_thread_sleep(100);
+ tx_thread_sleep(UX_TEST_HCD_DISCONNECT_SLEEP);
#endif
}
@@ -133,7 +148,7 @@ VOID ux_test_hcd_sim_host_connect(ULONG speed)
ux_test_hcd_sim_host_connect_no_wait(speed);
/* Sleep current thread for enum thread to run. */
- tx_thread_sleep(100);
+ tx_thread_sleep(UX_TEST_HCD_CONNECT_SLEEP);
}
/* Fork and modify _ux_hcd_sim_host_port_status_get. */