diff --git a/.github/workflows/regression_test.yml b/.github/workflows/regression_test.yml new file mode 100644 index 00000000..e725c77d --- /dev/null +++ b/.github/workflows/regression_test.yml @@ -0,0 +1,61 @@ +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 + default: 'default_build_coverage' + skip_coverage: + required: false + type: boolean + default: false + coverage_name: + required: false + default: 'default_build_coverage' + push: + branches: [ master ] + pull_request: + branches: [ master ] + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + + manual_tests: + if: github.event_name == 'workflow_dispatch' + permissions: + contents: read + issues: read + checks: write + pull-requests: write + pages: write + id-token: write + + uses: azure-rtos/threadx/.github/workflows/regression_template.yml@master + 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 }} + + auto_tests: + if: github.event_name != 'workflow_dispatch' + permissions: + contents: read + issues: read + checks: write + pull-requests: write + pages: write + id-token: write + + uses: azure-rtos/threadx/.github/workflows/regression_template.yml@master + with: + cmake_path: ./test/cmake/usbx + build_script: ./scripts/build.sh default_build_coverage + test_script: ./scripts/test.sh default_build_coverage + coverage_name: default_build_coverage + skip_coverage: false diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 00000000..7fdbcb10 --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,2 @@ +#!/bin/bash +$(dirname `realpath $0`)/../test/cmake/usbx/run.sh build $@ diff --git a/scripts/install.sh b/scripts/install.sh new file mode 100755 index 00000000..fed99714 --- /dev/null +++ b/scripts/install.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# +# 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 diff --git a/scripts/test.sh b/scripts/test.sh new file mode 100755 index 00000000..109b9e2c --- /dev/null +++ b/scripts/test.sh @@ -0,0 +1,2 @@ +#!/bin/bash +CTEST_PARALLEL_LEVEL=4 $(dirname `realpath $0`)/../test/cmake/usbx/run.sh test $@ diff --git a/test/cmake/libs/CMakeLists.txt b/test/cmake/libs/CMakeLists.txt new file mode 100644 index 00000000..f66a8d25 --- /dev/null +++ b/test/cmake/libs/CMakeLists.txt @@ -0,0 +1,37 @@ +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() diff --git a/test/cmake/libs/nx_user.h b/test/cmake/libs/nx_user.h new file mode 100644 index 00000000..bf9ea058 --- /dev/null +++ b/test/cmake/libs/nx_user.h @@ -0,0 +1,87 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#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/CMakeLists.txt b/test/cmake/usbx/CMakeLists.txt new file mode 100644 index 00000000..dc9f5127 --- /dev/null +++ b/test/cmake/usbx/CMakeLists.txt @@ -0,0 +1,437 @@ +cmake_minimum_required(VERSION 3.13 FATAL_ERROR) +cmake_policy(SET CMP0054 NEW) +cmake_policy(SET CMP0057 NEW) +cmake_policy(SET CMP0077 NEW) + +project(usbx_test LANGUAGES C) + +# Use customized ux_user.h +set(UX_USER_FILE ${CMAKE_CURRENT_SOURCE_DIR}/ux_user.h) + +# Copy files instead of using symlink +# libs/ -> ../libs/ +file(MAKE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/libs) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../libs/CMakeLists.txt + ${CMAKE_CURRENT_SOURCE_DIR}/libs/CMakeLists.txt COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../libs/nx_user.h + ${CMAKE_CURRENT_SOURCE_DIR}/libs/nx_user.h COPYONLY) + +# Set build configurations +# TODO: add when available : standalone_otg_build +set(BUILD_CONFIGURATIONS + 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 + ) + +set(CMAKE_CONFIGURATION_TYPES + ${BUILD_CONFIGURATIONS} + CACHE STRING "list of supported configuration types" FORCE) +set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + ${CMAKE_CONFIGURATION_TYPES}) +list(GET CMAKE_CONFIGURATION_TYPES 0 BUILD_TYPE) +if((NOT CMAKE_BUILD_TYPE) OR (NOT ("${CMAKE_BUILD_TYPE}" IN_LIST + CMAKE_CONFIGURATION_TYPES))) + set(CMAKE_BUILD_TYPE + "${BUILD_TYPE}" + CACHE STRING "Build Type of the project" FORCE) +endif() + +message(STATUS "Build for usbx") +message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") +message(STATUS "Using toolchain file: ${CMAKE_TOOLCHAIN_FILE}.") + +set(default_build_coverage + -DNX_PHYSICAL_HEADER=20 +# -DUX_SLAVE_REQUEST_CONTROL_MAX_LENGTH=512 +# -DUX_DEVICE_BIDIRECTIONAL_ENDPOINT_SUPPORT +# -DUX_HOST_DEVICE_CLASS_CODE_VALIDATION_ENABLE +# -DUX_DEVICE_CLASS_HID_INTERRUPT_OUT_SUPPORT +# -DUX_HOST_CLASS_HID_INTERRUPT_OUT_SUPPORT + -DUX_DISABLE_ASSERT +##############################################FeedBack Test Start +# -DUX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT +# -DUX_MAX_DEVICE_ENDPOINTS=6 +# -DUX_DEVICE_BIDIRECTIONAL_ENDPOINT_SUPPORT +# -DUX_SLAVE_REQUEST_CONTROL_MAX_LENGTH=512 +##############################################FeedBack Test end + # -DUX_HOST_CLASS_AUDIO_2_SUPPORT + # -DUX_HOST_CLASS_AUDIO_FEEDBACK_SUPPORT + # -DUX_HOST_CLASS_AUDIO_DISABLE_CONTROLS + # -DUX_HOST_CLASS_AUDIO_INTERRUPT_SUPPORT + # -DUX_DEVICE_CLASS_PRINTER_WRITE_AUTO_ZLP + # -DUX_DEVICE_CLASS_CDC_ACM_WRITE_AUTO_ZLP + # -DUX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT + -DUX_HOST_STACK_CONFIGURATION_INSTANCE_CREATE_CONTROL=0 + -DUX_DEVICE_ENABLE_GET_STRING_WITH_ZERO_LANGUAGE_ID +) + +set(error_check_build_full_coverage + ${default_build_coverage} + -DUX_ENABLE_ASSERT + -DUX_ENABLE_ERROR_CHECKING + -DUX_PIMA_WITH_MTP_SUPPORT +) + +set(msrc_rtos_build + ${error_check_build_full_coverage} + -DUX_SLAVE_REQUEST_CONTROL_MAX_LENGTH=512 + -DUX_HOST_CLASS_AUDIO_2_SUPPORT + -DUX_HOST_CLASS_AUDIO_INTERRUPT_SUPPORT +) +set(msrc_standalone_build + ${msrc_rtos_build} + -DUX_STANDALONE +) + +set(tracex_enable_build + -DNX_PHYSICAL_HEADER=20 + -DTX_ENABLE_EVENT_TRACE + -DUX_TRACE_INSERT_MACROS +) + +set(device_buffer_owner_build + -DNX_PHYSICAL_HEADER=20 +# -DUX_ENABLE_ASSERT + -DTX_ENABLE_EVENT_TRACE + -DUX_TRACE_INSERT_MACROS + -DUX_SLAVE_REQUEST_CONTROL_MAX_LENGTH=512 + -DUX_DEVICE_ENDPOINT_BUFFER_OWNER=1 + # -DUX_DEVICE_CLASS_CDC_ACM_TRANSMISSION_DISABLE + -DUX_DEVICE_CLASS_HID_INTERRUPT_OUT_SUPPORT + -DUX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT + -DUX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT +) +set(device_zero_copy_build + ${device_buffer_owner_build} + -DUX_DEVICE_CLASS_CDC_ACM_ZERO_COPY + -DUX_DEVICE_CLASS_CDC_ACM_WRITE_AUTO_ZLP + -DUX_DEVICE_CLASS_HID_ZERO_COPY + -DUX_DEVICE_CLASS_CDC_ECM_ZERO_COPY + -DUX_DEVICE_CLASS_RNDIS_ZERO_COPY + -DUX_DEVICE_CLASS_PRINTER_ZERO_COPY +) + +set(nofx_build_coverage + -DNX_PHYSICAL_HEADER=20 + -DUX_HOST_CLASS_STORAGE_NO_FILEX +) +set(standalone_build_coverage + -DNX_PHYSICAL_HEADER=20 + -DUX_STANDALONE + # -DTX_ENABLE_EVENT_TRACE +) +set(standalone_device_build_coverage + -DUX_DEVICE_STANDALONE + # -DUX_DEVICE_CLASS_HID_INTERRUPT_OUT_SUPPORT + -DUX_SLAVE_REQUEST_CONTROL_MAX_LENGTH=512 +##############################################FeedBack Test Start +# -DUX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT +# -DUX_MAX_DEVICE_ENDPOINTS=6 +# -DUX_DEVICE_BIDIRECTIONAL_ENDPOINT_SUPPORT +##############################################FeedBack Test End +# -DUX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT + -DUX_ENABLE_ERROR_CHECKING +) +set(standalone_device_buffer_owner_build + ${device_buffer_owner_build} + ${standalone_device_build_coverage} +) +set(standalone_device_zero_copy_build + ${device_zero_copy_build} + ${standalone_device_build_coverage} +) +set(standalone_host_build_coverage + -DUX_HOST_STANDALONE + # -DUX_HOST_CLASS_HID_INTERRUPT_OUT_SUPPORT + -DUX_ENABLE_ERROR_CHECKING +) +set(standalone_otg_build + -DUX_OTG_STANDALONE +) +set(optimized_build + -DNX_PHYSICAL_HEADER=20 + -DUX_NAME_REFERENCED_BY_POINTER + -DUX_MAX_HCD=1 + -DUX_MAX_ISO_TD=0 + -DUX_MAX_TD=20 + -DUX_MAX_CLASS_DRIVER=1 + -DUX_MAX_DEVICES=1 + -DUX_HOST_CLASS_STORAGE_MEMORY_BUFFER_SIZE=512 + -DUX_HOST_CLASS_STORAGE_MAX_TRANSFER_SIZE=512 + -DUX_HOST_CLASS_STORAGE_MAX_MEDIA=1 + -DUX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE + -DUX_MAX_DEVICE_ENDPOINTS=2 + -DUX_MAX_DEVICE_INTERFACES=1 + -DUX_MAX_SLAVE_INTERFACES=1 + -DUX_MAX_SLAVE_CLASS_DRIVER=1 + -DUX_MAX_SLAVE_LUN=1 + -DUX_SLAVE_REQUEST_DATA_MAX_LENGTH=512 + -DUX_DEVICE_ALTERNATE_SETTING_SUPPORT_DISABLE +) +set(generic_build + -DUX_HCD_EHCI_SPLIT_TRANSFER_ENABLE + -DUX_HOST_CLASS_STORAGE_INCLUDE_LEGACY_PROTOCOL_SUPPORT + -DUX_SLAVE_CLASS_STORAGE_INCLUDE_MMC + ############################################## warning check: CDC ACM + -DUX_DEVICE_CLASS_CDC_ACM_TRANSMISSION_DISABLE + ############################################## warning check: DFU + # -DUX_DEVICE_CLASS_DFU_UPLOAD_DISABLE + # -DUX_DEVICE_CLASS_DFU_ERROR_GET_ENABLE + -DUX_DEVICE_CLASS_DFU_STATUS_MODE=1 #0/1 + -DUX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT=0 + # -DUX_DEVICE_CLASS_DFU_CUSTOM_REQUEST_ENABLE + -DUX_HOST_STACK_CONFIGURATION_INSTANCE_CREATE_CONTROL=1 +) +set(otg_support_build + -DNX_PHYSICAL_HEADER=20 + -DUX_OTG_SUPPORT= +) +set(memory_management_build_coverage + ${default_build_coverage} + -DUX_ENFORCE_SAFE_ALIGNMENT + -DUX_ENABLE_MEMORY_STATISTICS + -DUX_ENABLE_MEMORY_POOL_SANITY_CHECK +) +# Control if USBX is static or shared +if($ENV{USBX_STATIC}) + message(STATUS "Building STATIC usbx") + set(BUILD_SHARED_LIBS OFF) +else() + message(STATUS "Building usbx BUILD_SHARED_LIBS: ${BUILD_SHARED_LIBS}") +endif() +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}}) + +enable_testing() + +add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../../../ usbx) +if(CMAKE_BUILD_TYPE STREQUAL "generic_build") + add_test(fake_test true) +else() + add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/regression regression) +endif() + +# TODO: Unmask after adding sample for STANDALONE +if(NOT (CMAKE_BUILD_TYPE MATCHES "standalone.*")) + add_subdirectory(../usbx/samples samples) +endif() + +# Coverage +if(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 + -DFX_ENABLE_EXFAT) + +# Remove includes and files not needed from usbx build +set(UX_STANDALONE_HOST_EXCLUDES + # ux_host_class_asix + # ux_host_class_audio + # ux_host_class_cdc_acm + # ux_host_class_cdc_ecm + # ux_host_class_gser + # ux_host_class_hid + # ux_host_class_hub + # ux_host_class_pima + # ux_host_class_printer + # ux_host_class_prolific + # ux_host_class_storage + # ux_host_class_swar + # ux_host_class_video + # ux_hcd_ehci + # ux_hcd_ohci +) +set(UX_STANDALONE_DEVICE_EXCLUDES + # ux_device_class_audio + # ux_device_class_cdc_acm + # ux_device_class_cdc_ecm + # ux_device_class_dfu + # ux_device_class_hid + # ux_device_class_pima + # ux_device_class_rndis + # ux_device_class_ccid + # ux_device_class_printer + # ux_device_class_video +) +set(UX_STANDALONE_UTILITY_EXCLUDES + # ux_utility_event + # ux_utility_delay + # ux_utility_mutex + # ux_utility_semaphore + # ux_utility_thread + # ux_utility_timer +) +set(UX_STANDALONE_PICTBRIDGE_EXCLUDES + # ux_pictbridge +) +set(UX_STANDALONE_NX_EXCLUDES + # ux_network_driver +) +set(UX_STANDALONE_FX_EXCLUDES + # ux_host_class_storage_driver_entry + usbx_ux_host_class_storage_fx_driver +) +if(CMAKE_BUILD_TYPE MATCHES "standalone.*") + get_target_property(test_utility_SOURCES_LIST test_utility SOURCES) + get_target_property(SOURCES_LIST usbx SOURCES) + get_target_property(INCLUDES_LIST usbx INCLUDE_DIRECTORIES) + + if("${CMAKE_BUILD_TYPE}" STREQUAL "standalone_build_coverage") + # TODO: enable when STANDALONE implement is done + # Remove files not support STANDALONE yet + foreach(EXCLUDE_VAL ${UX_STANDALONE_HOST_EXCLUDES} + ${UX_STANDALONE_DEVICE_EXCLUDES} + ${UX_STANDALONE_UTILITY_EXCLUDES} + ${UX_STANDALONE_PICTBRIDGE_EXCLUDES} + ${UX_STANDALONE_NX_EXCLUDES} + ${UX_STANDALONE_FX_EXCLUDES}) + list(FILTER test_utility_SOURCES_LIST EXCLUDE REGEX ".*${EXCLUDE_VAL}.*") + list(FILTER SOURCES_LIST EXCLUDE REGEX ".*${EXCLUDE_VAL}.*") + endforeach() + # Update includes to remove TX,FX,NX libs + list(FILTER INCLUDES_LIST EXCLUDE REGEX ".*externals.*") + list(FILTER INCLUDES_LIST EXCLUDE REGEX ".*/libs/inc.*") + # Update library links to remove TX,FX,NX libs + set_target_properties(usbx PROPERTIES LINK_LIBRARIES "") + set_target_properties(usbx PROPERTIES INTERFACE_LINK_LIBRARIES "") + + elseif("${CMAKE_BUILD_TYPE}" STREQUAL "standalone_device_build_coverage") + # Only device part linked with STANDALONE + # Remove files not support STANDALONE yet + foreach(EXCLUDE_VAL ${UX_STANDALONE_DEVICE_EXCLUDES}) + list(FILTER SOURCES_LIST EXCLUDE REGEX ".*${EXCLUDE_VAL}.*") + list(FILTER test_utility_SOURCES_LIST EXCLUDE REGEX ".*${EXCLUDE_VAL}.*") + endforeach() + + elseif("${CMAKE_BUILD_TYPE}" STREQUAL "standalone_host_build_coverage") + # Only host part linked with STANDALONE + # Remove files not support STANDALONE yet + foreach(EXCLUDE_VAL ${UX_STANDALONE_HOST_EXCLUDES}) + list(FILTER SOURCES_LIST EXCLUDE REGEX ".*${EXCLUDE_VAL}.*") + list(FILTER test_utility_SOURCES_LIST EXCLUDE REGEX ".*${EXCLUDE_VAL}.*") + endforeach() + + elseif("${CMAKE_BUILD_TYPE}" STREQUAL "standalone_otg_build") + # Only some stack file linked with STANDALONE + # No file list change for now + endif() + + # Commit sources and includes changes + set_target_properties(test_utility PROPERTIES SOURCES "${test_utility_SOURCES_LIST}") + set_target_properties(usbx PROPERTIES SOURCES "${SOURCES_LIST}") + set_target_properties(usbx PROPERTIES INCLUDE_DIRECTORIES "${INCLUDES_LIST}") +endif() + +# Remove files not compatible with optimized build +set(UX_OPTIMIZED_EXCLUDES + ux_device_class_rndis # buffer smaller than message size +) +if(CMAKE_BUILD_TYPE STREQUAL "optimized_build") + get_target_property(test_utility_SOURCES_LIST test_utility SOURCES) + get_target_property(SOURCES_LIST usbx SOURCES) + + # Remove files not support STANDALONE yet + foreach(EXCLUDE_VAL ${UX_OPTIMIZED_EXCLUDES}) + list(FILTER test_utility_SOURCES_LIST EXCLUDE REGEX ".*${EXCLUDE_VAL}.*") + list(FILTER SOURCES_LIST EXCLUDE REGEX ".*${EXCLUDE_VAL}.*") + endforeach() + + # Commit sources and includes changes + set_target_properties(test_utility PROPERTIES SOURCES "${test_utility_SOURCES_LIST}") + set_target_properties(usbx PROPERTIES SOURCES "${SOURCES_LIST}") +endif() + +# Use generic port file for generic build. +if(CMAKE_BUILD_TYPE STREQUAL "generic_build") + get_target_property(INCLUDES_LIST usbx INCLUDE_DIRECTORIES) + set(NEW_INCLUDES_LIST "") + foreach(INCLUDE_LIST ${INCLUDES_LIST}) + string(REPLACE "ports/linux/gnu" "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 diff --git a/test/cmake/usbx/coverage.sh b/test/cmake/usbx/coverage.sh new file mode 100755 index 00000000..f5f30c71 --- /dev/null +++ b/test/cmake/usbx/coverage.sh @@ -0,0 +1,124 @@ +#!/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 diff --git a/test/cmake/usbx/regression/CMakeLists.txt b/test/cmake/usbx/regression/CMakeLists.txt new file mode 100644 index 00000000..fe3cb6f8 --- /dev/null +++ b/test/cmake/usbx/regression/CMakeLists.txt @@ -0,0 +1,740 @@ +cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR) +cmake_policy(SET CMP0057 NEW) + +project(regression_test LANGUAGES C) + +get_filename_component(SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../regression + ABSOLUTE) + +set(ux_class_dfu_test_cases + ${SOURCE_DIR}/usbx_device_dfu_basic_test.c + ${SOURCE_DIR}/usbx_uxe_device_dfu_test.c +) + +set(ux_class_hub_test_cases + ${SOURCE_DIR}/usbx_host_class_hub_port_change_connection_process_coverage_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hub_descriptor_get_coverage_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hub_status_get_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hub_transfer_request_completed_test.c + ${SOURCE_DIR}/usbx_hub_hub_status_get_invalid_length_test.c + ${SOURCE_DIR}/usbx_hub_no_power_switching_test.c + ${SOURCE_DIR}/usbx_hub_get_hub_status_fails_during_port_reset_test.c + ${SOURCE_DIR}/usbx_hub_port_never_reset_test.c + ${SOURCE_DIR}/usbx_hub_port_change_reset_test.c + ${SOURCE_DIR}/usbx_hub_port_change_over_current_test.c + ${SOURCE_DIR}/usbx_hub_port_change_suspend_test.c + ${SOURCE_DIR}/usbx_hub_get_hub_status_fails_during_hub_device_enum_test.c + ${SOURCE_DIR}/usbx_hub_basic_test.c + ${SOURCE_DIR}/usbx_hub_basic_memory_test.c + ${SOURCE_DIR}/usbx_hub_get_status_fails_during_configuration_test.c + ${SOURCE_DIR}/usbx_hub_invalid_hub_descriptor_length_test.c + ${SOURCE_DIR}/usbx_bus_powered_hub_conn_to_self_and_bus_powered_hub_test.c + ${SOURCE_DIR}/usbx_hub_full_speed_hub_test.c + ${SOURCE_DIR}/usbx_hub_multiple_tt_test.c + ${SOURCE_DIR}/usbx_hub_invalid_device_protocol_test.c + ${SOURCE_DIR}/usbx_hub_request_to_hub_itself_test.c + ${SOURCE_DIR}/usbx_hub_single_tt_too_many_hub_ports_test.c + ${SOURCE_DIR}/usbx_hub_multiple_tt_too_many_hub_ports_test.c + ${SOURCE_DIR}/usbx_hub_no_endpoints_test.c + ${SOURCE_DIR}/usbx_hub_interrupt_out_endpoint_test.c + ${SOURCE_DIR}/usbx_hub_non_interrupt_in_endpoint_test.c + ${SOURCE_DIR}/usbx_hub_hub_device_connect_test.c + ${SOURCE_DIR}/usbx_hub_hub_device_disconnect_test.c + ${SOURCE_DIR}/usbx_hub_quick_hub_device_reconnection_test.c + ${SOURCE_DIR}/usbx_hub_hub_device_enumeration_keeps_failing_test.c + ${SOURCE_DIR}/usbx_hub_port_reset_fails_during_hub_device_enum_test.c + ${SOURCE_DIR}/usbx_hub_get_port_status_fails_during_hub_device_enum_test.c + ${SOURCE_DIR}/usbx_hub_low_speed_hub_device_test.c + ${SOURCE_DIR}/usbx_hub_full_speed_hub_device_test.c + ${SOURCE_DIR}/usbx_hub_quick_hub_device_disconnection_test.c + ${SOURCE_DIR}/usbx_hub_port_change_enable_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hub_entry_test.c) + +set(ux_class_hub_standalone_test_cases + ${SOURCE_DIR}/usbx_hub_basic_test.c + ${SOURCE_DIR}/usbx_hub_basic_memory_test.c +) + +set(ux_class_audio_test_cases + ${SOURCE_DIR}/usbx_audio10_device_basic_test.c + ${SOURCE_DIR}/usbx_audio10_device_feedback_test.c + ${SOURCE_DIR}/usbx_audio10_iad_device_basic_test.c + ${SOURCE_DIR}/usbx_audio10_iad_device_control_test.c + ${SOURCE_DIR}/usbx_audio10_iad_device_interrupt_test.c + ${SOURCE_DIR}/usbx_audio20_device_basic_test.c + ${SOURCE_DIR}/usbx_audio20_device_controls_test.c + ${SOURCE_DIR}/usbx_audio20_device_feedback_test.c + ${SOURCE_DIR}/usbx_audio10_iad_host_basic_test.c + ${SOURCE_DIR}/usbx_audio20_host_basic_test.c + ${SOURCE_DIR}/usbx_uxe_device_audio_test.c + ${SOURCE_DIR}/usbx_uxe_host_audio_test.c +) + +set(ux_class_audio_device_standalone_test_cases + ${SOURCE_DIR}/usbx_audio10_device_basic_test.c + ${SOURCE_DIR}/usbx_audio20_device_basic_test.c + ${SOURCE_DIR}/usbx_audio10_device_feedback_test.c + ${SOURCE_DIR}/usbx_audio20_device_feedback_test.c + ${SOURCE_DIR}/usbx_audio10_iad_device_interrupt_test.c +) + +set(ux_class_rndis_test_cases ${SOURCE_DIR}/usbx_rndis_basic_test.c) + +set(ux_class_cdc_ecm_test_cases + ${SOURCE_DIR}/usbx_cdc_ecm_basic_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_basic_ipv6_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_nx_packet_chain_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_disconnect_and_reconnect_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_alternate_setting_change_to_zero_test.c + ${SOURCE_DIR}/usbx_ux_host_class_cdc_ecm_transmission_callback_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_host_bulko_transfer_arming_during_link_dn_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_host_bulk_out_transfer_fail_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_host_bulki_arm_err_dueto_link_dn_thread_wait_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_host_non_ip_packet_received_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_host_bulk_in_transfer_fail_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_host_thread_link_down_before_transfer_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_host_thread_packet_allocate_fail_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_host_thread_packet_append_fail_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_mac_address_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_mac_address_invalid_length_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_no_functional_descriptor_test.c + ${SOURCE_DIR}/usbx_ux_host_class_cdc_ecm_mac_address_get_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_host_bulk_in_transfer_arming_during_link_down_test.c + ${SOURCE_DIR}/usbx_ux_host_class_cdc_ecm_interrupt_notification_test.c + ${SOURCE_DIR}/usbx_ux_host_class_cdc_ecm_entry_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_host_bulk_in_transfer_arming_during_deactivate_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_host_first_interrupt_transfer_fail_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_host_packet_pool_create_fail_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_host_thread_create_fail_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_host_int_notification_semaphore_create_fail_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_host_bulk_out_semaphore_create_fail_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_host_bulk_in_semaphore_create_fail_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_control_interface_no_interrupt_endpoint_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_data_iface_non_bulko_and_non_bulki_endpt_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_basic_memory_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_data_interface_setting_select_fails_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_non_data_iface_after_zero_endpt_data_iface_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_invalid_alt_setting_after_zero_endpt_data_iface_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_default_data_interface_setting_with_endpoints_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_one_data_interface_with_no_endpoints_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_no_control_interface_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_interface_before_control_interface_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_data_interface_no_bulk_out_endpoint_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_data_interface_no_bulk_in_endpoint_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_link_down_while_ongoing_transfers_test.c + ${SOURCE_DIR}/usbx_ux_host_class_cdc_ecm_write_test.c + ${SOURCE_DIR}/usbx_ux_device_class_cdc_ecm_activate_test.c + ${SOURCE_DIR}/usbx_ux_device_class_cdc_ecm_bulkin_thread_test.c + ${SOURCE_DIR}/usbx_ux_device_class_cdc_ecm_bulkout_thread_test.c + ${SOURCE_DIR}/usbx_ux_device_class_cdc_ecm_control_request_test.c + ${SOURCE_DIR}/usbx_ux_device_class_cdc_ecm_change_test.c + ${SOURCE_DIR}/usbx_ux_device_class_cdc_ecm_entry_test.c + ${SOURCE_DIR}/usbx_ux_device_class_cdc_ecm_deactivate_test.c + ${SOURCE_DIR}/usbx_ux_device_class_cdc_ecm_initialize_test.c + ${SOURCE_DIR}/usbx_ux_device_class_cdc_ecm_interrupt_thread_test.c + ${SOURCE_DIR}/usbx_ux_device_class_cdc_ecm_uninitialize_test.c) + +set(ux_class_hid_test_cases + ${SOURCE_DIR}/usbx_ux_device_class_hid_basic_memory_test.c + ${SOURCE_DIR}/usbx_ux_device_class_hid_activate_test2.c + ${SOURCE_DIR}/usbx_ux_device_class_hid_activate_test3.c + ${SOURCE_DIR}/usbx_ux_device_class_hid_control_request_test.c + ${SOURCE_DIR}/usbx_ux_device_class_hid_initialize_test.c + ${SOURCE_DIR}/usbx_ux_device_class_hid_interrupt_thread_test2.c + ${SOURCE_DIR}/usbx_ux_device_class_hid_read_test.c + ${SOURCE_DIR}/usbx_ux_device_class_hid_receiver_memory_test.c + ${SOURCE_DIR}/usbx_ux_device_class_hid_receiver_test.c + ${SOURCE_DIR}/usbx_ux_device_class_hid_report_test.c + ${SOURCE_DIR}/usbx_ux_device_class_hid_report_set_test2.c + ${SOURCE_DIR}/usbx_ux_device_class_hid_idle_rate_test.c + ${SOURCE_DIR}/usbx_ux_device_class_hid_wMaxPacketSize_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_client_register_test2.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_deactivate_test3.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_report_descriptor_get_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_report_descriptor_get_test4.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_idle_get_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_interrupt_endpoint_search_int_out_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_interrupt_endpoint_search_test2.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_keyboard_callback_test2.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_keyboard_ioctl_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_main_item_parse_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_main_item_parse_test2.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_mouse_entry_test2.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_mouse_entry_test3.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_periodic_report_start_test2.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_remote_control_activate_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_remote_control_activate_test2.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_remote_control_entry_test2.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_remote_control_entry_test3.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_report_get_test2.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_transfer_request_completed_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_deactivate_test.c + ${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_descriptor_parse_test5.c + ${SOURCE_DIR}/usbx_hid_keyboard_extraction_test2.c + ${SOURCE_DIR}/usbx_hid_mouse_extraction_test2.c + ${SOURCE_DIR}/usbx_hid_remote_control_extraction_test2.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_keyboard_thread_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_keyboard_thread_test2.c + ${SOURCE_DIR}/usbx_ux_device_class_hid_activate_test.c + ${SOURCE_DIR}/usbx_ux_device_class_hid_deactivate_test.c + ${SOURCE_DIR}/usbx_ux_device_class_hid_entry_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_activate_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_configure_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_descriptor_parse_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_entry_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_idle_set_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_interrupt_endpoint_search_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_keyboard_activate_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_keyboard_entry_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_local_item_parse_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_mouse_activate_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_mouse_buttons_get_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_mouse_entry_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_mouse_positions_get_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_mouse_wheel_get_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_periodic_report_start_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_periodic_report_stop_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_remote_control_entry_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_remote_control_usage_get_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_report_add_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_report_callback_register_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_report_id_get_test.c + ${SOURCE_DIR}/usbx_hid_interrupt_endpoint_get_report_test.c + ${SOURCE_DIR}/usbx_ux_device_class_hid_event_get_AND_set_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_client_register_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_client_search_test.c + ${SOURCE_DIR}/usbx_control_transfer_stall_test.c + ${SOURCE_DIR}/usbx_ux_device_class_hid_descriptor_send_test.c + ${SOURCE_DIR}/usbx_hid_keyboard_key_test.c + ${SOURCE_DIR}/usbx_ux_device_class_hid_interrupt_thread_test.c + ${SOURCE_DIR}/usbx_ux_device_class_hid_report_set_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_report_get_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_report_set_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_report_set_int_out_test.c + ${SOURCE_DIR}/usbx_hid_keyboard_key_get_test.c + ${SOURCE_DIR}/usbx_hid_transfer_request_completed_decompressed_test.c + ${SOURCE_DIR}/usbx_hid_transfer_request_completed_raw_test.c + ${SOURCE_DIR}/usbx_hid_transfer_request_completed_test.c + ${SOURCE_DIR}/usbx_hid_remote_control_extraction_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_compress_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_compress_array_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_compress_and_decompress_test.c + ${SOURCE_DIR}/usbx_hid_keyboard_extraction_test.c + ${SOURCE_DIR}/usbx_hid_keyboard_basic_test.c + ${SOURCE_DIR}/usbx_hid_mouse_basic_test.c + ${SOURCE_DIR}/usbx_hid_mouse_extraction_test.c + ${SOURCE_DIR}/usbx_hid_remote_control_tests.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_collection_overflow_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_decompress_array_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_decompress_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_delimiter_nested_close_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_delimiter_nested_open_test.c + ${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_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 + ${SOURCE_DIR}/usbx_hid_report_descriptor_example_display_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_example_joystk_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_example_keybrd_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_example_monitor_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_example_mouse_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_example_remote_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_example_tele_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_get_zero_length_item_data_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_global_item_persist_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_global_item_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_incoherent_usage_min_max_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_invalid_item_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_invalid_length_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_item_size_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_multiple_collections_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_multiple_fields_and_reports_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_multiple_fields_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_multiple_reports_feature_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_multiple_reports_input_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_multiple_reports_output_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_pop_underflow_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_push_overflow_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_push_pop_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_report_count_overflow_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_report_size_overflow_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_unknown_global_tag_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_unknown_local_tag_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_usages_min_max_test.c + ${SOURCE_DIR}/usbx_hid_report_descriptor_usages_single_test.c + ${SOURCE_DIR}/usbx_hid_report_multiple_reports_ids_test.c + ${SOURCE_DIR}/usbx_uxe_device_hid_test.c + ${SOURCE_DIR}/usbx_uxe_host_hid_test.c + ${SOURCE_DIR}/usbx_ux_host_class_hid_logitech_pro_x_superlight_test.c +) +set(ux_class_hid_device_standalone_test_cases + ${SOURCE_DIR}/usbx_hid_mouse_basic_test.c + ${SOURCE_DIR}/usbx_hid_keyboard_basic_test.c + ${SOURCE_DIR}/usbx_ux_device_class_hid_basic_memory_test.c + ${SOURCE_DIR}/usbx_ux_device_class_hid_control_request_test.c + ${SOURCE_DIR}/usbx_ux_device_class_hid_read_test.c + ${SOURCE_DIR}/usbx_ux_device_class_hid_receiver_memory_test.c + ${SOURCE_DIR}/usbx_ux_device_class_hid_receiver_test.c + ${SOURCE_DIR}/usbx_uxe_device_hid_test.c +) +set(ux_class_hid_host_standalone_test_cases + ${SOURCE_DIR}/usbx_class_hid_basic_test.c + ${SOURCE_DIR}/usbx_class_hid_keyboard_basic_test.c + ${SOURCE_DIR}/usbx_class_hid_mouse_basic_test.c + ${SOURCE_DIR}/usbx_class_hid_remote_control_basic_test.c + ${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 +) +set(ux_class_hid_standalone_test_cases +) + +set(ux_class_cdc_acm_test_cases + ${SOURCE_DIR}/usbx_cdc_acm_basic_test.c + ${SOURCE_DIR}/usbx_cdc_acm_basic_memory_test.c + ${SOURCE_DIR}/usbx_cdc_acm_configure_test.c + ${SOURCE_DIR}/usbx_cdc_acm_device_dtr_rts_reset_on_disconnect_test.c + ${SOURCE_DIR}/usbx_ux_device_class_cdc_acm_activate_test.c + ${SOURCE_DIR}/usbx_ux_device_class_cdc_acm_deactivate_test.c + ${SOURCE_DIR}/usbx_ux_device_class_cdc_acm_ioctl_test.c + ${SOURCE_DIR}/usbx_ux_device_class_cdc_acm_transmission_test.c + ${SOURCE_DIR}/usbx_ux_device_class_cdc_acm_write_test.c + ${SOURCE_DIR}/usbx_ux_device_class_cdc_acm_timeout_test.c + ${SOURCE_DIR}/usbx_ux_host_class_cdc_acm_activate_test.c + ${SOURCE_DIR}/usbx_ux_host_class_cdc_acm_capabilities_get_test.c + ${SOURCE_DIR}/usbx_ux_host_class_cdc_acm_deactivate_test.c + ${SOURCE_DIR}/usbx_ux_host_class_cdc_acm_endpoints_get_test.c + ${SOURCE_DIR}/usbx_ux_host_class_cdc_acm_entry_test.c + ${SOURCE_DIR}/usbx_ux_host_class_cdc_acm_read_test.c + ${SOURCE_DIR}/usbx_ux_host_class_cdc_acm_transfer_request_completed_test.c + ${SOURCE_DIR}/usbx_ux_host_class_cdc_acm_write_test.c + ${SOURCE_DIR}/usbx_ux_device_class_cdc_acm_bulkout_thread_test.c +) + +set(ux_class_gser_test_cases + ${SOURCE_DIR}/usbx_uxe_host_gser_test.c +) +set(ux_class_prolific_test_cases + ${SOURCE_DIR}/usbx_uxe_host_prolific_test.c +) +set(ux_class_swar_test_cases + ${SOURCE_DIR}/usbx_uxe_host_swar_test.c +) + +set(ux_dpump_test_cases ${SOURCE_DIR}/usbx_dpump_basic_test.c) + +set(ux_device_class_storage_tx_test_cases ${SOURCE_DIR}/usbx_storage_tests.c) + +set(ux_class_storage_test_cases + ${SOURCE_DIR}/usbx_host_class_storage_max_lun_get_coverage_test.c + ${SOURCE_DIR}/usbx_host_class_storage_entry_coverage_test.c + ${SOURCE_DIR}/usbx_storage_basic_memory_test.c + ${SOURCE_DIR}/usbx_storage_multi_lun_test.c + ${SOURCE_DIR}/usbx_ux_device_class_storage_request_sense_coverage_test.c + ${SOURCE_DIR}/usbx_ux_device_class_storage_control_request_test.c + ${SOURCE_DIR}/usbx_ux_device_class_storage_entry_test.c + ${SOURCE_DIR}/usbx_ux_device_class_storage_format_test.c + ${SOURCE_DIR}/usbx_ux_device_class_storage_initialize_test.c + ${SOURCE_DIR}/usbx_ux_device_class_storage_inquiry_test.c + ${SOURCE_DIR}/usbx_ux_device_class_storage_mode_select_test.c + ${SOURCE_DIR}/usbx_ux_device_class_storage_mode_sense_test.c + ${SOURCE_DIR}/usbx_ux_device_class_storage_prevent_allow_media_removal_test.c + ${SOURCE_DIR}/usbx_ux_device_class_storage_read_test.c + ${SOURCE_DIR}/usbx_ux_device_class_storage_request_sense_test.c + ${SOURCE_DIR}/usbx_ux_device_class_storage_start_stop_test.c + ${SOURCE_DIR}/usbx_ux_device_class_storage_synchronize_cache_test.c + ${SOURCE_DIR}/usbx_ux_device_class_storage_test_ready_test.c + ${SOURCE_DIR}/usbx_ux_device_class_storage_thread_test.c + ${SOURCE_DIR}/usbx_ux_device_class_storage_uninitialize_test.c + ${SOURCE_DIR}/usbx_ux_device_class_storage_verify_test.c + ${SOURCE_DIR}/usbx_ux_device_class_storage_vendor_strings_test.c + ${SOURCE_DIR}/usbx_ux_device_class_storage_write_test.c + ${SOURCE_DIR}/usbx_ux_device_class_storage_invalid_lun_test.c + ${SOURCE_DIR}/usbx_ux_host_class_storage_configure_coverage_test.c + ${SOURCE_DIR}/usbx_ux_host_class_storage_request_sense_test.c + ${SOURCE_DIR}/usbx_ux_host_class_storage_media_capacity_get_test.c + ${SOURCE_DIR}/usbx_ux_host_class_storage_max_lun_get_test.c + ${SOURCE_DIR}/usbx_ux_host_class_storage_configure_test.c + ${SOURCE_DIR}/usbx_ux_host_class_storage_activate_test.c + ${SOURCE_DIR}/usbx_ux_host_class_storage_device_support_check_test.c + ${SOURCE_DIR}/usbx_ux_host_class_storage_device_initialize_test.c + ${SOURCE_DIR}/usbx_ux_host_class_storage_media_mount_test.c + ${SOURCE_DIR}/usbx_ux_host_class_storage_media_open_test.c + ${SOURCE_DIR}/usbx_ux_host_class_storage_media_read_test.c + ${SOURCE_DIR}/usbx_ux_host_class_storage_media_write_test.c + ${SOURCE_DIR}/usbx_ux_host_class_storage_media_protection_check_test.c + ${SOURCE_DIR}/usbx_ux_host_class_storage_media_recovery_sense_get_test.c + ${SOURCE_DIR}/usbx_ux_host_class_storage_start_stop_test.c + ${SOURCE_DIR}/usbx_ux_host_class_storage_transport_bo_test.c + ${SOURCE_DIR}/usbx_ux_host_class_storage_driver_entry_test.c + ${SOURCE_DIR}/usbx_ux_host_class_storage_entry_test.c + ${SOURCE_DIR}/usbx_ux_host_class_storage_thread_entry_test.c + ${SOURCE_DIR}/usbx_ux_host_class_storage_fats_exfat_test.c + ${SOURCE_DIR}/usbx_uxe_device_storage_test.c + ${SOURCE_DIR}/usbx_uxe_host_storage_test.c +) +set(ux_class_memory_management_test_cases + ${SOURCE_DIR}/usbx_ux_host_device_basic_memory_tests.c + ${SOURCE_DIR}/usbx_ux_utility_memory_safe_test.c + ${SOURCE_DIR}/usbx_ux_utility_memory_test.c + ${SOURCE_DIR}/usbx_ux_utility_basic_memory_management_test.c + ${SOURCE_DIR}/usbx_hub_basic_memory_test.c + ${SOURCE_DIR}/usbx_cdc_ecm_basic_memory_test.c + ${SOURCE_DIR}/usbx_ux_device_class_hid_basic_memory_test.c + ${SOURCE_DIR}/usbx_ux_device_class_hid_receiver_memory_test.c + ${SOURCE_DIR}/usbx_class_hid_basic_memory_test.c + ${SOURCE_DIR}/usbx_cdc_acm_basic_memory_test.c + ${SOURCE_DIR}/usbx_storage_basic_memory_test.c +) +set(ux_class_storage_device_standalone_test_cases + ${SOURCE_DIR}/usbx_standalone_device_storage_basic_test.c + ${SOURCE_DIR}/usbx_standalone_device_storage_read_write_test.c + ${SOURCE_DIR}/usbx_standalone_device_storage_error_cv_test.c +) +set(ux_class_storage_host_standalone_test_cases + ${SOURCE_DIR}/usbx_standalone_host_storage_basic_test.c + ${SOURCE_DIR}/usbx_standalone_host_storage_read_write_test.c + ${SOURCE_DIR}/usbx_standalone_host_storage_insert_eject_test.c + ${SOURCE_DIR}/usbx_uxe_host_storage_test.c +) +set(ux_class_storage_standalone_test_cases +) + +set(ux_stack_cdc_acm_test_cases + ${SOURCE_DIR}/usbx_ux_host_device_basic_tests.c + ${SOURCE_DIR}/usbx_ux_host_device_basic_memory_tests.c + ${SOURCE_DIR}/usbx_ux_host_device_initialize_tests.c + ${SOURCE_DIR}/usbx_ux_host_stack_class_instance_verify_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_interface_setting_select_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_new_configuration_create_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_new_device_create_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_new_interface_create_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_rh_change_process_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_endpoint_reset_test.c + ${SOURCE_DIR}/usbx_ux_device_stack_standard_request_tests.c + ${SOURCE_DIR}/usbx_ux_device_stack_descriptor_send_test.c + ${SOURCE_DIR}/usbx_ux_device_stack_remote_wakeup_test.c + ${SOURCE_DIR}/usbx_ux_device_stack_vendor_request_test.c + ${SOURCE_DIR}/usbx_uxe_device_cdc_acm_test.c + ${SOURCE_DIR}/usbx_uxe_host_cdc_acm_test.c +) +set(ux_class_cdc_acm_device_standalone_test_cases + # ${SOURCE_DIR}/usbx_standalone_device_cdc_acm_basic_memory_test.c + ${SOURCE_DIR}/usbx_standalone_cdc_acm_basic_memory_test.c + # ${SOURCE_DIR}/usbx_standalone_device_cdc_acm_basic_test.c + ${SOURCE_DIR}/usbx_standalone_cdc_acm_basic_test.c + ${SOURCE_DIR}/usbx_standalone_device_cdc_acm_transmission_test.c + ${SOURCE_DIR}/usbx_uxe_device_cdc_acm_test.c +) +set(ux_class_cdc_acm_host_standalone_test_cases + ${SOURCE_DIR}/usbx_standalone_cdc_acm_basic_memory_test.c + ${SOURCE_DIR}/usbx_standalone_cdc_acm_basic_test.c +) + +set(ux_stack_test_cases + ${SOURCE_DIR}/usbx_host_stack_class_unregister_coverage_test.c + ${SOURCE_DIR}/usbx_host_stack_new_endpoint_create_coverage_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_uninitialize_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_hcd_unregister_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_bandwidth_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_device_address_set_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_device_configuration_activate_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_device_configuration_reset_coverage_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_device_get_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_device_remove_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_new_device_get_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_class_device_scan_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_class_get_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_class_instance_destroy_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_class_instance_get_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_class_interface_scan_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_class_register_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_configuration_descriptor_parse_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_configuration_enumerate_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_configuration_instance_delete_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_configuration_interface_get_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_configuration_set_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_device_descriptor_read_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_endpoint_instance_create_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_endpoint_instance_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_hcd_register_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_hcd_transfer_request_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_interfaces_scan_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_interface_endpoint_get_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_rh_device_insertion_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_device_configuration_get_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_device_configuration_reset_select_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_hcd_thread_entry_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_transfer_request_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_enum_bMaxPacketSize0_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_enum_wMaxPacketSize_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_transfer_request_abort_test.c + ${SOURCE_DIR}/usbx_ux_device_stack_class_register_test.c + ${SOURCE_DIR}/usbx_ux_device_stack_class_unregister_test.c + ${SOURCE_DIR}/usbx_ux_device_stack_set_feature_test.c + ${SOURCE_DIR}/usbx_ux_device_stack_alternate_setting_get_test.c + ${SOURCE_DIR}/usbx_ux_device_stack_alternate_setting_set_test.c + ${SOURCE_DIR}/usbx_ux_device_stack_configuration_set_test.c + ${SOURCE_DIR}/usbx_ux_device_stack_control_request_process_coverage_test.c + ${SOURCE_DIR}/usbx_ux_device_stack_control_request_process_test.c + ${SOURCE_DIR}/usbx_ux_device_stack_class_control_request_test.c + ${SOURCE_DIR}/usbx_ux_device_stack_interface_delete_test.c + ${SOURCE_DIR}/usbx_ux_device_stack_interface_set_test.c + ${SOURCE_DIR}/usbx_ux_device_stack_interface_start_test.c + ${SOURCE_DIR}/usbx_ux_device_stack_transfer_request_test.c + ${SOURCE_DIR}/usbx_ux_device_stack_endpoint_stall_test.c + ${SOURCE_DIR}/usbx_ux_device_stack_bos_test.c + ${SOURCE_DIR}/usbx_ux_device_stack_initialize_test.c + ${SOURCE_DIR}/usbx_ux_device_stack_clear_feature_coverage_test.c + ${SOURCE_DIR}/usbx_uxe_system_test.c + ${SOURCE_DIR}/usbx_uxe_device_stack_test.c + ${SOURCE_DIR}/usbx_uxe_host_stack_test.c +) +set(ux_stack_test_cases_hid + ${SOURCE_DIR}/usbx_ux_device_stack_get_status_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_class_unregister_test.c +) +set(ux_stack_test_cases_cdc +) +set(ux_utility_test_cases + ${SOURCE_DIR}/usbx_ux_api_tracex_id_test.c + ${SOURCE_DIR}/usbx_ux_utility_descriptor_pack_test.c + ${SOURCE_DIR}/usbx_ux_utility_descriptor_parse_test.c + ${SOURCE_DIR}/usbx_ux_utility_descriptor_struct_test.c + ${SOURCE_DIR}/usbx_ux_utility_memory_safe_test.c + ${SOURCE_DIR}/usbx_ux_utility_memory_test.c + ${SOURCE_DIR}/usbx_ux_utility_pci_write_test.c + ${SOURCE_DIR}/usbx_ux_utility_pci_read_test.c + ${SOURCE_DIR}/usbx_ux_utility_pci_class_scan_test.c + ${SOURCE_DIR}/usbx_ux_utility_physical_address_test.c + ${SOURCE_DIR}/usbx_ux_utility_string_length_check_test.c + ${SOURCE_DIR}/usbx_ux_utility_unicode_to_string_test.c +) +set(ux_utility_os_test_cases + ${SOURCE_DIR}/usbx_ux_utility_event_flags_test.c + ${SOURCE_DIR}/usbx_ux_utility_mutex_test.c + ${SOURCE_DIR}/usbx_ux_utility_semaphore_test.c + ${SOURCE_DIR}/usbx_ux_utility_thread_create_test.c + ${SOURCE_DIR}/usbx_ux_utility_thread_schedule_other_test.c + ${SOURCE_DIR}/usbx_ux_utility_thread_suspend_test.c + ${SOURCE_DIR}/usbx_ux_utility_thread_identify_test.c + ${SOURCE_DIR}/usbx_ux_utility_timer_test.c +) + +set(ux_class_video_test_cases + ${SOURCE_DIR}/usbx_ux_device_class_video_basic_tests.c + ${SOURCE_DIR}/usbx_ux_host_class_video_basic_tests.c + ${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_uxe_device_video_test.c + ${SOURCE_DIR}/usbx_uxe_host_video_test.c +) + +set(ux_class_video_device_standalone_test_cases + ${SOURCE_DIR}/usbx_ux_device_class_video_basic_tests.c + ${SOURCE_DIR}/usbx_uxe_device_video_test.c +) + +set(ux_class_print_test_cases + ${SOURCE_DIR}/usbx_class_printer_basic_tests.c + ${SOURCE_DIR}/usbx_uxe_device_printer_test.c + ${SOURCE_DIR}/usbx_uxe_host_printer_test.c +) + +set(ux_class_printer_device_standalone_test_cases + ${SOURCE_DIR}/usbx_class_printer_device_standalone_basic_tests.c + ${SOURCE_DIR}/usbx_uxe_device_printer_test.c +) + +set(ux_msrc_test_cases + ${SOURCE_DIR}/usbx_msrc_69702_dfu_dnload_test.c + ${SOURCE_DIR}/usbx_msrc_71934_dfu_upload_test.c +) +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_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 + ${SOURCE_DIR}/usbx_msrc_73386_host_storage_media_open_buffer_test.c + ${SOURCE_DIR}/usbx_msrc_73716_cdc_ecm_mac_get_desc_check.c + ${SOURCE_DIR}/usbx_msrc_73492_host_vc_header_parse.c + ${SOURCE_DIR}/usbx_msrc_80947_device_cdc_ecm_rx_length_less_than_14.c + ${SOURCE_DIR}/usbx_msrc_81024_host_cdc_ecm_rx_length_less_than_14.c + ${SOURCE_DIR}/usbx_msrc_80991_device_rndis_rx_length_less_than_14_test.c + ${SOURCE_DIR}/usbx_msrc_81251_host_hid_report_add_fail_mem_test.c + ${SOURCE_DIR}/usbx_msrc_81206_81225_ecm_multiple_data_reject_test.c + ${SOURCE_DIR}/usbx_msrc_81230_host_asix_inst_free_tests.c + ${SOURCE_DIR}/usbx_msrc_81231_host_prolific_inst_free_tests.c + ${SOURCE_DIR}/usbx_msrc_81232_host_gser_inst_free_tests.c + ${SOURCE_DIR}/usbx_msrc_81233_host_swar_inst_free_tests.c + ${SOURCE_DIR}/usbx_msrc_81112_host_cdc_ecm_endpoints_get_tests.c + ${SOURCE_DIR}/usbx_msrc_81142_host_storage_endpoints_get_tests.c + ${SOURCE_DIR}/usbx_msrc_81143_host_cdc_acm_endpoints_get_tests.c + ${SOURCE_DIR}/usbx_msrc_81108_pictbridge_object_parse_test.c + ${SOURCE_DIR}/usbx_msrc_81325_host_hid_remote_control_free_callback_test.c + ${SOURCE_DIR}/usbx_msrc_81326_host_hid_keyboard_free_callback_test.c + ${SOURCE_DIR}/usbx_msrc_81327_host_hid_mouse_free_callback_test.c + ${SOURCE_DIR}/usbx_msrc_81109_pictbridge_array_element_to_hexa_test.c + ${SOURCE_DIR}/usbx_msrc_81292_host_pima_deactivate_semaphore_test.c + ${SOURCE_DIR}/usbx_msrc_81323_host_pima_deactivate_no_int_ep_test.c + ${SOURCE_DIR}/usbx_msrc_81184_host_audio_desc_validate_test.c + ${SOURCE_DIR}/usbx_msrc_81426_host_audio_type_get_fail_ac_link_test.c + ${SOURCE_DIR}/usbx_msrc_81428_81429_host_audio_ac_search_test.c +) +set(ux_msrc_test_cases_standalone + ${SOURCE_DIR}/usbx_msrc_81489_81570_host_cdc_acm_standalone_ac_search_test.c + ${SOURCE_DIR}/usbx_msrc_81572_standalone_host_printer_allocated_enum_free_test.c + ${SOURCE_DIR}/usbx_msrc_81573_standalone_host_hub_allocated_enum_free_test.c + ${SOURCE_DIR}/usbx_msrc_81574_standalone_host_hid_allocated_enum_free_test.c + ${SOURCE_DIR}/usbx_msrc_81575_standalone_host_cdc_acm_allocated_enum_free_test.c + ${SOURCE_DIR}/usbx_msrc_81691_standalone_host_stack_enum_double_free_test.c +) + +set(ux_class_ccid_test_cases + ${SOURCE_DIR}/usbx_device_class_ccid_basic_tests.c + ${SOURCE_DIR}/usbx_device_class_ccid_busy_abort_tests.c + ${SOURCE_DIR}/usbx_uxe_device_ccid_test.c +) + +set(ux_basic_test_cases + ${SOURCE_DIR}/usbx_class_device_enumeration_test.c + ${SOURCE_DIR}/usbx_class_interface_enumeration_test.c + ${SOURCE_DIR}/usbx_class_multi_interface_enumeration_test.c + ${SOURCE_DIR}/usbx_ux_host_stack_device_string_get_test.c +) + +set(ux_class_pima_test_cases + ${SOURCE_DIR}/usbx_pima_basic_test.c + ${SOURCE_DIR}/usbx_pictbridge_basic_test.c + ${SOURCE_DIR}/usbx_uxe_device_pima_test.c + ${SOURCE_DIR}/usbx_uxe_host_pima_test.c +) + + +if("-DNX_BSD_ENABLE" IN_LIST ${CMAKE_BUILD_TYPE}) + +endif() + +set(test_utility_files + ${SOURCE_DIR}/usbxtestcontrol.c + ${SOURCE_DIR}/ux_test.c + ${SOURCE_DIR}/ux_host_class_dummy.c + ${SOURCE_DIR}/ux_host_class_dummy.h + ${SOURCE_DIR}/ux_device_class_dummy.c + ${SOURCE_DIR}/ux_device_class_dummy.h + ${SOURCE_DIR}/ux_device_class_dummy_hub.c + ${SOURCE_DIR}/ux_device_class_dummy_hub.h + # ${SOURCE_DIR}/ux_device_class_dummy_printer.c + # ${SOURCE_DIR}/ux_device_class_dummy_printer.h + ${SOURCE_DIR}/ux_test_utility_sim_no_overriding.c + ${SOURCE_DIR}/ux_test_race_condition_overrides.c + ${SOURCE_DIR}/ux_test_dcd_sim_slave.c + ${SOURCE_DIR}/ux_test_hcd_sim_host.c + ${SOURCE_DIR}/ux_test_utility_sim.c + ${SOURCE_DIR}/ux_test_standalone_references.c + ${SOURCE_DIR}/usbx_ux_host_class_storage_fx_driver.c) +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 FX_ENABLE_EXFAT) + +if (CMAKE_BUILD_TYPE MATCHES "msrc_rtos_build") + set(test_cases + ${ux_msrc_test_cases} + ${ux_msrc_test_cases_rtos} + ) +elseif (CMAKE_BUILD_TYPE MATCHES "msrc_standalone_build") + set(test_cases + ${ux_msrc_test_cases} + ${ux_msrc_test_cases_standalone} + ) +elseif(NOT (CMAKE_BUILD_TYPE MATCHES "standalone.*")) + if (CMAKE_BUILD_TYPE MATCHES "nofx_.*") + set(test_cases + ${ux_class_storage_test_cases} + ) + elseif (CMAKE_BUILD_TYPE MATCHES "memory_management_.*") + set(test_cases + ${ux_class_memory_management_test_cases} + ) + else() + set(test_cases + ${ux_basic_test_cases} + ${ux_utility_test_cases} + ${ux_utility_os_test_cases} + ${ux_stack_test_cases} + ${ux_dpump_test_cases} + ${ux_class_hub_test_cases} + ${ux_device_class_storage_tx_test_cases} + ${ux_class_dfu_test_cases} + ${ux_class_print_test_cases} + ${ux_class_ccid_test_cases} + ) + if(NOT (CMAKE_BUILD_TYPE MATCHES "optimized.*")) + list(APPEND test_cases + ${ux_stack_test_cases_hid} + ${ux_stack_test_cases_cdc} + ${ux_stack_cdc_acm_test_cases} + ${ux_class_cdc_acm_test_cases} + ${ux_class_audio_test_cases} + ${ux_class_rndis_test_cases} + ${ux_class_cdc_ecm_test_cases} + ${ux_class_hid_test_cases} + ${ux_class_video_test_cases} + ${ux_class_storage_test_cases} + ${ux_class_pima_test_cases} + ${ux_class_gser_test_cases} + ${ux_class_prolific_test_cases} + ${ux_class_swar_test_cases} + ${ux_msrc_test_cases} + ) + endif() + endif() +else() + set(test_cases + ${ux_basic_test_cases} + ${ux_utility_test_cases} + ${ux_dpump_test_cases} + ) + if (CMAKE_BUILD_TYPE MATCHES "standalone_device.*") + list(APPEND test_cases + ${ux_utility_os_test_cases} + ${ux_class_storage_device_standalone_test_cases} + ${ux_class_cdc_acm_device_standalone_test_cases} + ${ux_class_video_device_standalone_test_cases} + ${ux_class_hid_device_standalone_test_cases} + ${ux_class_dfu_test_cases} + ${ux_msrc_test_cases} + ${ux_class_printer_device_standalone_test_cases} + ${ux_class_audio_device_standalone_test_cases} + ${ux_class_ccid_test_cases} + ) + elseif (CMAKE_BUILD_TYPE MATCHES "standalone_host.*") + list(APPEND test_cases + ${ux_utility_os_test_cases} + ${ux_class_storage_host_standalone_test_cases} + ${ux_class_cdc_acm_host_standalone_test_cases} + ${ux_class_hid_host_standalone_test_cases} + ${ux_class_print_test_cases} + ${ux_class_hub_standalone_test_cases} + ) + else () + list(APPEND test_cases + ${ux_class_dfu_test_cases} + ) + endif() +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) + add_test(${CMAKE_BUILD_TYPE}::${test_name} ${test_name}) +endforeach() diff --git a/test/cmake/usbx/run.sh b/test/cmake/usbx/run.sh new file mode 100755 index 00000000..c9a81ca4 --- /dev/null +++ b/test/cmake/usbx/run.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +cd $(dirname $0) + +# Checkout externals +[ -d externals] || mkdir ../../externals +git clone https://github.com/azure-rtos/threadx.git ../../externals/threadx +git clone https://github.com/azure-rtos/netxduo.git ../../externals/netxduo +git clone https://github.com/azure-rtos/filex.git ../../externals/filex + +# 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 +fi + +[ -f .run.sh ] || ln -sf ../../externals/threadx/scripts/cmake_bootstrap.sh .run.sh +./.run.sh $* \ No newline at end of file diff --git a/test/cmake/usbx/samples/CMakeLists.txt b/test/cmake/usbx/samples/CMakeLists.txt new file mode 100644 index 00000000..16e1d520 --- /dev/null +++ b/test/cmake/usbx/samples/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR) +cmake_policy(SET CMP0057 NEW) + +project(samples LANGUAGES C) + +set(SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../../samples) + +set(sample_files + ${SOURCE_DIR}/demo_usbx.c) + +foreach(sample_file ${sample_files}) + get_filename_component(sample_file_name ${sample_file} NAME_WE) + add_executable(${sample_file_name} ${sample_file} fake.c) + target_link_libraries(${sample_file_name} PRIVATE azrtos::usbx) +endforeach() diff --git a/test/cmake/usbx/samples/fake.c b/test/cmake/usbx/samples/fake.c new file mode 100644 index 00000000..c5bdbe50 --- /dev/null +++ b/test/cmake/usbx/samples/fake.c @@ -0,0 +1,11 @@ +#include "ux_api.h" + +UCHAR inpb(ULONG addr){return(0);} +USHORT inpw(ULONG addr){return(0);} +ULONG inpl(ULONG addr){return(0);} + +UCHAR outpb(ULONG addr, UCHAR b){return(b);} +USHORT outpw(ULONG addr, USHORT w){return(w);} +ULONG outpl(ULONG addr, ULONG l){return(l);} + +void ux_test_assert_hit(char* file, INT line){}; \ No newline at end of file diff --git a/test/cmake/usbx/ux_user.h b/test/cmake/usbx/ux_user.h new file mode 100644 index 00000000..4a79b6ac --- /dev/null +++ b/test/cmake/usbx/ux_user.h @@ -0,0 +1,345 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** USBX Component */ +/** */ +/** User Specific */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* PORT SPECIFIC C INFORMATION RELEASE */ +/* */ +/* ux_user.h PORTABLE C */ +/* 6.x */ +/* */ +/* AUTHOR */ +/* */ +/* Chaoqiong Xiao, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file contains user defines for configuring USBX in specific */ +/* ways. This file will have an effect only if the application and */ +/* USBX library are built with UX_INCLUDE_USER_DEFINE_FILE defined. */ +/* Note that all the defines in this file may also be made on the */ +/* command line when building USBX library and application objects. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */ +/* 09-30-2020 Chaoqiong Xiao Modified comment(s), */ +/* resulting in version 6.1 */ +/* xx-xx-xxxx Chaoqiong Xiao Modified comment(s), */ +/* added standalone supoort, */ +/* resulting in version 6.x */ +/* */ +/**************************************************************************/ + +#ifndef UX_USER_H +#define UX_USER_H + + +/* Define various build options for the USBX port. The application should either make changes + here by commenting or un-commenting the conditional compilation defined OR supply the defines + though the compiler's equivalent of the -D option. */ +/* #define UX_THREAD_STACK_SIZE (2 * 1024) */ + +/* Define USBX Host Enum Thread Stack Size. The default is to use UX_THREAD_STACK_SIZE */ +/* +#define UX_HOST_ENUM_THREAD_STACK_SIZE UX_THREAD_STACK_SIZE +*/ + + +/* Define USBX Host Thread Stack Size. The default is to use UX_THREAD_STACK_SIZE */ +/* +#define UX_HOST_HCD_THREAD_STACK_SIZE UX_THREAD_STACK_SIZE +*/ + +/* Define USBX Host HNP Polling Thread Stack Size. The default is to use UX_THREAD_STACK_SIZE */ +/* +#define UX_HOST_HNP_POLLING_THREAD_STACK UX_THREAD_STACK_SIZE +*/ + +/* Override various options with default values already assigned in ux_api.h or ux_port.h. Please + also refer to ux_port.h for descriptions on each of these options. */ + +/* Defined, this value represents how many ticks per seconds for a specific hardware platform. + The default is 1000 indicating 1 tick per millisecond. */ + +/* #define UX_PERIODIC_RATE 1000 +*/ +#ifdef TX_TIMER_TICKS_PER_SECOND +#define UX_PERIODIC_RATE (TX_TIMER_TICKS_PER_SECOND) +#else +#define UX_PERIODIC_RATE (100ul) +#endif + +/* Defined, this value is the maximum number of classes that can be loaded by USBX. This value + represents the class container and not the number of instances of a class. For instance, if a + particular implementation of USBX needs the hub class, the printer class, and the storage + class, then the UX_MAX_CLASSES value can be set to 3 regardless of the number of devices + that belong to these classes. */ + +/* #define UX_MAX_CLASSES 3 +*/ + + +/* Defined, this value is the maximum number of classes in the device stack that can be loaded by + USBX. */ + +/* #define UX_MAX_SLAVE_CLASS_DRIVER 1 +*/ + +/* Defined, this value is the maximum number of interfaces in the device framework. */ + +/* #define UX_MAX_SLAVE_INTERFACES 16 +*/ + +/* Defined, this value represents the number of different host controllers available in the system. + For USB 1.1 support, this value will usually be 1. For USB 2.0 support, this value can be more + than 1. This value represents the number of concurrent host controllers running at the same time. + If for instance there are two instances of OHCI running, or one EHCI and one OHCI controller + running, the UX_MAX_HCD should be set to 2. */ + +/* #define UX_MAX_HCD 1 +*/ + + +/* Defined, this value represents the maximum number of devices that can be attached to the USB. + Normally, the theoretical maximum number on a single USB is 127 devices. This value can be + scaled down to conserve memory. Note that this value represents the total number of devices + regardless of the number of USB buses in the system. */ + +/* #define UX_MAX_DEVICES 127 +*/ + + +/* Defined, this value represents the current number of SCSI logical units represented in the device + storage class driver. */ + +/* #define UX_MAX_SLAVE_LUN 1 +*/ + + +/* Defined, this value represents the maximum number of SCSI logical units represented in the + host storage class driver. */ + +#ifndef UX_MAX_HOST_LUN +#define UX_MAX_HOST_LUN 2 /* for test. */ +#endif + + +/* Defined, this value represents the maximum number of bytes received on a control endpoint in + the device stack. The default is 256 bytes but can be reduced in memory constraint environments. */ + +#ifndef UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH +#define UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH 248 /* for test. */ +#endif + + +/* Defined, this value represents the maximum number of bytes that can be received or transmitted + on any endpoint. This value cannot be less than the maximum packet size of any endpoint. The default + is 4096 bytes but can be reduced in memory constraint environments. For cd-rom support in the storage + class, this value cannot be less than 2048. */ + +/* #define UX_SLAVE_REQUEST_DATA_MAX_LENGTH (1024 * 2) */ + + +/* Defined, this value includes code to handle storage Multi-Media Commands (MMC). E.g., DVD-ROM. +*/ + +/* #define UX_SLAVE_CLASS_STORAGE_INCLUDE_MMC */ + + +/* Defined, this value represents the maximum number of bytes that a storage payload can send/receive. + The default is 8K bytes but can be reduced in memory constraint environments. */ + +/* #define UX_HOST_CLASS_STORAGE_MEMORY_BUFFER_SIZE (1024 * 8) */ + +/* Define USBX Mass Storage Thread Stack Size. The default is to use UX_THREAD_STACK_SIZE. */ + +/* #define UX_HOST_CLASS_STORAGE_THREAD_STACK_SIZE UX_THREAD_STACK_SIZE + */ + +/* Defined, this value represents the maximum number of Ed, regular TDs and Isochronous TDs. These values + depend on the type of host controller and can be reduced in memory constraint environments. */ + +#ifndef UX_MAX_ED +#define UX_MAX_ED 80 /* for test */ +#endif +#ifndef UX_MAX_TD +#define UX_MAX_TD 128 /* for test */ +#endif +#ifndef UX_MAX_ISO_TD +#define UX_MAX_ISO_TD 8 /* for test */ +#endif + +/* Defined, this value represents the maximum size of the HID decompressed buffer. This cannot be determined + in advance so we allocate a big block, usually 4K but for simple HID devices like keyboard and mouse + it can be reduced a lot. */ + +/* #define UX_HOST_CLASS_HID_DECOMPRESSION_BUFFER 4096 */ + +/* Defined, this value represents the maximum number of HID usages for a HID device. + Default is 2048 but for simple HID devices like keyboard and mouse it can be reduced a lot. */ + +/* #define UX_HOST_CLASS_HID_USAGES 2048 */ + + +/* By default, each key in each HID report from the device is reported by ux_host_class_hid_keyboard_key_get + (a HID report from the device is received whenever there is a change in a key state i.e. when a key is pressed + or released. The report contains every key that is down). There are limitations to this method such as not being + able to determine when a key has been released. + + Defined, this value causes ux_host_class_hid_keyboard_key_get to only report key changes i.e. key presses + and key releases. */ + +/* #define UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE */ + +/* Works when UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE is defined. + + Defined, this value causes ux_host_class_hid_keyboard_key_get to only report key pressed/down changes; + key released/up changes are not reported. + */ + +/* #define UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE_REPORT_KEY_DOWN_ONLY */ + +/* Works when UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE is defined. + + Defined, this value causes ux_host_class_hid_keyboard_key_get to report lock key (CapsLock/NumLock/ScrollLock) changes. + */ + +/* #define UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE_REPORT_LOCK_KEYS */ + +/* Works when UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE is defined. + + Defined, this value causes ux_host_class_hid_keyboard_key_get to report modifier key (Ctrl/Alt/Shift/GUI) changes. + */ + +/* #define UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE_REPORT_MODIFIER_KEYS */ + + +/* Defined, this value represents the maximum number of media for the host storage class. + Default is 8 but for memory contrained resource systems this can ne reduced to 1. */ + +#ifndef UX_HOST_CLASS_STORAGE_MAX_MEDIA +#define UX_HOST_CLASS_STORAGE_MAX_MEDIA 2 /* for test. */ +#endif + +/* Defined, this value includes code to handle storage devices that use the CB + or CBI protocol (such as floppy disks). It is off by default because these + protocols are obsolete, being superseded by the Bulk Only Transport (BOT) protocol + which virtually all modern storage devices use. +*/ + +/* #define UX_HOST_CLASS_STORAGE_INCLUDE_LEGACY_PROTOCOL_SUPPORT */ + +/* Defined, this value forces the memory allocation scheme to enforce alignement + of memory with the UX_SAFE_ALIGN field. +*/ + +/* #define UX_ENFORCE_SAFE_ALIGNMENT */ + +/* Defined, this value represents the number of packets in the CDC_ECM device class. + The default is 16. +*/ + +/* #define UX_DEVICE_CLASS_CDC_ECM_NX_PKPOOL_ENTRIES 4 */ + +/* Defined, this value represents the number of packets in the CDC_ECM host class. + The default is 16. +*/ + +/* #define UX_HOST_CLASS_CDC_ECM_NX_PKPOOL_ENTRIES 16 */ + +/* Defined, this value represents the number of milliseconds to wait for packet + allocation until invoking the application's error callback and retrying. + The default is 1000 milliseconds. +*/ + +/* #define UX_HOST_CLASS_CDC_ECM_PACKET_POOL_WAIT 10 */ + +/* Defined, this value represents the number of milliseconds to wait for packet + allocation until invoking the application's error callback and retrying. +*/ + +/* #define UX_DEVICE_CLASS_CDC_ECM_PACKET_POOL_WAIT 10 */ + +/* Defined, this value represents the the maximum length of HID reports on the + device. + */ + +/* #define UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH 64 */ + +/* Defined, this value represents the the maximum number of HID events/reports + that can be queued at once. + */ + +/* #define UX_DEVICE_CLASS_HID_MAX_EVENTS_QUEUE 8 */ + +/* Defined, this value will only enable the host side of usbx. */ +/* #define UX_HOST_SIDE_ONLY */ + +/* Defined, this value will only enable the device side of usbx. */ +/* #define UX_DEVICE_SIDE_ONLY */ + +/* Defined, this value will include the OTG polling thread. OTG can only be active if both host/device are present. +*/ + +#ifndef UX_HOST_SIDE_ONLY +#ifndef UX_DEVICE_SIDE_ONLY + +/* #define UX_OTG_SUPPORT */ + +#endif +#endif + +/* Defined, this value represents the maximum size of single tansfers for the SCSI data phase. +*/ + +/* #define UX_HOST_CLASS_STORAGE_MAX_TRANSFER_SIZE (1024 * 1) */ + +/* Defined, this value represents the size of the log pool. +*/ +#define UX_DEBUG_LOG_SIZE (1024 * 16) + + +/* Defined, this disables the assert checks inside usbx. */ +#ifndef UX_DISABLE_ASSERT +#define UX_ENABLE_ASSERT +#endif + +/* Defined, this defines the assert action taken when failure detected. By default + it halts without any output. */ +void ux_test_assert_hit(char* file, int line); +#define UX_ASSERT_FAIL ux_test_assert_hit(__FILE__, __LINE__); + + +/* DEBUG includes and macros for a specific platform go here. */ +#ifdef UX_INCLUDE_USER_DEFINE_BSP +#include "usb_bsp.h" +#include "usbh_hcs.h" +#include "usbh_stdreq.h" +#include "usbh_core.h" +#endif + +#endif + diff --git a/test/regression/usbx_audio10_device_basic_test.c b/test/regression/usbx_audio10_device_basic_test.c new file mode 100644 index 00000000..5dfbe807 --- /dev/null +++ b/test/regression/usbx_audio10_device_basic_test.c @@ -0,0 +1,1252 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" + +#include "fx_api.h" + +#include "ux_device_class_audio.h" +#include "ux_device_stack.h" + +#include "ux_host_class_audio.h" +#include "ux_host_class_dummy.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_DEMO_REQUEST_MAX_LENGTH \ + ((UX_HCD_SIM_HOST_MAX_PAYLOAD) > (UX_SLAVE_REQUEST_DATA_MAX_LENGTH) ? \ + (UX_HCD_SIM_HOST_MAX_PAYLOAD) : (UX_SLAVE_REQUEST_DATA_MAX_LENGTH)) + +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_DEMO_REQUEST_MAX_LENGTH + 1) +#define UX_DEMO_MEMORY_SIZE (128*1024) + +#define UX_TEST_LOG_SIZE (64) + + +/* Define local/extern function prototypes. */ +static void test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static void tx_test_thread_host_simulation_entry(ULONG); +static void tx_test_thread_slave_simulation_entry(ULONG); + + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +static UX_HOST_CLASS_DUMMY *dummy_control; +static UX_HOST_CLASS_DUMMY *dummy_tx; +static UX_HOST_CLASS_DUMMY *dummy_rx; + +static UX_DEVICE_CLASS_AUDIO *slave_audio_tx; +static UX_DEVICE_CLASS_AUDIO_STREAM *slave_audio_tx_stream; +static UX_DEVICE_CLASS_AUDIO_PARAMETER slave_audio_tx_parameter; +static UX_DEVICE_CLASS_AUDIO_STREAM_PARAMETER slave_audio_tx_stream_parameter; + +static UX_DEVICE_CLASS_AUDIO *slave_audio_rx; +static UX_DEVICE_CLASS_AUDIO_STREAM *slave_audio_rx_stream; +static UX_DEVICE_CLASS_AUDIO_PARAMETER slave_audio_rx_parameter; +static UX_DEVICE_CLASS_AUDIO_STREAM_PARAMETER slave_audio_rx_stream_parameter; +static UX_SLAVE_TRANSFER *slave_audio_rx_transfer; + +static UX_HOST_CLASS_AUDIO *audio; + +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_audio_sem_usage; +static ULONG rsc_audio_sem_get_count; +static ULONG rsc_audio_mutex_usage; +static ULONG rsc_audio_mem_usage; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +static struct BUFFER_LOG_STRUCT { + ULONG length; + UCHAR data[256]; +} buffer_log[UX_TEST_LOG_SIZE]; +static ULONG buffer_log_count = 0; +#define SAVE_BUFFER_LOG(buf,siz) do { \ + if (buffer_log_count < UX_TEST_LOG_SIZE) { \ + ULONG __local_size__ = ((siz) > 256) ? 256 : (siz); \ + buffer_log[buffer_log_count].length = (siz); \ + _ux_utility_memory_copy(buffer_log[buffer_log_count].data, (buf), __local_size__); \ + } \ + buffer_log_count ++; \ +} while(0) + +static ULONG test_tx_ack_count = 0xFFFFFFFF; +static ULONG test_tx_ins_count = 0; +static ULONG test_tx_ins_way = 0; + +static struct CALLBACK_INVOKE_LOG_STRUCT { + VOID *func; + VOID *param1; + VOID *param2; + VOID *param3; +} callback_invoke_log[UX_TEST_LOG_SIZE]; +static ULONG callback_invoke_count = 0; + +#define SAVE_CALLBACK_INVOKE_LOG(f,p1,p2,p3) do { \ + if (callback_invoke_count < UX_TEST_LOG_SIZE) { \ + callback_invoke_log[callback_invoke_count].func = (VOID *)(f); \ + callback_invoke_log[callback_invoke_count].param1 = (VOID *)(p1); \ + callback_invoke_log[callback_invoke_count].param2 = (VOID *)(p2); \ + callback_invoke_log[callback_invoke_count].param3 = (VOID *)(p3); \ + callback_invoke_count++; \ + } \ +} while(0) +#define RESET_CALLBACK_INVOKE_LOG() do { \ + callback_invoke_count = 0; \ +} while(0) + +/* Define device framework. */ + +#define D3(d) ((UCHAR)((d) >> 24)) +#define D2(d) ((UCHAR)((d) >> 16)) +#define D1(d) ((UCHAR)((d) >> 8)) +#define D0(d) ((UCHAR)((d) >> 0)) + +static unsigned char device_framework_full_speed[] = { + +/* --------------------------------------- Device Descriptor */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 0x08, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x01, 0x00, +/* 12 bcdDevice */ D0(0x100),D1(0x100), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* -------------------------------- Configuration Descriptor *//* 9+81+52*2=194 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(194),D1(194), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+72=81) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x00, +/* 8 iInterface */ 0, +/* ---------------- Audio 1.0 AC Interface Header Descriptor *//* (10+12*2+10*2+9*2=72) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x01, +/* 3 bcdADC */ 0x00, 0x01, +/* 5 wTotalLength, bInCollection */ D0(72),D1(72), 2, +/* 8 baInterfaceNr(1) ... baInterfaceNr(n) */ 1, 2, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x02, +/* 8 iTerminal */ 0, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x05, +/* 8 iTerminal */ 0, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x03, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 1, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x04, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 1, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { +/* --------------------------------------- Device Descriptor */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x01, 0x00, +/* 12 bcdDevice */ D0(0x100),D1(0x100), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* ----------------------------- Device Qualifier Descriptor */ +/* 0 bLength, bDescriptorType */ 10, 0x06, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 bNumConfigurations */ 1, +/* 9 bReserved */ 0, + +/* -------------------------------- Configuration Descriptor *//* 9+81+52*2=194 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(194),D1(194), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+72=81) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x00, +/* 8 iInterface */ 0, +/* ---------------- Audio 1.0 AC Interface Header Descriptor *//* (10+12*2+10*2+9*2=72) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x01, +/* 3 bcdADC */ 0x00, 0x01, +/* 5 wTotalLength, bInCollection */ D0(72),D1(72), 2, +/* 8 baInterfaceNr(1) ... baInterfaceNr(n) */ 1, 2, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x02, +/* 8 iTerminal */ 0, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x05, +/* 8 iTerminal */ 0, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x03, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 4, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x04, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 4, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + +/* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + +/* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + +/* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; +static UX_TEST_SETUP _GetCfgDescr = UX_TEST_SETUP_GetCfgDescr; +static UX_TEST_SETUP _SetAddress = UX_TEST_SETUP_SetAddress; +static UX_TEST_SETUP _GetDeviceDescriptor = UX_TEST_SETUP_GetDevDescr; +static UX_TEST_SETUP _GetConfigDescriptor = UX_TEST_SETUP_GetCfgDescr; + +/* Interaction define */ + +/* Hooks define */ + +static VOID ux_device_class_audio_tx_hook(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *p = (UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *)params; +UX_SLAVE_TRANSFER *transfer = (UX_SLAVE_TRANSFER *)p -> parameter; +UCHAR tmp[32] = {'i','n','s','e','r','t','A',0}; + + + (void)params; + // printf("tTX\n"); + + /* Acknowledge frame sent. */ + if (test_tx_ack_count) + { + SAVE_BUFFER_LOG(transfer -> ux_slave_transfer_request_data_pointer, transfer -> ux_slave_transfer_request_requested_length); + transfer -> ux_slave_transfer_request_actual_length = transfer -> ux_slave_transfer_request_requested_length; + transfer -> ux_slave_transfer_request_completion_code = UX_SUCCESS; + ux_test_dcd_sim_slave_transfer_done(transfer, UX_SUCCESS); + } + if (test_tx_ack_count != 0xFFFFFFFF && test_tx_ack_count > 0) + test_tx_ack_count --; + + /* Insert frames when sent. */ + if (test_tx_ins_count) + { + tmp[6] = (test_tx_ins_count % 26) + 'A'; + if (test_tx_ins_way == 0) + ux_device_class_audio_frame_write(slave_audio_tx_stream, tmp, 32); + else + { + + UCHAR *frame; + ULONG frame_length; + + + ux_device_class_audio_write_frame_get(slave_audio_tx_stream, &frame, &frame_length); + _ux_utility_memory_copy(frame, tmp, 32); + ux_device_class_audio_write_frame_commit(slave_audio_tx_stream, 32); + } + } + if (test_tx_ins_count != 0xFFFFFFFF && test_tx_ins_count > 0) + test_tx_ins_count --; +} + +static VOID ux_device_class_audio_rx_hook(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *p = (UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *)params; +UX_SLAVE_TRANSFER *transfer = (UX_SLAVE_TRANSFER *)p -> parameter; + + + (void)action; + (void)params; + (void)p; + (void)transfer; + // printf("tRX\n"); + slave_audio_rx_transfer = transfer; +} +static VOID slave_audio_rx_simulate_one_frame(UCHAR *frame, ULONG frame_length) +{ + UX_TEST_ASSERT(slave_audio_rx_transfer); + if (frame_length) + { + _ux_utility_memory_copy(slave_audio_rx_transfer->ux_slave_transfer_request_data_pointer, frame, frame_length); + slave_audio_rx_transfer->ux_slave_transfer_request_actual_length = frame_length; + slave_audio_rx_transfer->ux_slave_transfer_request_completion_code = UX_SUCCESS; + } + ux_test_dcd_sim_slave_transfer_done(slave_audio_rx_transfer, UX_SUCCESS); + _ux_utility_thread_sleep(1); +} + +static UX_TEST_ACTION ux_device_class_audio_transfer_hook[] = +{ + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .action_func = ux_device_class_audio_tx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x81, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .action_func = ux_device_class_audio_rx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x02, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, +{ 0 }, +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* 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 ++; + // printf("Error #%d, system_level: %d, system_context: %d, error_code: 0x%x\n", __LINE__, system_level, system_context, error_code); + + if (!error_callback_ignore) + { + { + /* Failed test. */ + 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 VOID slave_audio_tx_activate(VOID *audio_instance) +{ + slave_audio_tx = (UX_DEVICE_CLASS_AUDIO *)audio_instance; + ux_device_class_audio_stream_get(slave_audio_tx, 0, &slave_audio_tx_stream); + // printf("sAUD_tx:%p,%p\n", audio_instance, slave_audio_tx_stream); +} +static VOID slave_audio_rx_activate(VOID *audio_instance) +{ + slave_audio_rx = (UX_DEVICE_CLASS_AUDIO *)audio_instance; + ux_device_class_audio_stream_get(slave_audio_rx, 0, &slave_audio_rx_stream); + // printf("sAUD_rx:%p,%p\n", audio_instance, slave_audio_rx_stream); +} +static VOID slave_audio_deactivate(VOID *audio_instance) +{ + if ((VOID *)slave_audio_rx == audio_instance) + { + slave_audio_rx = UX_NULL; + slave_audio_rx_stream = UX_NULL; + } + if ((VOID *)slave_audio_tx == audio_instance) + slave_audio_tx = UX_NULL; + slave_audio_tx_stream = UX_NULL; +} +static VOID slave_audio_tx_stream_change(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG alt) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_tx_stream_change, audio, (ALIGN_TYPE)alt, 0); +} +static VOID slave_audio_rx_stream_change(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG alt) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_rx_stream_change, audio, (ALIGN_TYPE)alt, 0); + + slave_audio_rx_transfer = UX_NULL; +} +static UINT slave_audio_control_process(UX_DEVICE_CLASS_AUDIO *audio, UX_SLAVE_TRANSFER *transfer) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_control_process, audio, transfer, 0); + return(UX_ERROR); +} +static VOID slave_audio_tx_done(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG length) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_tx_done, audio, (ALIGN_TYPE)length, 0); +} +static VOID slave_audio_rx_done(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG length) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_rx_done, audio, (ALIGN_TYPE)length, 0); +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_DUMMY *dummy = (UX_HOST_CLASS_DUMMY *) inst; + + + switch(event) + { + + case UX_DEVICE_INSERTION: + + // printf("hINS:%p,%p:%ld\n", cls, inst, dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber); + switch(dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber) + { + case 0: dummy_control = dummy; break; + case 1: dummy_rx = dummy; break; + case 2: dummy_tx = dummy; break; + } + break; + + case UX_DEVICE_REMOVAL: + + // printf("hRMV:%p,%p:%ld\n", cls, inst, dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber); + switch(dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber) + { + case 0: dummy_control = UX_NULL; break; + case 1: dummy_rx = UX_NULL; break; + case 2: dummy_tx = UX_NULL; break; + } + break; + + default: + break; + } + return 0; +} + + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_audio10_device_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ +#if !UX_TEST_MULTI_IFC_ON || !UX_TEST_MULTI_ALT_ON || !UX_TEST_MULTI_CLS_ON + printf("Running Audio 1.0 Device Basic Functionality Test...............SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + + printf("Running Audio 1.0 Device Basic Functionality Test................... "); + + stepinfo("\n"); + + /* 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(); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* 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_host_change_function); + UX_TEST_CHECK_SUCCESS(status); + + /* Register Audio class. */ + status = ux_host_stack_class_register(_ux_host_class_dummy_name, _ux_host_class_dummy_entry); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Set the parameters for callback when insertion/extraction of a Audio 1.0 device, no IAD. */ + ux_utility_memory_set(&slave_audio_tx_stream_parameter, 0, sizeof(slave_audio_tx_stream_parameter)); + ux_utility_memory_set(&slave_audio_rx_stream_parameter, 0, sizeof(slave_audio_rx_stream_parameter)); +#if !defined(UX_DEVICE_STANDALONE) + slave_audio_tx_stream_parameter.ux_device_class_audio_stream_parameter_thread_entry = ux_device_class_audio_write_thread_entry; +#else + slave_audio_tx_stream_parameter.ux_device_class_audio_stream_parameter_task_function = _ux_device_class_audio_write_task_function; +#endif + slave_audio_tx_stream_parameter.ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_change = slave_audio_tx_stream_change; + slave_audio_tx_stream_parameter.ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_frame_done = slave_audio_tx_done; + slave_audio_tx_stream_parameter.ux_device_class_audio_stream_parameter_max_frame_buffer_size = 256; + slave_audio_tx_stream_parameter.ux_device_class_audio_stream_parameter_max_frame_buffer_nb = 8; + slave_audio_tx_parameter.ux_device_class_audio_parameter_streams = &slave_audio_tx_stream_parameter; + slave_audio_tx_parameter.ux_device_class_audio_parameter_streams_nb = 1; + slave_audio_tx_parameter.ux_device_class_audio_parameter_callbacks.ux_slave_class_audio_instance_activate = slave_audio_tx_activate; + slave_audio_tx_parameter.ux_device_class_audio_parameter_callbacks.ux_slave_class_audio_instance_deactivate = slave_audio_deactivate; + slave_audio_tx_parameter.ux_device_class_audio_parameter_callbacks.ux_device_class_audio_control_process = slave_audio_control_process; + slave_audio_tx_parameter.ux_device_class_audio_parameter_callbacks.ux_device_class_audio_arg = UX_NULL; + +#if !defined(UX_DEVICE_STANDALONE) + slave_audio_rx_stream_parameter.ux_device_class_audio_stream_parameter_thread_entry = ux_device_class_audio_read_thread_entry; +#else + slave_audio_rx_stream_parameter.ux_device_class_audio_stream_parameter_task_function = _ux_device_class_audio_read_task_function; +#endif + slave_audio_rx_stream_parameter.ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_change = slave_audio_rx_stream_change; + slave_audio_rx_stream_parameter.ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_frame_done = slave_audio_rx_done; + slave_audio_rx_stream_parameter.ux_device_class_audio_stream_parameter_max_frame_buffer_size = 256; + slave_audio_rx_stream_parameter.ux_device_class_audio_stream_parameter_max_frame_buffer_nb = 8; + slave_audio_rx_parameter.ux_device_class_audio_parameter_streams = &slave_audio_rx_stream_parameter; + slave_audio_rx_parameter.ux_device_class_audio_parameter_streams_nb = 1; + slave_audio_rx_parameter.ux_device_class_audio_parameter_callbacks.ux_slave_class_audio_instance_activate = slave_audio_rx_activate; + slave_audio_rx_parameter.ux_device_class_audio_parameter_callbacks.ux_slave_class_audio_instance_deactivate = slave_audio_deactivate; + slave_audio_rx_parameter.ux_device_class_audio_parameter_callbacks.ux_device_class_audio_control_process = slave_audio_control_process; + slave_audio_rx_parameter.ux_device_class_audio_parameter_callbacks.ux_device_class_audio_arg = UX_NULL; + +#if defined(UX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT) + slave_audio_tx_parameter.ux_device_class_audio_parameter_status_queue_size = 2; + slave_audio_tx_parameter.ux_device_class_audio_parameter_status_size = 8; /* Actually 6 bytes in length. */ + slave_audio_rx_parameter.ux_device_class_audio_parameter_status_queue_size = 2; + slave_audio_rx_parameter.ux_device_class_audio_parameter_status_size = 8; /* Actually 6 bytes in length. */ +#endif + +#if 0 + printf("Memory requirement UX_DEVICE_CLASS_:\n"); + printf(" per _AUDIO: %d bytes\n", sizeof(UX_DEVICE_CLASS_AUDIO)); + printf(" per _AUDIO_STREAM: %d bytes\n", sizeof(UX_DEVICE_CLASS_AUDIO_STREAM)); + printf(" per _AUDIO_CONTROL: %d bytes\n", sizeof(UX_DEVICE_CLASS_AUDIO_CONTROL)); + printf("Dynamic memory allocation:\n"); + temp = (slave_audio_tx_stream_parameter.ux_device_class_audio_stream_parameter_max_frame_buffer_size+8) * + slave_audio_tx_stream_parameter.ux_device_class_audio_stream_parameter_max_frame_buffer_nb; + printf(" per _frame_buffer_size: (%ld + 8) * %ld = %ld\n", + slave_audio_tx_stream_parameter.ux_device_class_audio_stream_parameter_max_frame_buffer_size, + slave_audio_tx_stream_parameter.ux_device_class_audio_stream_parameter_max_frame_buffer_nb, + temp); + temp += sizeof(UX_DEVICE_CLASS_AUDIO_STREAM); + printf(" per _stream: _AUDIO_STREAM + _frame_buffer_size = %ld\n", temp); + temp += sizeof(UX_DEVICE_CLASS_AUDIO); + temp *= 2; + printf(" per _audio: (_AUDIO + _stream * 1 + _CONTROL * 0) * 2 = %ld\n", temp); +#endif + + /* Initialize the device Audio class. This class owns interfaces starting with 1, 2. */ + status = ux_device_stack_class_register(_ux_system_slave_class_audio_name, ux_device_class_audio_entry, + 1, 1, &slave_audio_tx_parameter); + status |= ux_device_stack_class_register(_ux_system_slave_class_audio_name, ux_device_class_audio_entry, + 1, 2, &slave_audio_rx_parameter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + UX_TEST_CHECK_SUCCESS(status); +#endif + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx demo host simulation", tx_test_thread_host_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx demo slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_CHECK_SUCCESS(status); +} + +static UINT test_wait_until_expected(VOID **ptr, ULONG loop, VOID *expected) +{ + while(loop) + { + _ux_utility_delay_ms(10); + if (*ptr == expected) + return UX_SUCCESS; + } + return UX_ERROR; +} +static UINT test_wait_until_not_expected(VOID **ptr, ULONG loop, VOID *expected) +{ + while(loop) + { + _ux_utility_delay_ms(10); + if (*ptr != expected) + return UX_SUCCESS; + } + return UX_ERROR; +} +#define test_wait_until_not_null(ptr, loop) test_wait_until_not_expected(ptr, loop, UX_NULL) +#define test_wait_until_null(ptr, loop) test_wait_until_expected(ptr, loop, UX_NULL) + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +// ULONG mem_free; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +UX_INTERFACE *interface_inst[3][2]; +// UX_ENDPOINT *control_endpoint; +// UX_TRANSFER *transfer_request; +UCHAR test_cmp[32]; +ULONG temp; + + + /* Test connect. */ + status = test_wait_until_not_null((void**)&dummy_control, 100); + status |= test_wait_until_not_null((void**)&dummy_tx, 100); + status |= test_wait_until_not_null((void**)&dummy_rx, 100); + status |= test_wait_until_not_null((void**)&slave_audio_tx, 100); + status |= test_wait_until_not_null((void**)&slave_audio_rx, 100); + UX_TEST_CHECK_SUCCESS(status); + + // /* Test disconnect. */ + // ux_test_dcd_sim_slave_disconnect(); + // ux_test_hcd_sim_host_disconnect(); + + // /* Reset testing counts. */ + // ux_test_utility_sim_mutex_create_count_reset(); + // ux_test_utility_sim_sem_create_count_reset(); + // ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + // /* Save free memory usage. */ + // mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + // ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + // ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + // tx_thread_sleep(100); + // /* Log create counts for further tests. */ + // rsc_enum_mutex_usage = rsc_mutex_on_set_cfg; + // rsc_enum_sem_usage = rsc_sem_on_set_cfg; + // rsc_enum_mem_usage = mem_free - rsc_mem_free_on_set_cfg; + // /* Log create counts when instances active for further tests. */ + // rsc_cdc_mutex_usage = ux_test_utility_sim_mutex_create_count() - rsc_enum_mutex_usage; + // rsc_cdc_sem_usage = ux_test_utility_sim_sem_create_count() - rsc_enum_sem_usage; + // rsc_cdc_mem_usage = rsc_mem_free_on_set_cfg - _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + // stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + + /* Validate configuration descriptors. */ + /* ... */ + + /* Get testing instances. */ + + status = ux_host_stack_device_get(0, &device); + UX_TEST_CHECK_SUCCESS(status); + + // control_endpoint = &device->ux_device_control_endpoint; + // transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + status = ux_host_stack_device_configuration_get(device, 0, &configuration); + UX_TEST_CHECK_SUCCESS(status); + + interface = configuration -> ux_configuration_first_interface; + while(interface) + { + // printf("Interface: %ld.%ld\n", interface -> ux_interface_descriptor.bInterfaceNumber, interface -> ux_interface_descriptor.bAlternateSetting); + interface_inst[interface -> ux_interface_descriptor.bInterfaceNumber][interface -> ux_interface_descriptor.bAlternateSetting] = interface; + interface = interface -> ux_interface_next_interface; + } + + /* Test interface change. */ + /* Reset log. */ + RESET_CALLBACK_INVOKE_LOG(); + status = ux_host_stack_interface_setting_select(interface_inst[1][1]); + status |= ux_host_stack_interface_setting_select(interface_inst[1][0]); + status |= ux_host_stack_interface_setting_select(interface_inst[1][1]); + + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(callback_invoke_count == 3); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_tx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_tx_stream); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (VOID*)1); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_tx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_tx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].param2 == 0); + + RESET_CALLBACK_INVOKE_LOG(); + status = ux_host_stack_interface_setting_select(interface_inst[2][1]); + status |= ux_host_stack_interface_setting_select(interface_inst[2][0]); + status |= ux_host_stack_interface_setting_select(interface_inst[2][1]); + + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(callback_invoke_count == 3); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_rx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (VOID*)1); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_rx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].param2 == 0); + + /* Test data streaming. */ + + /* Wrong interface! */ + status = ux_device_class_audio_transmission_start(slave_audio_rx_stream); + status |= ux_device_class_audio_reception_start(slave_audio_tx_stream); + UX_TEST_CHECK_NOT_SUCCESS(status); + + ux_test_link_hooks_from_array(ux_device_class_audio_transfer_hook); + + /* ------------------ Write test. */ + + status = ux_device_class_audio_frame_write(slave_audio_tx_stream, "test0", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test1", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test2", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test3", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test4", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test5", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test6", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test7", 16); + UX_TEST_CHECK_SUCCESS(status); + + error_callback_counter = 0; + status = ux_device_class_audio_frame_write(slave_audio_tx_stream, "test8", 16); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + /* + Keep sending until under-run. + No buffer appended while running. + */ + + buffer_log_count = 0; + test_tx_ack_count = 10; + status = ux_device_class_audio_transmission_start(slave_audio_tx_stream); + UX_TEST_CHECK_SUCCESS(status); + + /* Delay to let thread runs. */ + _ux_utility_delay_ms(100); + + /* Prepare data for checking. */ + _ux_utility_memory_set(test_cmp, 0, 16); + _ux_utility_memory_copy(test_cmp, "test", 4); + + /* 8 frame should be available. */ + for (test_n = 0; test_n < 8; test_n ++) + { + // printf("%ld: %ld: %s\n", test_n, buffer_log[test_n].length, buffer_log[test_n].data); + test_cmp[4] = (UCHAR)(test_n + '0'); + + UX_TEST_ASSERT(buffer_log[test_n].length == 16); + + status = _ux_utility_memory_compare(buffer_log[test_n].data, test_cmp, 6); + UX_TEST_CHECK_SUCCESS(status); + } + /* Then under-run, 0 length packets. */ + for(;test_n < buffer_log_count; test_n ++) + { + // printf("%ld: %ld\n", test_n, buffer_log[test_n].length); + UX_TEST_ASSERT(buffer_log[test_n].length == 0); + } + + /* + Keep sending until under-run. + Specific number of buffer appended while running. + */ + + for (test_tx_ins_way = 0; test_tx_ins_way < 2; test_tx_ins_way ++) + { + + /* Switch interface to clean up status. */ + status = ux_host_stack_interface_setting_select(interface_inst[1][0]); + status |= ux_host_stack_interface_setting_select(interface_inst[1][1]); + + status = ux_device_class_audio_frame_write(slave_audio_tx_stream, "test0", 20); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test1", 20); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test2", 20); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test3", 20); + UX_TEST_CHECK_SUCCESS(status); + + test_tx_ins_count = 10; + test_tx_ack_count = 20; + buffer_log_count = 0; + status = ux_device_class_audio_transmission_start(slave_audio_tx_stream); + UX_TEST_CHECK_SUCCESS(status); + + /* Delay to let thread runs. */ + _ux_utility_delay_ms(300); + + /* Prepare data for checking. */ + _ux_utility_memory_set(test_cmp, 0, 32); + + /* 4 frame should be available. */ + _ux_utility_memory_copy(test_cmp, "test", 4); + for (test_n = 0; test_n < 4; test_n ++) + { + // printf("%ld: %ld: %s\n", test_n, buffer_log[test_n].length, buffer_log[test_n].data); + test_cmp[4] = (UCHAR)(test_n + '0'); + + UX_TEST_ASSERT(buffer_log[test_n].length == 20); + + status = _ux_utility_memory_compare(buffer_log[test_n].data, test_cmp, 6); + UX_TEST_CHECK_SUCCESS(status); + } + /* 10 more frame should be available. */ + _ux_utility_memory_copy(test_cmp, "insert", 6); + for (; test_n < 14; test_n ++) + { + // printf("%ld: %ld: %s\n", test_n, buffer_log[test_n].length, buffer_log[test_n].data); + test_cmp[6] = (UCHAR)(((10 - (test_n - 4)) % 26) + 'A'); + + UX_TEST_ASSERT(buffer_log[test_n].length == 32); + + status = _ux_utility_memory_compare(buffer_log[test_n].data, test_cmp, 8); + UX_TEST_CHECK_SUCCESS(status); + } + /* Then under-run, 0 length packets. */ + for(;test_n < buffer_log_count; test_n ++) + { + // printf("%ld: %ld\n", test_n, buffer_log[test_n].length); + UX_TEST_ASSERT(buffer_log[test_n].length == 0); + } + } + + UX_TEST_ASSERT(slave_audio_tx_stream->ux_device_class_audio_stream_transfer_pos == slave_audio_tx_stream->ux_device_class_audio_stream_access_pos); + + /* ------------------ Read - 8 test. */ + + UX_TEST_ASSERT(slave_audio_rx_transfer == UX_NULL); + + temp = 0; + status = ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + status = ux_device_class_audio_reception_start(slave_audio_rx_stream); + UX_TEST_CHECK_SUCCESS(status); + _ux_utility_thread_sleep(1); + + UX_TEST_ASSERT(slave_audio_rx_transfer != UX_NULL); + + status = ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + RESET_CALLBACK_INVOKE_LOG(); + + slave_audio_rx_simulate_one_frame("012345", 6); + for (test_n = 0; test_n < 6; test_n ++) + { + status = ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(temp == (test_n + '0')); + } + + slave_audio_rx_simulate_one_frame("012345", 6); + slave_audio_rx_simulate_one_frame("67", 2); + slave_audio_rx_simulate_one_frame("89", 2); + + for (test_n = 0; test_n < 10; test_n ++) + { + status = ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(temp == (test_n + '0')); + } + + UX_TEST_ASSERT(callback_invoke_count == 4); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[2].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[2].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[3].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[3].param1 == slave_audio_rx_stream); + + RESET_CALLBACK_INVOKE_LOG(); + error_callback_counter = 0; + for (test_n = 0; test_n < 10; test_n ++) + { + test_cmp[0] = (UCHAR)(test_n + '0'); + slave_audio_rx_simulate_one_frame(test_cmp, 1); + } + + UX_TEST_ASSERT(callback_invoke_count == 10); + UX_TEST_ASSERT(error_callback_counter == 3); + for (test_n = 0; test_n < 7; test_n ++) + { + status = ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp); + UX_TEST_CHECK_SUCCESS(status); + // printf("(%lx)%c\n", temp, (char)temp); + UX_TEST_ASSERT(temp == (test_n + '0')); + } + UX_TEST_CHECK_SUCCESS(ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp)); + UX_TEST_ASSERT(temp == '9'); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp)); + + /* ------------------ Read - 16 test. */ + + status = ux_device_class_audio_sample_read16(slave_audio_rx_stream, (USHORT *)&temp); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + RESET_CALLBACK_INVOKE_LOG(); + slave_audio_rx_simulate_one_frame("012345", 6); + slave_audio_rx_simulate_one_frame("67", 2); + UX_TEST_ASSERT(callback_invoke_count == 2); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (VOID*)6); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].param2 == (VOID*)2); + for (test_n = 0; test_n < 4; test_n ++) + { + status = ux_device_class_audio_sample_read16(slave_audio_rx_stream, (USHORT *)&temp); + UX_TEST_CHECK_SUCCESS(status); + // printf("%lx\n", temp); + test_cmp[0] = (UCHAR)(test_n * 2 + '0'); + test_cmp[1] = (UCHAR)(test_n * 2 + '1'); + UX_TEST_CHECK_SUCCESS(_ux_utility_memory_compare(test_cmp, &temp, 2)); + } + + /* ------------------ Read - 24 test. */ + + status = ux_device_class_audio_sample_read24(slave_audio_rx_stream, &temp); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + RESET_CALLBACK_INVOKE_LOG(); + slave_audio_rx_simulate_one_frame("012345", 6); + slave_audio_rx_simulate_one_frame("678", 3); + UX_TEST_ASSERT(callback_invoke_count == 2); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (VOID*)6); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].param2 == (VOID*)3); + for (test_n = 0; test_n < 3; test_n ++) + { + status = ux_device_class_audio_sample_read24(slave_audio_rx_stream, &temp); + UX_TEST_CHECK_SUCCESS(status); + // printf("%lx\n", temp); + test_cmp[0] = (UCHAR)(test_n * 3 + '0'); + test_cmp[1] = (UCHAR)(test_n * 3 + '1'); + test_cmp[2] = (UCHAR)(test_n * 3 + '2'); + UX_TEST_CHECK_SUCCESS(_ux_utility_memory_compare(test_cmp, &temp, 3)); + } + + /* ------------------ Read - 32 test. */ + + status = ux_device_class_audio_sample_read32(slave_audio_rx_stream, &temp); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + RESET_CALLBACK_INVOKE_LOG(); + slave_audio_rx_simulate_one_frame("01234567", 8); + slave_audio_rx_simulate_one_frame("8901", 4); + UX_TEST_ASSERT(callback_invoke_count == 2); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (VOID*)8); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].param2 == (VOID*)4); + for (test_n = 0; test_n < 3; test_n ++) + { + status = ux_device_class_audio_sample_read32(slave_audio_rx_stream, &temp); + UX_TEST_CHECK_SUCCESS(status); + // printf("%lx\n", temp); + test_cmp[0] = ((test_n * 4 + 0) % 10) + '0'; + test_cmp[1] = ((test_n * 4 + 1) % 10) + '0'; + test_cmp[2] = ((test_n * 4 + 2) % 10) + '0'; + test_cmp[3] = ((test_n * 4 + 3) % 10) + '0'; + UX_TEST_CHECK_SUCCESS(_ux_utility_memory_compare(test_cmp, &temp, 4)); + } + + UX_TEST_ASSERT(slave_audio_tx_stream->ux_device_class_audio_stream_transfer_pos == slave_audio_tx_stream->ux_device_class_audio_stream_access_pos); + + + /* Wait pending threads. */ + _ux_utility_thread_sleep(1); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + ux_device_stack_class_unregister(_ux_system_slave_class_audio_name, ux_device_class_audio_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + + /* Standalone background task. */ + ux_system_tasks_run(); +#else + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); +#endif + } +} diff --git a/test/regression/usbx_audio10_device_feedback_test.c b/test/regression/usbx_audio10_device_feedback_test.c new file mode 100644 index 00000000..cac92206 --- /dev/null +++ b/test/regression/usbx_audio10_device_feedback_test.c @@ -0,0 +1,1344 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" + +#include "fx_api.h" + +#include "ux_device_class_audio.h" +#include "ux_device_stack.h" + +#include "ux_host_class_audio.h" +#include "ux_host_class_dummy.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_DEMO_REQUEST_MAX_LENGTH \ + ((UX_HCD_SIM_HOST_MAX_PAYLOAD) > (UX_SLAVE_REQUEST_DATA_MAX_LENGTH) ? \ + (UX_HCD_SIM_HOST_MAX_PAYLOAD) : (UX_SLAVE_REQUEST_DATA_MAX_LENGTH)) + +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_DEMO_REQUEST_MAX_LENGTH + 1) +#define UX_DEMO_MEMORY_SIZE (128*1024) + +#define UX_TEST_LOG_SIZE (64) + + +/* Define local/extern function prototypes. */ +static void test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static void tx_test_thread_host_simulation_entry(ULONG); +static void tx_test_thread_slave_simulation_entry(ULONG); + + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +static UX_HOST_CLASS_DUMMY *dummy_control; +static UX_HOST_CLASS_DUMMY *dummy_tx; +static UX_HOST_CLASS_DUMMY *dummy_rx; + +static UX_DEVICE_CLASS_AUDIO *slave_audio_tx; +static UX_DEVICE_CLASS_AUDIO_STREAM *slave_audio_tx_stream; +static UX_DEVICE_CLASS_AUDIO_PARAMETER slave_audio_tx_parameter; +static UX_DEVICE_CLASS_AUDIO_STREAM_PARAMETER slave_audio_tx_stream_parameter; + +static UX_DEVICE_CLASS_AUDIO *slave_audio_rx; +static UX_DEVICE_CLASS_AUDIO_STREAM *slave_audio_rx_stream; +static UX_DEVICE_CLASS_AUDIO_PARAMETER slave_audio_rx_parameter; +static UX_DEVICE_CLASS_AUDIO_STREAM_PARAMETER slave_audio_rx_stream_parameter; +static UX_SLAVE_TRANSFER *slave_audio_rx_transfer; + +static ULONG device_audio_tx_feedback; +static UCHAR* device_audio_tx_feedback_u8a = (UCHAR*)&device_audio_tx_feedback; +static ULONG device_audio_tx_feedback_count; +static ULONG device_audio_rx_feedback; +static UCHAR* device_audio_rx_feedback_u8a = (UCHAR*)&device_audio_rx_feedback; +static ULONG device_audio_rx_feedback_count; + + +static UX_HOST_CLASS_AUDIO *audio; + +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_audio_sem_usage; +static ULONG rsc_audio_sem_get_count; +static ULONG rsc_audio_mutex_usage; +static ULONG rsc_audio_mem_usage; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +static struct BUFFER_LOG_STRUCT { + ULONG length; + UCHAR data[256]; +} buffer_log[UX_TEST_LOG_SIZE]; +static ULONG buffer_log_count = 0; +#define SAVE_BUFFER_LOG(buf,siz) do { \ + if (buffer_log_count < UX_TEST_LOG_SIZE) { \ + ULONG __local_size__ = ((siz) > 256) ? 256 : (siz); \ + buffer_log[buffer_log_count].length = (siz); \ + _ux_utility_memory_copy(buffer_log[buffer_log_count].data, (buf), __local_size__); \ + } \ + buffer_log_count ++; \ +} while(0) + +static ULONG test_tx_ack_count = 0xFFFFFFFF; +static ULONG test_tx_ins_count = 0; +static ULONG test_tx_ins_way = 0; + +static struct CALLBACK_INVOKE_LOG_STRUCT { + VOID *func; + VOID *param1; + VOID *param2; + VOID *param3; +} callback_invoke_log[UX_TEST_LOG_SIZE]; +static ULONG callback_invoke_count = 0; + +#define SAVE_CALLBACK_INVOKE_LOG(f,p1,p2,p3) do { \ + if (callback_invoke_count < UX_TEST_LOG_SIZE) { \ + callback_invoke_log[callback_invoke_count].func = (VOID *)(f); \ + callback_invoke_log[callback_invoke_count].param1 = (VOID *)(p1); \ + callback_invoke_log[callback_invoke_count].param2 = (VOID *)(p2); \ + callback_invoke_log[callback_invoke_count].param3 = (VOID *)(p3); \ + callback_invoke_count++; \ + } \ +} while(0) +#define RESET_CALLBACK_INVOKE_LOG() do { \ + callback_invoke_count = 0; \ +} while(0) + +/* Define device framework. */ + +#define D3(d) ((UCHAR)((d) >> 24)) +#define D2(d) ((UCHAR)((d) >> 16)) +#define D1(d) ((UCHAR)((d) >> 8)) +#define D0(d) ((UCHAR)((d) >> 0)) + +static unsigned char device_framework_full_speed[] = { + +/* --------------------------------------- Device Descriptor */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 0x08, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x01, 0x00, +/* 12 bcdDevice */ D0(0x100),D1(0x100), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* -------------------------------- Configuration Descriptor *//* 9+81+52*2=194 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(194+18),D1(194+18), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+72=81) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x00, +/* 8 iInterface */ 0, +/* ---------------- Audio 1.0 AC Interface Header Descriptor *//* (10+12*2+10*2+9*2=72) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x01, +/* 3 bcdADC */ 0x00, 0x01, +/* 5 wTotalLength, bInCollection */ D0(72),D1(72), 2, +/* 8 baInterfaceNr(1) ... baInterfaceNr(n) */ 1, 2, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x02, +/* 8 iTerminal */ 0, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x05, +/* 8 iTerminal */ 0, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 2, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x03, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 1, 0, 0x01, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +/* --------------------- Audio 1.0 AS ISO Feedback Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x01, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(4),D1(4), 1, 4, 0x00, + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 2, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x04, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 1, 0, 0x82, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +/* --------------------- Audio 1.0 AS ISO Feedback Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x82, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(4),D1(4), 1, 4, 0x00, +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { +/* --------------------------------------- Device Descriptor */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x01, 0x00, +/* 12 bcdDevice */ D0(0x100),D1(0x100), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* ----------------------------- Device Qualifier Descriptor */ +/* 0 bLength, bDescriptorType */ 10, 0x06, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 bNumConfigurations */ 1, +/* 9 bReserved */ 0, + +/* -------------------------------- Configuration Descriptor *//* 9+81+52*2=194 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(194+18),D1(194+18), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+72=81) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x00, +/* 8 iInterface */ 0, +/* ---------------- Audio 1.0 AC Interface Header Descriptor *//* (10+12*2+10*2+9*2=72) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x01, +/* 3 bcdADC */ 0x00, 0x01, +/* 5 wTotalLength, bInCollection */ D0(72),D1(72), 2, +/* 8 baInterfaceNr(1) ... baInterfaceNr(n) */ 1, 2, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x02, +/* 8 iTerminal */ 0, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x05, +/* 8 iTerminal */ 0, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 2, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x03, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 4, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +/* --------------------- Audio 1.0 AS ISO Feedback Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x01, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(4),D1(4), 1, 4, 0x00, + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 2, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x04, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 4, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +/* --------------------- Audio 1.0 AS ISO Feedback Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x82, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(4),D1(4), 1, 4, 0x00, +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + +/* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + +/* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + +/* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; +static UX_TEST_SETUP _GetCfgDescr = UX_TEST_SETUP_GetCfgDescr; +static UX_TEST_SETUP _SetAddress = UX_TEST_SETUP_SetAddress; +static UX_TEST_SETUP _GetDeviceDescriptor = UX_TEST_SETUP_GetDevDescr; +static UX_TEST_SETUP _GetConfigDescriptor = UX_TEST_SETUP_GetCfgDescr; + +/* Interaction define */ + +/* Hooks define */ + +static VOID ux_device_class_audio_tx_hook(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *p = (UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *)params; +UX_SLAVE_TRANSFER *transfer = (UX_SLAVE_TRANSFER *)p -> parameter; +UCHAR tmp[32] = {'i','n','s','e','r','t','A',0}; + + + (void)params; + // printf("tTX\n"); + + /* Acknowledge frame sent. */ + if (test_tx_ack_count) + { + SAVE_BUFFER_LOG(transfer -> ux_slave_transfer_request_data_pointer, transfer -> ux_slave_transfer_request_requested_length); + transfer -> ux_slave_transfer_request_actual_length = transfer -> ux_slave_transfer_request_requested_length; + transfer -> ux_slave_transfer_request_completion_code = UX_SUCCESS; + ux_test_dcd_sim_slave_transfer_done(transfer, UX_SUCCESS); + } + if (test_tx_ack_count != 0xFFFFFFFF && test_tx_ack_count > 0) + test_tx_ack_count --; + + /* Insert frames when sent. */ + if (test_tx_ins_count) + { + tmp[6] = (test_tx_ins_count % 26) + 'A'; + if (test_tx_ins_way == 0) + ux_device_class_audio_frame_write(slave_audio_tx_stream, tmp, 32); + else + { + + UCHAR *frame; + ULONG frame_length; + + + ux_device_class_audio_write_frame_get(slave_audio_tx_stream, &frame, &frame_length); + _ux_utility_memory_copy(frame, tmp, 32); + ux_device_class_audio_write_frame_commit(slave_audio_tx_stream, 32); + } + } + if (test_tx_ins_count != 0xFFFFFFFF && test_tx_ins_count > 0) + test_tx_ins_count --; +} + +static VOID ux_device_class_audio_rx_hook(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *p = (UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *)params; +UX_SLAVE_TRANSFER *transfer = (UX_SLAVE_TRANSFER *)p -> parameter; + + + (void)action; + (void)params; + (void)p; + (void)transfer; + // printf("tRX\n"); + slave_audio_rx_transfer = transfer; +} + +static VOID ux_device_class_audio_feedback_hook(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *p = (UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *)params; +UX_SLAVE_TRANSFER *transfer = (UX_SLAVE_TRANSFER *)p -> parameter; +ULONG length; + + (void)action; + (void)params; + (void)p; + (void)transfer; + length = UX_MIN(4, transfer->ux_slave_transfer_request_requested_length); + if (transfer->ux_slave_transfer_request_endpoint->ux_slave_endpoint_descriptor.bEndpointAddress & 0x80) + { + device_audio_rx_feedback_count ++; + /* IN for OUT(RX/read) feedback. */ + device_audio_rx_feedback = 0; + _ux_utility_memory_copy(device_audio_rx_feedback_u8a, + transfer->ux_slave_transfer_request_data_pointer, length); + transfer -> ux_slave_transfer_request_completion_code = UX_SUCCESS; + transfer -> ux_slave_transfer_request_actual_length = length; + } + else + { + device_audio_tx_feedback_count ++; + /* OUT for IN(TX/write) feedback. */ + _ux_utility_memory_copy(transfer->ux_slave_transfer_request_data_pointer, + device_audio_tx_feedback_u8a, length); + transfer -> ux_slave_transfer_request_completion_code = UX_SUCCESS; + transfer -> ux_slave_transfer_request_actual_length = length; + } + ux_test_dcd_sim_slave_transfer_done(transfer, UX_SUCCESS); + _ux_utility_thread_sleep(1); +} + +static VOID slave_audio_rx_simulate_one_frame(UCHAR *frame, ULONG frame_length) +{ + UX_TEST_ASSERT(slave_audio_rx_transfer); + if (frame_length) + { + _ux_utility_memory_copy(slave_audio_rx_transfer->ux_slave_transfer_request_data_pointer, frame, frame_length); + slave_audio_rx_transfer->ux_slave_transfer_request_actual_length = frame_length; + slave_audio_rx_transfer->ux_slave_transfer_request_completion_code = UX_SUCCESS; + } + ux_test_dcd_sim_slave_transfer_done(slave_audio_rx_transfer, UX_SUCCESS); + _ux_utility_delay_ms(100); +} + +static UX_TEST_ACTION ux_device_class_audio_transfer_hook[] = +{ + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .action_func = ux_device_class_audio_tx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x81, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .action_func = ux_device_class_audio_rx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x02, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .action_func = ux_device_class_audio_feedback_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x82, + .req_status = UX_SUCCESS, + .status = UX_SUCCESS, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .action_func = ux_device_class_audio_feedback_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x01, + .req_status = UX_SUCCESS, + .status = UX_SUCCESS, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, +{ 0 }, +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* 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 ++; + // printf("Error #%d, system_level: %d, system_context: %d, error_code: 0x%x\n", __LINE__, system_level, system_context, error_code); + + if (!error_callback_ignore) + { + { + /* Failed test. */ + 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 VOID slave_audio_tx_activate(VOID *audio_instance) +{ + slave_audio_tx = (UX_DEVICE_CLASS_AUDIO *)audio_instance; + ux_device_class_audio_stream_get(slave_audio_tx, 0, &slave_audio_tx_stream); + // printf("sAUD_tx:%p,%p\n", audio_instance, slave_audio_tx_stream); +} +static VOID slave_audio_rx_activate(VOID *audio_instance) +{ + slave_audio_rx = (UX_DEVICE_CLASS_AUDIO *)audio_instance; + ux_device_class_audio_stream_get(slave_audio_rx, 0, &slave_audio_rx_stream); + // printf("sAUD_rx:%p,%p\n", audio_instance, slave_audio_rx_stream); +} +static VOID slave_audio_deactivate(VOID *audio_instance) +{ + if ((VOID *)slave_audio_rx == audio_instance) + { + slave_audio_rx = UX_NULL; + slave_audio_rx_stream = UX_NULL; + } + if ((VOID *)slave_audio_tx == audio_instance) + slave_audio_tx = UX_NULL; + slave_audio_tx_stream = UX_NULL; +} +static VOID slave_audio_tx_stream_change(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG alt) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_tx_stream_change, audio, (ALIGN_TYPE)alt, 0); +} +static VOID slave_audio_rx_stream_change(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG alt) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_rx_stream_change, audio, (ALIGN_TYPE)alt, 0); + + slave_audio_rx_transfer = UX_NULL; +} +static UINT slave_audio_control_process(UX_DEVICE_CLASS_AUDIO *audio, UX_SLAVE_TRANSFER *transfer) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_control_process, audio, transfer, 0); + return(UX_ERROR); +} +static VOID slave_audio_tx_done(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG length) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_tx_done, audio, (ALIGN_TYPE)length, 0); +} +static VOID slave_audio_rx_done(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG length) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_rx_done, audio, (ALIGN_TYPE)length, 0); +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_DUMMY *dummy = (UX_HOST_CLASS_DUMMY *) inst; + + + switch(event) + { + + case UX_DEVICE_INSERTION: + + // printf("hINS:%p,%p:%ld\n", cls, inst, dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber); + switch(dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber) + { + case 0: dummy_control = dummy; break; + case 1: dummy_rx = dummy; break; + case 2: dummy_tx = dummy; break; + } + break; + + case UX_DEVICE_REMOVAL: + + // printf("hRMV:%p,%p:%ld\n", cls, inst, dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber); + switch(dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber) + { + case 0: dummy_control = UX_NULL; break; + case 1: dummy_rx = UX_NULL; break; + case 2: dummy_tx = UX_NULL; break; + } + break; + + default: + break; + } + return 0; +} + + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_audio10_device_feedback_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ +#if !UX_TEST_MULTI_IFC_ON || !UX_TEST_MULTI_ALT_ON || !UX_TEST_MULTI_CLS_ON || !UX_TEST_MULTI_EP_OVER(4) || !defined(UX_DEVICE_BIDIRECTIONAL_ENDPOINT_SUPPORT) + printf("Running Audio 1.0 Device Feedback Functionality Test................SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + + printf("Running Audio 1.0 Device Feedback Functionality Test................ "); + + stepinfo("\n"); + + /* 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(); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* 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_host_change_function); + UX_TEST_CHECK_SUCCESS(status); + + /* Register Audio class. */ + status = ux_host_stack_class_register(_ux_host_class_dummy_name, _ux_host_class_dummy_entry); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Set the parameters for callback when insertion/extraction of a Audio 1.0 device, no IAD. */ + ux_utility_memory_set(&slave_audio_tx_stream_parameter, 0, sizeof(slave_audio_tx_stream_parameter)); + ux_utility_memory_set(&slave_audio_rx_stream_parameter, 0, sizeof(slave_audio_rx_stream_parameter)); +#if !defined(UX_DEVICE_STANDALONE) + slave_audio_tx_stream_parameter.ux_device_class_audio_stream_parameter_thread_entry = ux_device_class_audio_write_thread_entry; +#else + slave_audio_tx_stream_parameter.ux_device_class_audio_stream_parameter_task_function = ux_device_class_audio_write_task_function; +#endif +#if defined(UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT) +#if !defined(UX_DEVICE_STANDALONE) + slave_audio_tx_stream_parameter.ux_device_class_audio_stream_parameter_feedback_thread_entry = ux_device_class_audio_feedback_thread_entry; +#else + slave_audio_tx_stream_parameter.ux_device_class_audio_stream_parameter_feedback_task_function = _ux_device_class_audio_feedback_task_function; +#endif +#endif + slave_audio_tx_stream_parameter.ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_change = slave_audio_tx_stream_change; + slave_audio_tx_stream_parameter.ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_frame_done = slave_audio_tx_done; + slave_audio_tx_stream_parameter.ux_device_class_audio_stream_parameter_max_frame_buffer_size = 256; + slave_audio_tx_stream_parameter.ux_device_class_audio_stream_parameter_max_frame_buffer_nb = 8; + slave_audio_tx_parameter.ux_device_class_audio_parameter_streams = &slave_audio_tx_stream_parameter; + slave_audio_tx_parameter.ux_device_class_audio_parameter_streams_nb = 1; + slave_audio_tx_parameter.ux_device_class_audio_parameter_callbacks.ux_slave_class_audio_instance_activate = slave_audio_tx_activate; + slave_audio_tx_parameter.ux_device_class_audio_parameter_callbacks.ux_slave_class_audio_instance_deactivate = slave_audio_deactivate; + slave_audio_tx_parameter.ux_device_class_audio_parameter_callbacks.ux_device_class_audio_control_process = slave_audio_control_process; + slave_audio_tx_parameter.ux_device_class_audio_parameter_callbacks.ux_device_class_audio_arg = UX_NULL; + +#if !defined(UX_DEVICE_STANDALONE) + slave_audio_rx_stream_parameter.ux_device_class_audio_stream_parameter_thread_entry = ux_device_class_audio_read_thread_entry; +#else + slave_audio_rx_stream_parameter.ux_device_class_audio_stream_parameter_task_function = ux_device_class_audio_read_task_function; +#endif +#if defined(UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT) +#if !defined(UX_DEVICE_STANDALONE) + slave_audio_rx_stream_parameter.ux_device_class_audio_stream_parameter_feedback_thread_entry = ux_device_class_audio_feedback_thread_entry; +#else + slave_audio_rx_stream_parameter.ux_device_class_audio_stream_parameter_feedback_task_function = _ux_device_class_audio_feedback_task_function; +#endif +#endif + slave_audio_rx_stream_parameter.ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_change = slave_audio_rx_stream_change; + slave_audio_rx_stream_parameter.ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_frame_done = slave_audio_rx_done; + slave_audio_rx_stream_parameter.ux_device_class_audio_stream_parameter_max_frame_buffer_size = 256; + slave_audio_rx_stream_parameter.ux_device_class_audio_stream_parameter_max_frame_buffer_nb = 8; + slave_audio_rx_parameter.ux_device_class_audio_parameter_streams = &slave_audio_rx_stream_parameter; + slave_audio_rx_parameter.ux_device_class_audio_parameter_streams_nb = 1; + slave_audio_rx_parameter.ux_device_class_audio_parameter_callbacks.ux_slave_class_audio_instance_activate = slave_audio_rx_activate; + slave_audio_rx_parameter.ux_device_class_audio_parameter_callbacks.ux_slave_class_audio_instance_deactivate = slave_audio_deactivate; + slave_audio_rx_parameter.ux_device_class_audio_parameter_callbacks.ux_device_class_audio_control_process = slave_audio_control_process; + slave_audio_rx_parameter.ux_device_class_audio_parameter_callbacks.ux_device_class_audio_arg = UX_NULL; + +#if defined(UX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT) + slave_audio_tx_parameter.ux_device_class_audio_parameter_status_queue_size = 2; + slave_audio_tx_parameter.ux_device_class_audio_parameter_status_size = 8; /* Actually 6 bytes in length. */ + slave_audio_rx_parameter.ux_device_class_audio_parameter_status_queue_size = 2; + slave_audio_rx_parameter.ux_device_class_audio_parameter_status_size = 8; /* Actually 6 bytes in length. */ +#endif + + /* Initialize the device Audio class. This class owns interfaces starting with 1, 2. */ + status = ux_device_stack_class_register(_ux_system_slave_class_audio_name, ux_device_class_audio_entry, + 1, 1, &slave_audio_tx_parameter); + status |= ux_device_stack_class_register(_ux_system_slave_class_audio_name, ux_device_class_audio_entry, + 1, 2, &slave_audio_rx_parameter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + UX_TEST_CHECK_SUCCESS(status); +#endif + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx demo host simulation", tx_test_thread_host_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx demo slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_CHECK_SUCCESS(status); +} + +static UINT test_wait_until_expected(VOID **ptr, ULONG loop, VOID *expected) +{ + while(loop) + { + _ux_utility_delay_ms(10); + if (*ptr == expected) + return UX_SUCCESS; + } + return UX_ERROR; +} +static UINT test_wait_until_not_expected(VOID **ptr, ULONG loop, VOID *expected) +{ + while(loop) + { + _ux_utility_delay_ms(10); + if (*ptr != expected) + return UX_SUCCESS; + } + return UX_ERROR; +} +#define test_wait_until_not_null(ptr, loop) test_wait_until_not_expected(ptr, loop, UX_NULL) +#define test_wait_until_null(ptr, loop) test_wait_until_expected(ptr, loop, UX_NULL) + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +UX_INTERFACE *interface_inst[3][2]; +UCHAR test_cmp[32]; +ULONG temp; + + + /* Test connect. */ + status = test_wait_until_not_null((void**)&dummy_control, 100); + status |= test_wait_until_not_null((void**)&dummy_tx, 100); + status |= test_wait_until_not_null((void**)&dummy_rx, 100); + status |= test_wait_until_not_null((void**)&slave_audio_tx, 100); + status |= test_wait_until_not_null((void**)&slave_audio_rx, 100); + UX_TEST_CHECK_SUCCESS(status); + + /* Get testing instances. */ + + status = ux_host_stack_device_get(0, &device); + UX_TEST_CHECK_SUCCESS(status); + + status = ux_host_stack_device_configuration_get(device, 0, &configuration); + UX_TEST_CHECK_SUCCESS(status); + + interface = configuration -> ux_configuration_first_interface; + while(interface) + { + // printf("Interface: %ld.%ld\n", interface -> ux_interface_descriptor.bInterfaceNumber, interface -> ux_interface_descriptor.bAlternateSetting); + interface_inst[interface -> ux_interface_descriptor.bInterfaceNumber][interface -> ux_interface_descriptor.bAlternateSetting] = interface; + interface = interface -> ux_interface_next_interface; + } + + ux_test_link_hooks_from_array(ux_device_class_audio_transfer_hook); + + /* Test interface change. */ + /* Reset log. */ + RESET_CALLBACK_INVOKE_LOG(); + status = ux_host_stack_interface_setting_select(interface_inst[1][1]); + status |= ux_host_stack_interface_setting_select(interface_inst[1][0]); + status |= ux_host_stack_interface_setting_select(interface_inst[1][1]); + + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(callback_invoke_count == 3); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_tx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_tx_stream); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (VOID*)1); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_tx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_tx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].param2 == 0); + + RESET_CALLBACK_INVOKE_LOG(); + status = ux_host_stack_interface_setting_select(interface_inst[2][1]); + status |= ux_host_stack_interface_setting_select(interface_inst[2][0]); + status |= ux_host_stack_interface_setting_select(interface_inst[2][1]); + + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(callback_invoke_count == 3); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_rx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (VOID*)1); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_rx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].param2 == 0); + + +#if defined(UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT) + /* Test feedbacks. */ + + /* Read/write feedback test, pass any data of 4 bytes. */ + _ux_system_slave->ux_system_slave_speed = UX_HIGH_SPEED_DEVICE; + slave_audio_rx_stream->ux_device_class_audio_stream_feedback->ux_slave_endpoint_transfer_request.ux_slave_transfer_request_requested_length = 4; + slave_audio_tx_stream->ux_device_class_audio_stream_feedback->ux_slave_endpoint_transfer_request.ux_slave_transfer_request_requested_length = 4; + temp = 0x1234567; + ux_device_class_audio_feedback_set(slave_audio_rx_stream, (UCHAR *)&temp); + temp = device_audio_rx_feedback_count; + while(device_audio_rx_feedback_count == temp) + tx_thread_sleep(1); + UX_TEST_ASSERT(device_audio_rx_feedback == 0x1234567); + + device_audio_tx_feedback = 0xabcd1234; + temp = device_audio_tx_feedback_count; + while(device_audio_tx_feedback_count != (temp + 2)) + tx_thread_sleep(1); + status = ux_device_class_audio_feedback_get(slave_audio_tx_stream, (UCHAR *)&temp); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(temp == 0xabcd1234); + + /* Read/write feedback test full speed, pass any data of 3 bytes. */ + _ux_system_slave->ux_system_slave_speed = UX_FULL_SPEED_DEVICE; + slave_audio_rx_stream->ux_device_class_audio_stream_feedback->ux_slave_endpoint_transfer_request.ux_slave_transfer_request_requested_length = 3; + slave_audio_tx_stream->ux_device_class_audio_stream_feedback->ux_slave_endpoint_transfer_request.ux_slave_transfer_request_requested_length = 3; + temp = 0x7654321; + ux_device_class_audio_feedback_set(slave_audio_rx_stream, (UCHAR *)&temp); + temp = device_audio_rx_feedback_count; + while(device_audio_rx_feedback_count == temp) + tx_thread_sleep(1); + UX_TEST_ASSERT(device_audio_rx_feedback == 0x654321); + + device_audio_tx_feedback = 0x4321dcba; + temp = device_audio_tx_feedback_count; + while(device_audio_tx_feedback_count != (temp + 2)) + tx_thread_sleep(1); + status = ux_device_class_audio_feedback_get(slave_audio_tx_stream, (UCHAR *)&temp); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(temp == 0x21dcba); +#endif + + + /* Test data streaming. */ + + /* Wrong interface! */ + status = ux_device_class_audio_transmission_start(slave_audio_rx_stream); + status |= ux_device_class_audio_reception_start(slave_audio_tx_stream); + UX_TEST_CHECK_NOT_SUCCESS(status); + + /* ------------------ Write test. */ + + status = ux_device_class_audio_frame_write(slave_audio_tx_stream, "test0", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test1", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test2", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test3", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test4", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test5", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test6", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test7", 16); + UX_TEST_CHECK_SUCCESS(status); + + error_callback_counter = 0; + status = ux_device_class_audio_frame_write(slave_audio_tx_stream, "test8", 16); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + /* + Keep sending until under-run. + No buffer appended while running. + */ + + buffer_log_count = 0; + test_tx_ack_count = 10; + status = ux_device_class_audio_transmission_start(slave_audio_tx_stream); + UX_TEST_CHECK_SUCCESS(status); + + /* Delay to let thread runs. */ + _ux_utility_delay_ms(500); + + /* Prepare data for checking. */ + _ux_utility_memory_set(test_cmp, 0, 16); + _ux_utility_memory_copy(test_cmp, "test", 4); + + /* 8 frame should be available. */ + for (test_n = 0; test_n < 8; test_n ++) + { + // printf("%ld: %ld: %s\n", test_n, buffer_log[test_n].length, buffer_log[test_n].data); + test_cmp[4] = (UCHAR)(test_n + '0'); + + UX_TEST_ASSERT(buffer_log[test_n].length == 16); + + status = _ux_utility_memory_compare(buffer_log[test_n].data, test_cmp, 6); + UX_TEST_CHECK_SUCCESS(status); + } + /* Then under-run, 0 length packets. */ + for(;test_n < buffer_log_count; test_n ++) + { + // printf("%ld: %ld\n", test_n, buffer_log[test_n].length); + UX_TEST_ASSERT(buffer_log[test_n].length == 0); + } + + /* + Keep sending until under-run. + Specific number of buffer appended while running. + */ + + for (test_tx_ins_way = 0; test_tx_ins_way < 2; test_tx_ins_way ++) + { + + /* Switch interface to clean up status. */ + status = ux_host_stack_interface_setting_select(interface_inst[1][0]); + status |= ux_host_stack_interface_setting_select(interface_inst[1][1]); + + status = ux_device_class_audio_frame_write(slave_audio_tx_stream, "test0", 20); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test1", 20); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test2", 20); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test3", 20); + UX_TEST_CHECK_SUCCESS(status); + + test_tx_ins_count = 10; + test_tx_ack_count = 20; + buffer_log_count = 0; + status = ux_device_class_audio_transmission_start(slave_audio_tx_stream); + UX_TEST_CHECK_SUCCESS(status); + + /* Delay to let thread runs. */ + _ux_utility_delay_ms(500); + + /* Prepare data for checking. */ + _ux_utility_memory_set(test_cmp, 0, 32); + + /* 4 frame should be available. */ + _ux_utility_memory_copy(test_cmp, "test", 4); + for (test_n = 0; test_n < 4; test_n ++) + { + // printf("%ld: %ld: %s\n", test_n, buffer_log[test_n].length, buffer_log[test_n].data); + test_cmp[4] = (UCHAR)(test_n + '0'); + + UX_TEST_ASSERT(buffer_log[test_n].length == 20); + + status = _ux_utility_memory_compare(buffer_log[test_n].data, test_cmp, 6); + UX_TEST_CHECK_SUCCESS(status); + } + /* 10 more frame should be available. */ + _ux_utility_memory_copy(test_cmp, "insert", 6); + for (; test_n < 14; test_n ++) + { + // printf("%ld: %ld: %s\n", test_n, buffer_log[test_n].length, buffer_log[test_n].data); + test_cmp[6] = (UCHAR)(((10 - (test_n - 4)) % 26) + 'A'); + + UX_TEST_ASSERT(buffer_log[test_n].length == 32); + + status = _ux_utility_memory_compare(buffer_log[test_n].data, test_cmp, 8); + UX_TEST_CHECK_SUCCESS(status); + } + /* Then under-run, 0 length packets. */ + for(;test_n < buffer_log_count; test_n ++) + { + // printf("%ld: %ld\n", test_n, buffer_log[test_n].length); + UX_TEST_ASSERT(buffer_log[test_n].length == 0); + } + } + + UX_TEST_ASSERT(slave_audio_tx_stream->ux_device_class_audio_stream_transfer_pos == slave_audio_tx_stream->ux_device_class_audio_stream_access_pos); + + /* ------------------ Read - 8 test. */ + + UX_TEST_ASSERT(slave_audio_rx_transfer == UX_NULL); + + temp = 0; + status = ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + status = ux_device_class_audio_reception_start(slave_audio_rx_stream); + UX_TEST_CHECK_SUCCESS(status); + _ux_utility_thread_sleep(1); + + UX_TEST_ASSERT(slave_audio_rx_transfer != UX_NULL); + + status = ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + RESET_CALLBACK_INVOKE_LOG(); + + slave_audio_rx_simulate_one_frame("012345", 6); + for (test_n = 0; test_n < 6; test_n ++) + { + status = ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(temp == (test_n + '0')); + } + + slave_audio_rx_simulate_one_frame("012345", 6); + slave_audio_rx_simulate_one_frame("67", 2); + slave_audio_rx_simulate_one_frame("89", 2); + + for (test_n = 0; test_n < 10; test_n ++) + { + status = ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(temp == (test_n + '0')); + } + + UX_TEST_ASSERT(callback_invoke_count == 4); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[2].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[2].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[3].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[3].param1 == slave_audio_rx_stream); + + RESET_CALLBACK_INVOKE_LOG(); + error_callback_counter = 0; + for (test_n = 0; test_n < 10; test_n ++) + { + test_cmp[0] = (UCHAR)(test_n + '0'); + slave_audio_rx_simulate_one_frame(test_cmp, 1); + } + + UX_TEST_ASSERT(callback_invoke_count == 10); + UX_TEST_ASSERT(error_callback_counter == 3); + for (test_n = 0; test_n < 7; test_n ++) + { + status = ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp); + UX_TEST_CHECK_SUCCESS(status); + // printf("(%lx)%c\n", temp, (char)temp); + UX_TEST_ASSERT(temp == (test_n + '0')); + } + UX_TEST_CHECK_SUCCESS(ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp)); + UX_TEST_ASSERT(temp == '9'); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp)); + + /* ------------------ Read - 16 test. */ + + status = ux_device_class_audio_sample_read16(slave_audio_rx_stream, (USHORT *)&temp); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + RESET_CALLBACK_INVOKE_LOG(); + slave_audio_rx_simulate_one_frame("012345", 6); + slave_audio_rx_simulate_one_frame("67", 2); + UX_TEST_ASSERT(callback_invoke_count == 2); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (VOID*)6); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].param2 == (VOID*)2); + for (test_n = 0; test_n < 4; test_n ++) + { + status = ux_device_class_audio_sample_read16(slave_audio_rx_stream, (USHORT *)&temp); + UX_TEST_CHECK_SUCCESS(status); + // printf("%lx\n", temp); + test_cmp[0] = (UCHAR)(test_n * 2 + '0'); + test_cmp[1] = (UCHAR)(test_n * 2 + '1'); + UX_TEST_CHECK_SUCCESS(_ux_utility_memory_compare(test_cmp, &temp, 2)); + } + + /* ------------------ Read - 24 test. */ + + status = ux_device_class_audio_sample_read24(slave_audio_rx_stream, &temp); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + RESET_CALLBACK_INVOKE_LOG(); + slave_audio_rx_simulate_one_frame("012345", 6); + slave_audio_rx_simulate_one_frame("678", 3); + UX_TEST_ASSERT(callback_invoke_count == 2); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (VOID*)6); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].param2 == (VOID*)3); + for (test_n = 0; test_n < 3; test_n ++) + { + status = ux_device_class_audio_sample_read24(slave_audio_rx_stream, &temp); + UX_TEST_CHECK_SUCCESS(status); + // printf("%lx\n", temp); + test_cmp[0] = (UCHAR)(test_n * 3 + '0'); + test_cmp[1] = (UCHAR)(test_n * 3 + '1'); + test_cmp[2] = (UCHAR)(test_n * 3 + '2'); + UX_TEST_CHECK_SUCCESS(_ux_utility_memory_compare(test_cmp, &temp, 3)); + } + + /* ------------------ Read - 32 test. */ + + status = ux_device_class_audio_sample_read32(slave_audio_rx_stream, &temp); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + RESET_CALLBACK_INVOKE_LOG(); + slave_audio_rx_simulate_one_frame("01234567", 8); + slave_audio_rx_simulate_one_frame("8901", 4); + UX_TEST_ASSERT(callback_invoke_count == 2); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (VOID*)8); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].param2 == (VOID*)4); + for (test_n = 0; test_n < 3; test_n ++) + { + status = ux_device_class_audio_sample_read32(slave_audio_rx_stream, &temp); + UX_TEST_CHECK_SUCCESS(status); + // printf("%lx\n", temp); + test_cmp[0] = ((test_n * 4 + 0) % 10) + '0'; + test_cmp[1] = ((test_n * 4 + 1) % 10) + '0'; + test_cmp[2] = ((test_n * 4 + 2) % 10) + '0'; + test_cmp[3] = ((test_n * 4 + 3) % 10) + '0'; + UX_TEST_CHECK_SUCCESS(_ux_utility_memory_compare(test_cmp, &temp, 4)); + } + + UX_TEST_ASSERT(slave_audio_tx_stream->ux_device_class_audio_stream_transfer_pos == slave_audio_tx_stream->ux_device_class_audio_stream_access_pos); + + + /* Wait pending threads. */ + _ux_utility_thread_sleep(1); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + ux_device_stack_class_unregister(_ux_system_slave_class_audio_name, ux_device_class_audio_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + while(1) + { + +#if defined(UX_DEVICE_STANDALONE) + + /* Standalone background task. */ + ux_system_tasks_run(); +#else + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); +#endif + } +} diff --git a/test/regression/usbx_audio10_iad_device_basic_test.c b/test/regression/usbx_audio10_iad_device_basic_test.c new file mode 100644 index 00000000..e92fcf3e --- /dev/null +++ b/test/regression/usbx_audio10_iad_device_basic_test.c @@ -0,0 +1,1222 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" + +#include "fx_api.h" + +#include "ux_device_class_audio.h" +#include "ux_device_stack.h" + +#include "ux_host_class_audio.h" +#include "ux_host_class_dummy.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_DEMO_REQUEST_MAX_LENGTH \ + ((UX_HCD_SIM_HOST_MAX_PAYLOAD) > (UX_SLAVE_REQUEST_DATA_MAX_LENGTH) ? \ + (UX_HCD_SIM_HOST_MAX_PAYLOAD) : (UX_SLAVE_REQUEST_DATA_MAX_LENGTH)) + +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_DEMO_REQUEST_MAX_LENGTH + 1) +#define UX_DEMO_MEMORY_SIZE (128*1024) + +#define UX_TEST_LOG_SIZE (64) + + +/* Define local/extern function prototypes. */ +static void test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static void tx_test_thread_host_simulation_entry(ULONG); +static void tx_test_thread_slave_simulation_entry(ULONG); + + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +static UX_HOST_CLASS_DUMMY *dummy_control; +static UX_HOST_CLASS_DUMMY *dummy_tx; +static UX_HOST_CLASS_DUMMY *dummy_rx; + +static UX_DEVICE_CLASS_AUDIO *slave_audio; +static UX_DEVICE_CLASS_AUDIO_PARAMETER slave_audio_parameter; +static UX_DEVICE_CLASS_AUDIO_STREAM_PARAMETER slave_audio_stream_parameter[2]; + +static UX_DEVICE_CLASS_AUDIO_STREAM *slave_audio_tx_stream; + +static UX_DEVICE_CLASS_AUDIO_STREAM *slave_audio_rx_stream; +static UX_SLAVE_TRANSFER *slave_audio_rx_transfer; + +static UX_HOST_CLASS_AUDIO *audio; + +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_audio_sem_usage; +static ULONG rsc_audio_sem_get_count; +static ULONG rsc_audio_mutex_usage; +static ULONG rsc_audio_mem_usage; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +static struct BUFFER_LOG_STRUCT { + ULONG length; + UCHAR data[256]; +} buffer_log[UX_TEST_LOG_SIZE]; +static ULONG buffer_log_count = 0; +#define SAVE_BUFFER_LOG(buf,siz) do { \ + if (buffer_log_count < UX_TEST_LOG_SIZE) { \ + ULONG __local_size__ = ((siz) > 256) ? 256 : (siz); \ + buffer_log[buffer_log_count].length = (siz); \ + _ux_utility_memory_copy(buffer_log[buffer_log_count].data, (buf), __local_size__); \ + } \ + buffer_log_count ++; \ +} while(0) + +static ULONG test_tx_ack_count = 0xFFFFFFFF; +static ULONG test_tx_ins_count = 0; +static ULONG test_tx_ins_way = 0; + +static struct CALLBACK_INVOKE_LOG_STRUCT { + VOID *func; + VOID *param1; + VOID *param2; + VOID *param3; +} callback_invoke_log[UX_TEST_LOG_SIZE]; +static ULONG callback_invoke_count = 0; + +#define SAVE_CALLBACK_INVOKE_LOG(f,p1,p2,p3) do { \ + if (callback_invoke_count < UX_TEST_LOG_SIZE) { \ + callback_invoke_log[callback_invoke_count].func = (VOID *)(f); \ + callback_invoke_log[callback_invoke_count].param1 = (VOID *)(p1); \ + callback_invoke_log[callback_invoke_count].param2 = (VOID *)(p2); \ + callback_invoke_log[callback_invoke_count].param3 = (VOID *)(p3); \ + callback_invoke_count++; \ + } \ +} while(0) +#define RESET_CALLBACK_INVOKE_LOG() do { \ + callback_invoke_count = 0; \ +} while(0) + +/* Define device framework. */ + +#define D3(d) ((UCHAR)((d) >> 24)) +#define D2(d) ((UCHAR)((d) >> 16)) +#define D1(d) ((UCHAR)((d) >> 8)) +#define D0(d) ((UCHAR)((d) >> 0)) + +static unsigned char device_framework_full_speed[] = { + +/* --------------------------------------- Device Descriptor */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 0x08, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x01, 0x00, +/* 12 bcdDevice */ D0(0x100),D1(0x100), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* -------------------------------- Configuration Descriptor *//* 9+8+81+52*2=202 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(202),D1(202), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------ Interface Association Descriptor */ +/* 0 bLength, bDescriptorType */ 8, 0x0B, +/* 2 bFirstInterface, bInterfaceCount */ 0, 3, +/* 4 bFunctionClass, bFunctionSubClass, bFunctionProtocol */ 0x01, 0x01, 0x00, +/* 7 iFunction */ 0, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+72=81) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x00, +/* 8 iInterface */ 0, +/* ---------------- Audio 1.0 AC Interface Header Descriptor *//* (10+12*2+10*2+9*2=72) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x01, +/* 3 bcdADC */ 0x00, 0x01, +/* 5 wTotalLength, bInCollection */ D0(72),D1(72), 2, +/* 8 baInterfaceNr(1) ... baInterfaceNr(n) */ 1, 2, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x02, +/* 8 iTerminal */ 0, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x05, +/* 8 iTerminal */ 0, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x03, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 1, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x04, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 1, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { +/* --------------------------------------- Device Descriptor */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x01, 0x00, +/* 12 bcdDevice */ D0(0x100),D1(0x100), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* ----------------------------- Device Qualifier Descriptor */ +/* 0 bLength, bDescriptorType */ 10, 0x06, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 bNumConfigurations */ 1, +/* 9 bReserved */ 0, + +/* -------------------------------- Configuration Descriptor *//* 9+8+81+52*2=202 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(202),D1(202), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------ Interface Association Descriptor */ +/* 0 bLength, bDescriptorType */ 8, 0x0B, +/* 2 bFirstInterface, bInterfaceCount */ 0, 3, +/* 4 bFunctionClass, bFunctionSubClass, bFunctionProtocol */ 0x01, 0x01, 0x00, +/* 7 iFunction */ 0, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+72=81) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x00, +/* 8 iInterface */ 0, +/* ---------------- Audio 1.0 AC Interface Header Descriptor *//* (10+12*2+10*2+9*2=72) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x01, +/* 3 bcdADC */ 0x00, 0x01, +/* 5 wTotalLength, bInCollection */ D0(72),D1(72), 2, +/* 8 baInterfaceNr(1) ... baInterfaceNr(n) */ 1, 2, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x02, +/* 8 iTerminal */ 0, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x05, +/* 8 iTerminal */ 0, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x03, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 4, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x04, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 4, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + +/* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + +/* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + +/* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; +static UX_TEST_SETUP _GetCfgDescr = UX_TEST_SETUP_GetCfgDescr; +static UX_TEST_SETUP _SetAddress = UX_TEST_SETUP_SetAddress; +static UX_TEST_SETUP _GetDeviceDescriptor = UX_TEST_SETUP_GetDevDescr; +static UX_TEST_SETUP _GetConfigDescriptor = UX_TEST_SETUP_GetCfgDescr; + +/* Interaction define */ + +/* Hooks define */ + +static VOID ux_device_class_audio_tx_hook(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *p = (UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *)params; +UX_SLAVE_TRANSFER *transfer = (UX_SLAVE_TRANSFER *)p -> parameter; +UCHAR tmp[32] = {'i','n','s','e','r','t','A',0}; + + + (void)params; + // printf("tTX\n"); + + /* Acknowledge frame sent. */ + if (test_tx_ack_count) + { + SAVE_BUFFER_LOG(transfer -> ux_slave_transfer_request_data_pointer, transfer -> ux_slave_transfer_request_requested_length); + transfer -> ux_slave_transfer_request_actual_length = transfer -> ux_slave_transfer_request_requested_length; + transfer -> ux_slave_transfer_request_completion_code = UX_SUCCESS; + _ux_utility_semaphore_put(&transfer -> ux_slave_transfer_request_semaphore); + } + if (test_tx_ack_count != 0xFFFFFFFF && test_tx_ack_count > 0) + test_tx_ack_count --; + + /* Insert frames when sent. */ + if (test_tx_ins_count) + { + tmp[6] = (test_tx_ins_count % 26) + 'A'; + if (test_tx_ins_way == 0) + ux_device_class_audio_frame_write(slave_audio_tx_stream, tmp, 32); + else + { + + UCHAR *frame; + ULONG frame_length; + + + ux_device_class_audio_write_frame_get(slave_audio_tx_stream, &frame, &frame_length); + _ux_utility_memory_copy(frame, tmp, 32); + ux_device_class_audio_write_frame_commit(slave_audio_tx_stream, 32); + } + } + if (test_tx_ins_count != 0xFFFFFFFF && test_tx_ins_count > 0) + test_tx_ins_count --; +} + +static VOID ux_device_class_audio_rx_hook(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *p = (UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *)params; +UX_SLAVE_TRANSFER *transfer = (UX_SLAVE_TRANSFER *)p -> parameter; + + + (void)action; + (void)params; + (void)p; + (void)transfer; + // printf("tRX\n"); + slave_audio_rx_transfer = transfer; +} +static VOID slave_audio_rx_simulate_one_frame(UCHAR *frame, ULONG frame_length) +{ + UX_TEST_ASSERT(slave_audio_rx_transfer); + if (frame_length) + { + _ux_utility_memory_copy(slave_audio_rx_transfer->ux_slave_transfer_request_data_pointer, frame, frame_length); + slave_audio_rx_transfer->ux_slave_transfer_request_actual_length = frame_length; + slave_audio_rx_transfer->ux_slave_transfer_request_completion_code = UX_SUCCESS; + } + _ux_utility_semaphore_put(&slave_audio_rx_transfer->ux_slave_transfer_request_semaphore); + _ux_utility_thread_sleep(1); +} + +static UX_TEST_ACTION ux_device_class_audio_transfer_hook[] = +{ + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .action_func = ux_device_class_audio_tx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x81, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .action_func = ux_device_class_audio_rx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x02, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, +{ 0 }, +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* 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 ++; + // printf("Error #%d, system_level: %d, system_context: %d, error_code: 0x%x\n", __LINE__, system_level, system_context, error_code); + + if (!error_callback_ignore) + { + { + /* Failed test. */ + 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 VOID slave_audio_activate(VOID *audio_instance) +{ + slave_audio = (UX_DEVICE_CLASS_AUDIO *)audio_instance; + ux_device_class_audio_stream_get(slave_audio, 0, &slave_audio_tx_stream); + ux_device_class_audio_stream_get(slave_audio, 1, &slave_audio_rx_stream); + // printf("sAUD:%p;%p,%p\n", audio_instance, slave_audio_tx_stream, slave_audio_rx_stream); +} +static VOID slave_audio_deactivate(VOID *audio_instance) +{ + if ((VOID *)slave_audio == audio_instance) + { + slave_audio = UX_NULL; + slave_audio_tx_stream = UX_NULL; + slave_audio_rx_stream = UX_NULL; + } +} +static VOID slave_audio_tx_stream_change(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG alt) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_tx_stream_change, audio, (ALIGN_TYPE)alt, 0); +} +static VOID slave_audio_rx_stream_change(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG alt) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_rx_stream_change, audio, (ALIGN_TYPE)alt, 0); + + slave_audio_rx_transfer = UX_NULL; +} +static UINT slave_audio_control_process(UX_DEVICE_CLASS_AUDIO *audio, UX_SLAVE_TRANSFER *transfer) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_control_process, audio, transfer, 0); + return(UX_ERROR); +} +static VOID slave_audio_tx_done(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG length) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_tx_done, audio, (ALIGN_TYPE)length, 0); +} +static VOID slave_audio_rx_done(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG length) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_rx_done, audio, (ALIGN_TYPE)length, 0); +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_DUMMY *dummy = (UX_HOST_CLASS_DUMMY *) inst; + + + switch(event) + { + + case UX_DEVICE_INSERTION: + + // printf("hINS:%p,%p:%ld\n", cls, inst, dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber); + switch(dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber) + { + case 0: dummy_control = dummy; break; + case 1: dummy_rx = dummy; break; + case 2: dummy_tx = dummy; break; + } + break; + + case UX_DEVICE_REMOVAL: + + // printf("hRMV:%p,%p:%ld\n", cls, inst, dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber); + switch(dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber) + { + case 0: dummy_control = UX_NULL; break; + case 1: dummy_rx = UX_NULL; break; + case 2: dummy_tx = UX_NULL; break; + } + break; + + default: + break; + } + return 0; +} + + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_audio10_iad_device_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running Audio 1.0 IAD Device Basic Functionality Test............... "); + stepinfo("\n"); + + /* 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(); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* 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_host_change_function); + UX_TEST_CHECK_SUCCESS(status); + + /* Register Audio class. */ + status = ux_host_stack_class_register(_ux_host_class_dummy_name, _ux_host_class_dummy_entry); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Set the parameters for callback when insertion/extraction of a Audio 1.0 device, no IAD. */ + ux_utility_memory_set(&slave_audio_parameter, 0, sizeof(slave_audio_parameter)); + ux_utility_memory_set(slave_audio_stream_parameter, 0, sizeof(slave_audio_stream_parameter)); + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_thread_entry = ux_device_class_audio_write_thread_entry; + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_change = slave_audio_tx_stream_change; + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_frame_done = slave_audio_tx_done; + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_max_frame_buffer_size = 256; + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_max_frame_buffer_nb = 8; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_thread_entry = ux_device_class_audio_read_thread_entry; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_change = slave_audio_rx_stream_change; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_frame_done = slave_audio_rx_done; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_max_frame_buffer_size = 256; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_max_frame_buffer_nb = 8; + slave_audio_parameter.ux_device_class_audio_parameter_streams = slave_audio_stream_parameter; + slave_audio_parameter.ux_device_class_audio_parameter_streams_nb = 2; + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_slave_class_audio_instance_activate = slave_audio_activate; + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_slave_class_audio_instance_deactivate = slave_audio_deactivate; + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_device_class_audio_control_process = slave_audio_control_process; + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_device_class_audio_arg = UX_NULL; + +#if defined(UX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT) + slave_audio_parameter.ux_device_class_audio_parameter_status_queue_size = 2; + slave_audio_parameter.ux_device_class_audio_parameter_status_size = 6; +#endif + +#if 0 + printf("Memory requirement UX_DEVICE_CLASS_:\n"); + printf(" per _AUDIO: %d bytes\n", sizeof(UX_DEVICE_CLASS_AUDIO)); + printf(" per _AUDIO_STREAM: %d bytes\n", sizeof(UX_DEVICE_CLASS_AUDIO_STREAM)); + printf(" per _AUDIO_CONTROL: %d bytes\n", sizeof(UX_DEVICE_CLASS_AUDIO_CONTROL)); + printf("Dynamic memory allocation:\n"); + temp = (slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_max_frame_buffer_size+8) * + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_max_frame_buffer_nb; + printf(" per _frame_buffer_size: (%ld + 8) * %ld = %ld\n", + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_max_frame_buffer_size, + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_max_frame_buffer_nb, + temp); + temp += sizeof(UX_DEVICE_CLASS_AUDIO_STREAM); + printf(" per _stream: _AUDIO_STREAM + _frame_buffer_size = %ld\n", temp); + temp *= 2; + temp += sizeof(UX_DEVICE_CLASS_AUDIO); + printf(" per _audio: _AUDIO + _stream * 2 + _CONTROL * 0 = %ld\n", temp); +#endif + + /* Initialize the device Audio class. This class owns interfaces starting with 1, 2. */ + status = ux_device_stack_class_register(_ux_system_slave_class_audio_name, ux_device_class_audio_entry, + 1, 0, &slave_audio_parameter); + UX_TEST_CHECK_SUCCESS(status); + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx demo host simulation", tx_test_thread_host_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx demo slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_CHECK_SUCCESS(status); +} + +static UINT test_wait_until_expected(VOID **ptr, ULONG loop, VOID *expected) +{ + while(loop) + { + _ux_utility_delay_ms(10); + if (*ptr == expected) + return UX_SUCCESS; + } + return UX_ERROR; +} +static UINT test_wait_until_not_expected(VOID **ptr, ULONG loop, VOID *expected) +{ + while(loop) + { + _ux_utility_delay_ms(10); + if (*ptr != expected) + return UX_SUCCESS; + } + return UX_ERROR; +} +#define test_wait_until_not_null(ptr, loop) test_wait_until_not_expected(ptr, loop, UX_NULL) +#define test_wait_until_null(ptr, loop) test_wait_until_expected(ptr, loop, UX_NULL) + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +// ULONG mem_free; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +UX_INTERFACE *interface_inst[3][2]; +// UX_ENDPOINT *control_endpoint; +// UX_TRANSFER *transfer_request; +UCHAR test_cmp[32]; +ULONG temp; + + + /* Test connect. */ + status = test_wait_until_not_null((void**)&dummy_control, 100); + status |= test_wait_until_not_null((void**)&dummy_tx, 100); + status |= test_wait_until_not_null((void**)&dummy_rx, 100); + status |= test_wait_until_not_null((void**)&slave_audio_tx_stream, 100); + status |= test_wait_until_not_null((void**)&slave_audio_rx_stream, 100); + UX_TEST_CHECK_SUCCESS(status); + + // /* Test disconnect. */ + // ux_test_dcd_sim_slave_disconnect(); + // ux_test_hcd_sim_host_disconnect(); + + // /* Reset testing counts. */ + // ux_test_utility_sim_mutex_create_count_reset(); + // ux_test_utility_sim_sem_create_count_reset(); + // ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + // /* Save free memory usage. */ + // mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + // ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + // ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + // tx_thread_sleep(100); + // /* Log create counts for further tests. */ + // rsc_enum_mutex_usage = rsc_mutex_on_set_cfg; + // rsc_enum_sem_usage = rsc_sem_on_set_cfg; + // rsc_enum_mem_usage = mem_free - rsc_mem_free_on_set_cfg; + // /* Log create counts when instances active for further tests. */ + // rsc_cdc_mutex_usage = ux_test_utility_sim_mutex_create_count() - rsc_enum_mutex_usage; + // rsc_cdc_sem_usage = ux_test_utility_sim_sem_create_count() - rsc_enum_sem_usage; + // rsc_cdc_mem_usage = rsc_mem_free_on_set_cfg - _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + // stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + + /* Validate configuration descriptors. */ + /* ... */ + + /* Get testing instances. */ + + status = ux_host_stack_device_get(0, &device); + UX_TEST_CHECK_SUCCESS(status); + + // control_endpoint = &device->ux_device_control_endpoint; + // transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + status = ux_host_stack_device_configuration_get(device, 0, &configuration); + UX_TEST_CHECK_SUCCESS(status); + + interface = configuration -> ux_configuration_first_interface; + while(interface) + { + // printf("Interface: %ld.%ld\n", interface -> ux_interface_descriptor.bInterfaceNumber, interface -> ux_interface_descriptor.bAlternateSetting); + interface_inst[interface -> ux_interface_descriptor.bInterfaceNumber][interface -> ux_interface_descriptor.bAlternateSetting] = interface; + interface = interface -> ux_interface_next_interface; + } + + /* Test interface change. */ + /* Reset log. */ + RESET_CALLBACK_INVOKE_LOG(); + status = ux_host_stack_interface_setting_select(interface_inst[1][1]); + status |= ux_host_stack_interface_setting_select(interface_inst[1][0]); + status |= ux_host_stack_interface_setting_select(interface_inst[1][1]); + + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(callback_invoke_count == 3); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_tx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_tx_stream); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (VOID*)1); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_tx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_tx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].param2 == 0); + + RESET_CALLBACK_INVOKE_LOG(); + status = ux_host_stack_interface_setting_select(interface_inst[2][1]); + status |= ux_host_stack_interface_setting_select(interface_inst[2][0]); + status |= ux_host_stack_interface_setting_select(interface_inst[2][1]); + + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(callback_invoke_count == 3); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_rx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (VOID*)1); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_rx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].param2 == 0); + + /* Test data streaming. */ + + /* Wrong interface! */ + status = ux_device_class_audio_transmission_start(slave_audio_rx_stream); + status |= ux_device_class_audio_reception_start(slave_audio_tx_stream); + UX_TEST_CHECK_NOT_SUCCESS(status); + + ux_test_link_hooks_from_array(ux_device_class_audio_transfer_hook); + + /* ------------------ Write test. */ + + status = ux_device_class_audio_frame_write(slave_audio_tx_stream, "test0", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test1", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test2", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test3", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test4", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test5", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test6", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test7", 16); + UX_TEST_CHECK_SUCCESS(status); + + error_callback_counter = 0; + status = ux_device_class_audio_frame_write(slave_audio_tx_stream, "test8", 16); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + /* + Keep sending until under-run. + No buffer appended while running. + */ + + buffer_log_count = 0; + test_tx_ack_count = 10; + status = ux_device_class_audio_transmission_start(slave_audio_tx_stream); + UX_TEST_CHECK_SUCCESS(status); + + /* Delay to let thread runs. */ + _ux_utility_delay_ms(100); + + /* Prepare data for checking. */ + _ux_utility_memory_set(test_cmp, 0, 16); + _ux_utility_memory_copy(test_cmp, "test", 4); + + /* 8 frame should be available. */ + for (test_n = 0; test_n < 8; test_n ++) + { + // printf("%ld: %ld: %s\n", test_n, buffer_log[test_n].length, buffer_log[test_n].data); + test_cmp[4] = (UCHAR)(test_n + '0'); + + UX_TEST_ASSERT(buffer_log[test_n].length == 16); + + status = _ux_utility_memory_compare(buffer_log[test_n].data, test_cmp, 6); + UX_TEST_CHECK_SUCCESS(status); + } + /* Then under-run, 0 length packets. */ + for(;test_n < buffer_log_count; test_n ++) + { + // printf("%ld: %ld\n", test_n, buffer_log[test_n].length); + UX_TEST_ASSERT(buffer_log[test_n].length == 0); + } + + /* + Keep sending until under-run. + Specific number of buffer appended while running. + */ + + for (test_tx_ins_way = 0; test_tx_ins_way < 2; test_tx_ins_way ++) + { + + /* Switch interface to clean up status. */ + status = ux_host_stack_interface_setting_select(interface_inst[1][0]); + status |= ux_host_stack_interface_setting_select(interface_inst[1][1]); + + status = ux_device_class_audio_frame_write(slave_audio_tx_stream, "test0", 20); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test1", 20); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test2", 20); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test3", 20); + UX_TEST_CHECK_SUCCESS(status); + + test_tx_ins_count = 10; + test_tx_ack_count = 20; + buffer_log_count = 0; + status = ux_device_class_audio_transmission_start(slave_audio_tx_stream); + UX_TEST_CHECK_SUCCESS(status); + + /* Delay to let thread runs. */ + _ux_utility_delay_ms(300); + + /* Prepare data for checking. */ + _ux_utility_memory_set(test_cmp, 0, 32); + + /* 4 frame should be available. */ + _ux_utility_memory_copy(test_cmp, "test", 4); + for (test_n = 0; test_n < 4; test_n ++) + { + // printf("%ld: %ld: %s\n", test_n, buffer_log[test_n].length, buffer_log[test_n].data); + test_cmp[4] = (UCHAR)(test_n + '0'); + + UX_TEST_ASSERT(buffer_log[test_n].length == 20); + + status = _ux_utility_memory_compare(buffer_log[test_n].data, test_cmp, 6); + UX_TEST_CHECK_SUCCESS(status); + } + /* 10 more frame should be available. */ + _ux_utility_memory_copy(test_cmp, "insert", 6); + for (; test_n < 14; test_n ++) + { + // printf("%ld: %ld: %s\n", test_n, buffer_log[test_n].length, buffer_log[test_n].data); + test_cmp[6] = (UCHAR)(((10 - (test_n - 4)) % 26) + 'A'); + + UX_TEST_ASSERT(buffer_log[test_n].length == 32); + + status = _ux_utility_memory_compare(buffer_log[test_n].data, test_cmp, 8); + UX_TEST_CHECK_SUCCESS(status); + } + /* Then under-run, 0 length packets. */ + for(;test_n < buffer_log_count; test_n ++) + { + // printf("%ld: %ld\n", test_n, buffer_log[test_n].length); + UX_TEST_ASSERT(buffer_log[test_n].length == 0); + } + } + + UX_TEST_ASSERT(slave_audio_tx_stream->ux_device_class_audio_stream_transfer_pos == slave_audio_tx_stream->ux_device_class_audio_stream_access_pos); + + /* ------------------ Read - 8 test. */ + + UX_TEST_ASSERT(slave_audio_rx_transfer == UX_NULL); + + temp = 0; + status = ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + status = ux_device_class_audio_reception_start(slave_audio_rx_stream); + UX_TEST_CHECK_SUCCESS(status); + _ux_utility_thread_sleep(1); + + UX_TEST_ASSERT(slave_audio_rx_transfer != UX_NULL); + + status = ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + RESET_CALLBACK_INVOKE_LOG(); + + slave_audio_rx_simulate_one_frame("012345", 6); + for (test_n = 0; test_n < 6; test_n ++) + { + status = ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(temp == (test_n + '0')); + } + + slave_audio_rx_simulate_one_frame("012345", 6); + slave_audio_rx_simulate_one_frame("67", 2); + slave_audio_rx_simulate_one_frame("89", 2); + + for (test_n = 0; test_n < 10; test_n ++) + { + status = ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(temp == (test_n + '0')); + } + + UX_TEST_ASSERT(callback_invoke_count == 4); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[2].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[2].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[3].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[3].param1 == slave_audio_rx_stream); + + RESET_CALLBACK_INVOKE_LOG(); + error_callback_counter = 0; + for (test_n = 0; test_n < 10; test_n ++) + { + test_cmp[0] = (UCHAR)(test_n + '0'); + slave_audio_rx_simulate_one_frame(test_cmp, 1); + } + + UX_TEST_ASSERT(callback_invoke_count == 10); + UX_TEST_ASSERT(error_callback_counter == 3); + for (test_n = 0; test_n < 7; test_n ++) + { + status = ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp); + UX_TEST_CHECK_SUCCESS(status); + // printf("(%lx)%c\n", temp, (char)temp); + UX_TEST_ASSERT(temp == (test_n + '0')); + } + UX_TEST_CHECK_SUCCESS(ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp)); + UX_TEST_ASSERT(temp == '9'); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp)); + + /* ------------------ Read - 16 test. */ + + status = ux_device_class_audio_sample_read16(slave_audio_rx_stream, (USHORT *)&temp); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + RESET_CALLBACK_INVOKE_LOG(); + slave_audio_rx_simulate_one_frame("012345", 6); + slave_audio_rx_simulate_one_frame("67", 2); + UX_TEST_ASSERT(callback_invoke_count == 2); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (VOID*)6); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].param2 == (VOID*)2); + for (test_n = 0; test_n < 4; test_n ++) + { + status = ux_device_class_audio_sample_read16(slave_audio_rx_stream, (USHORT *)&temp); + UX_TEST_CHECK_SUCCESS(status); + // printf("%lx\n", temp); + test_cmp[0] = (UCHAR)(test_n * 2 + '0'); + test_cmp[1] = (UCHAR)(test_n * 2 + '1'); + UX_TEST_CHECK_SUCCESS(_ux_utility_memory_compare(test_cmp, &temp, 2)); + } + + /* ------------------ Read - 24 test. */ + + status = ux_device_class_audio_sample_read24(slave_audio_rx_stream, &temp); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + RESET_CALLBACK_INVOKE_LOG(); + slave_audio_rx_simulate_one_frame("012345", 6); + slave_audio_rx_simulate_one_frame("678", 3); + UX_TEST_ASSERT(callback_invoke_count == 2); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (VOID*)6); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].param2 == (VOID*)3); + for (test_n = 0; test_n < 3; test_n ++) + { + status = ux_device_class_audio_sample_read24(slave_audio_rx_stream, &temp); + UX_TEST_CHECK_SUCCESS(status); + // printf("%lx\n", temp); + test_cmp[0] = (UCHAR)(test_n * 3 + '0'); + test_cmp[1] = (UCHAR)(test_n * 3 + '1'); + test_cmp[2] = (UCHAR)(test_n * 3 + '2'); + UX_TEST_CHECK_SUCCESS(_ux_utility_memory_compare(test_cmp, &temp, 3)); + } + + /* ------------------ Read - 32 test. */ + + status = ux_device_class_audio_sample_read32(slave_audio_rx_stream, &temp); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + RESET_CALLBACK_INVOKE_LOG(); + slave_audio_rx_simulate_one_frame("01234567", 8); + slave_audio_rx_simulate_one_frame("8901", 4); + UX_TEST_ASSERT(callback_invoke_count == 2); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (VOID*)8); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].param2 == (VOID*)4); + for (test_n = 0; test_n < 3; test_n ++) + { + status = ux_device_class_audio_sample_read32(slave_audio_rx_stream, &temp); + UX_TEST_CHECK_SUCCESS(status); + // printf("%lx\n", temp); + test_cmp[0] = ((test_n * 4 + 0) % 10) + '0'; + test_cmp[1] = ((test_n * 4 + 1) % 10) + '0'; + test_cmp[2] = ((test_n * 4 + 2) % 10) + '0'; + test_cmp[3] = ((test_n * 4 + 3) % 10) + '0'; + UX_TEST_CHECK_SUCCESS(_ux_utility_memory_compare(test_cmp, &temp, 4)); + } + + UX_TEST_ASSERT(slave_audio_tx_stream->ux_device_class_audio_stream_transfer_pos == slave_audio_tx_stream->ux_device_class_audio_stream_access_pos); + + + /* Wait pending threads. */ + _ux_utility_thread_sleep(1); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + ux_device_stack_class_unregister(_ux_system_slave_class_audio_name, ux_device_class_audio_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + while(1) + { + + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); + } +} diff --git a/test/regression/usbx_audio10_iad_device_control_test.c b/test/regression/usbx_audio10_iad_device_control_test.c new file mode 100644 index 00000000..d92911d6 --- /dev/null +++ b/test/regression/usbx_audio10_iad_device_control_test.c @@ -0,0 +1,1106 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" + +#include "fx_api.h" + +#include "ux_device_class_audio.h" +#include "ux_device_class_audio10.h" +#include "ux_device_stack.h" + +#include "ux_host_class_audio.h" +#include "ux_host_class_dummy.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_DEMO_REQUEST_MAX_LENGTH \ + ((UX_HCD_SIM_HOST_MAX_PAYLOAD) > (UX_SLAVE_REQUEST_DATA_MAX_LENGTH) ? \ + (UX_HCD_SIM_HOST_MAX_PAYLOAD) : (UX_SLAVE_REQUEST_DATA_MAX_LENGTH)) + +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_DEMO_REQUEST_MAX_LENGTH + 1) +#define UX_DEMO_MEMORY_SIZE (128*1024) + +#define UX_TEST_LOG_SIZE (64) + + +/* Define local/extern function prototypes. */ +static void test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static void tx_test_thread_host_simulation_entry(ULONG); +static void tx_test_thread_slave_simulation_entry(ULONG); + + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[64]; + +static UX_HOST_CLASS_DUMMY *dummy_control; +static UX_HOST_CLASS_DUMMY *dummy_tx; +static UX_HOST_CLASS_DUMMY *dummy_rx; + +static UX_DEVICE_CLASS_AUDIO *slave_audio; +static UX_DEVICE_CLASS_AUDIO_PARAMETER slave_audio_parameter; +static UX_DEVICE_CLASS_AUDIO_STREAM_PARAMETER slave_audio_stream_parameter[2]; + +static UX_DEVICE_CLASS_AUDIO_STREAM *slave_audio_tx_stream; + +static UX_DEVICE_CLASS_AUDIO_STREAM *slave_audio_rx_stream; +static UX_SLAVE_TRANSFER *slave_audio_rx_transfer; + +static UX_HOST_CLASS_AUDIO *audio; + +static UX_DEVICE_CLASS_AUDIO10_CONTROL g_slave_audio10_control[2]; + +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_audio_sem_usage; +static ULONG rsc_audio_sem_get_count; +static ULONG rsc_audio_mutex_usage; +static ULONG rsc_audio_mem_usage; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +static struct BUFFER_LOG_STRUCT { + ULONG length; + UCHAR data[256]; +} buffer_log[UX_TEST_LOG_SIZE]; +static ULONG buffer_log_count = 0; +#define SAVE_BUFFER_LOG(buf,siz) do { \ + if (buffer_log_count < UX_TEST_LOG_SIZE) { \ + ULONG __local_size__ = ((siz) > 256) ? 256 : (siz); \ + buffer_log[buffer_log_count].length = (siz); \ + _ux_utility_memory_copy(buffer_log[buffer_log_count].data, (buf), __local_size__); \ + } \ + buffer_log_count ++; \ +} while(0) + +static ULONG test_tx_ack_count = 0xFFFFFFFF; +static ULONG test_tx_ins_count = 0; +static ULONG test_tx_ins_way = 0; + +static struct CALLBACK_INVOKE_LOG_STRUCT { + VOID *func; + VOID *param1; + VOID *param2; + VOID *param3; +} callback_invoke_log[UX_TEST_LOG_SIZE]; +static ULONG callback_invoke_count = 0; + +#define SAVE_CALLBACK_INVOKE_LOG(f,p1,p2,p3) do { \ + if (callback_invoke_count < UX_TEST_LOG_SIZE) { \ + callback_invoke_log[callback_invoke_count].func = (VOID *)(f); \ + callback_invoke_log[callback_invoke_count].param1 = (VOID *)(p1); \ + callback_invoke_log[callback_invoke_count].param2 = (VOID *)(p2); \ + callback_invoke_log[callback_invoke_count].param3 = (VOID *)(p3); \ + callback_invoke_count++; \ + } \ +} while(0) +#define RESET_CALLBACK_INVOKE_LOG() do { \ + callback_invoke_count = 0; \ +} while(0) + +/* Define device framework. */ + +#define D3(d) ((UCHAR)((d) >> 24)) +#define D2(d) ((UCHAR)((d) >> 16)) +#define D1(d) ((UCHAR)((d) >> 8)) +#define D0(d) ((UCHAR)((d) >> 0)) + +static unsigned char device_framework_full_speed[] = { + +/* --------------------------------------- Device Descriptor */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 0x08, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x01, 0x00, +/* 12 bcdDevice */ D0(0x100),D1(0x100), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* -------------------------------- Configuration Descriptor *//* 9+8+81+52*2=202 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(202),D1(202), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------ Interface Association Descriptor */ +/* 0 bLength, bDescriptorType */ 8, 0x0B, +/* 2 bFirstInterface, bInterfaceCount */ 0, 3, +/* 4 bFunctionClass, bFunctionSubClass, bFunctionProtocol */ 0x01, 0x01, 0x00, +/* 7 iFunction */ 0, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+72=81) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x00, +/* 8 iInterface */ 0, +/* ---------------- Audio 1.0 AC Interface Header Descriptor *//* (10+12*2+10*2+9*2=72) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x01, +/* 3 bcdADC */ 0x00, 0x01, +/* 5 wTotalLength, bInCollection */ D0(72),D1(72), 2, +/* 8 baInterfaceNr(1) ... baInterfaceNr(n) */ 1, 2, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x02, +/* 8 iTerminal */ 0, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x05, +/* 8 iTerminal */ 0, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x03, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 1, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x04, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 1, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { +/* --------------------------------------- Device Descriptor */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x01, 0x00, +/* 12 bcdDevice */ D0(0x100),D1(0x100), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* ----------------------------- Device Qualifier Descriptor */ +/* 0 bLength, bDescriptorType */ 10, 0x06, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 bNumConfigurations */ 1, +/* 9 bReserved */ 0, + +/* -------------------------------- Configuration Descriptor *//* 9+8+81+52*2=202 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(202),D1(202), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------ Interface Association Descriptor */ +/* 0 bLength, bDescriptorType */ 8, 0x0B, +/* 2 bFirstInterface, bInterfaceCount */ 0, 3, +/* 4 bFunctionClass, bFunctionSubClass, bFunctionProtocol */ 0x01, 0x01, 0x00, +/* 7 iFunction */ 0, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+72=81) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x00, +/* 8 iInterface */ 0, +/* ---------------- Audio 1.0 AC Interface Header Descriptor *//* (10+12*2+10*2+9*2=72) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x01, +/* 3 bcdADC */ 0x00, 0x01, +/* 5 wTotalLength, bInCollection */ D0(72),D1(72), 2, +/* 8 baInterfaceNr(1) ... baInterfaceNr(n) */ 1, 2, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x02, +/* 8 iTerminal */ 0, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x05, +/* 8 iTerminal */ 0, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x03, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 4, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x04, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 4, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + +/* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + +/* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + +/* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; +static UX_TEST_SETUP _GetCfgDescr = UX_TEST_SETUP_GetCfgDescr; +static UX_TEST_SETUP _SetAddress = UX_TEST_SETUP_SetAddress; +static UX_TEST_SETUP _GetDeviceDescriptor = UX_TEST_SETUP_GetDevDescr; +static UX_TEST_SETUP _GetConfigDescriptor = UX_TEST_SETUP_GetCfgDescr; + +/* Interaction define */ + +/* Hooks define */ + +static VOID ux_device_class_audio_tx_hook(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *p = (UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *)params; +UX_SLAVE_TRANSFER *transfer = (UX_SLAVE_TRANSFER *)p -> parameter; +UCHAR tmp[32] = {'i','n','s','e','r','t','A',0}; + + + (void)params; + // printf("tTX\n"); + + /* Acknowledge frame sent. */ + if (test_tx_ack_count) + { + SAVE_BUFFER_LOG(transfer -> ux_slave_transfer_request_data_pointer, transfer -> ux_slave_transfer_request_requested_length); + transfer -> ux_slave_transfer_request_actual_length = transfer -> ux_slave_transfer_request_requested_length; + transfer -> ux_slave_transfer_request_completion_code = UX_SUCCESS; + _ux_utility_semaphore_put(&transfer -> ux_slave_transfer_request_semaphore); + } + if (test_tx_ack_count != 0xFFFFFFFF && test_tx_ack_count > 0) + test_tx_ack_count --; + + /* Insert frames when sent. */ + if (test_tx_ins_count) + { + tmp[6] = (test_tx_ins_count % 26) + 'A'; + if (test_tx_ins_way == 0) + ux_device_class_audio_frame_write(slave_audio_tx_stream, tmp, 32); + else + { + + UCHAR *frame; + ULONG frame_length; + + + ux_device_class_audio_write_frame_get(slave_audio_tx_stream, &frame, &frame_length); + _ux_utility_memory_copy(frame, tmp, 32); + ux_device_class_audio_write_frame_commit(slave_audio_tx_stream, 32); + } + } + if (test_tx_ins_count != 0xFFFFFFFF && test_tx_ins_count > 0) + test_tx_ins_count --; +} + +static VOID ux_device_class_audio_rx_hook(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *p = (UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *)params; +UX_SLAVE_TRANSFER *transfer = (UX_SLAVE_TRANSFER *)p -> parameter; + + + (void)action; + (void)params; + (void)p; + (void)transfer; + // printf("tRX\n"); + slave_audio_rx_transfer = transfer; +} +static VOID slave_audio_rx_simulate_one_frame(UCHAR *frame, ULONG frame_length) +{ + UX_TEST_ASSERT(slave_audio_rx_transfer); + if (frame_length) + { + _ux_utility_memory_copy(slave_audio_rx_transfer->ux_slave_transfer_request_data_pointer, frame, frame_length); + slave_audio_rx_transfer->ux_slave_transfer_request_actual_length = frame_length; + slave_audio_rx_transfer->ux_slave_transfer_request_completion_code = UX_SUCCESS; + } + _ux_utility_semaphore_put(&slave_audio_rx_transfer->ux_slave_transfer_request_semaphore); + _ux_utility_thread_sleep(1); +} + +static UX_TEST_ACTION ux_device_class_audio_transfer_hook[] = +{ + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .action_func = ux_device_class_audio_tx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x81, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .action_func = ux_device_class_audio_rx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x02, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, +{ 0 }, +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* 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 ++; + // printf("Error #%d, system_level: %d, system_context: %d, error_code: 0x%x\n", __LINE__, system_level, system_context, error_code); + + if (!error_callback_ignore) + { + { + /* Failed test. */ + 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 VOID slave_audio_activate(VOID *audio_instance) +{ + slave_audio = (UX_DEVICE_CLASS_AUDIO *)audio_instance; + ux_device_class_audio_stream_get(slave_audio, 0, &slave_audio_tx_stream); + ux_device_class_audio_stream_get(slave_audio, 1, &slave_audio_rx_stream); + // printf("sAUD:%p;%p,%p\n", audio_instance, slave_audio_tx_stream, slave_audio_rx_stream); +} +static VOID slave_audio_deactivate(VOID *audio_instance) +{ + if ((VOID *)slave_audio == audio_instance) + { + slave_audio = UX_NULL; + slave_audio_tx_stream = UX_NULL; + slave_audio_rx_stream = UX_NULL; + } +} +static VOID slave_audio_feature_change(struct UX_DEVICE_CLASS_AUDIO_STRUCT *audio, VOID *ext, ULONG selector) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_feature_change, audio, ext, (ALIGN_TYPE)selector); +} +static VOID slave_audio_tx_stream_change(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG alt) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_tx_stream_change, audio, (ALIGN_TYPE)alt, 0); +} +static VOID slave_audio_rx_stream_change(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG alt) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_rx_stream_change, audio, (ALIGN_TYPE)alt, 0); + + slave_audio_rx_transfer = UX_NULL; +} +static UINT slave_audio_control_process(UX_DEVICE_CLASS_AUDIO *audio, UX_SLAVE_TRANSFER *transfer) +{ + +UINT status; +UX_DEVICE_CLASS_AUDIO10_CONTROL_GROUP group = + {2, g_slave_audio10_control}; + + + SAVE_CALLBACK_INVOKE_LOG(slave_audio_control_process, audio, transfer, 0); + + status = ux_device_class_audio10_control_process(audio, transfer, &group); + if (status == UX_SUCCESS) + { + if (g_slave_audio10_control[0].ux_device_class_audio10_control_changed == UX_DEVICE_CLASS_AUDIO10_CONTROL_MUTE_CHANGED) + { + /* Mute change! */ + } + if (g_slave_audio10_control[0].ux_device_class_audio10_control_changed == UX_DEVICE_CLASS_AUDIO10_CONTROL_VOLUME_CHANGED) + { + /* Volume change! */ + } + if (g_slave_audio10_control[1].ux_device_class_audio10_control_changed == UX_DEVICE_CLASS_AUDIO10_CONTROL_MUTE_CHANGED) + { + /* Mute change! */ + } + if (g_slave_audio10_control[1].ux_device_class_audio10_control_changed == UX_DEVICE_CLASS_AUDIO10_CONTROL_VOLUME_CHANGED) + { + /* Volume change! */ + } + } + return(status); +} +static VOID slave_audio_tx_done(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG length) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_tx_done, audio, (ALIGN_TYPE)length, 0); +} +static VOID slave_audio_rx_done(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG length) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_rx_done, audio, (ALIGN_TYPE)length, 0); +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_DUMMY *dummy = (UX_HOST_CLASS_DUMMY *) inst; + + + switch(event) + { + + case UX_DEVICE_INSERTION: + + // printf("hINS:%p,%p:%ld\n", cls, inst, dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber); + switch(dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber) + { + case 0: dummy_control = dummy; break; + case 1: dummy_rx = dummy; break; + case 2: dummy_tx = dummy; break; + } + break; + + case UX_DEVICE_REMOVAL: + + // printf("hRMV:%p,%p:%ld\n", cls, inst, dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber); + switch(dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber) + { + case 0: dummy_control = UX_NULL; break; + case 1: dummy_rx = UX_NULL; break; + case 2: dummy_tx = UX_NULL; break; + } + break; + + default: + break; + } + return 0; +} + + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_audio10_iad_device_control_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running Audio 1.0 IAD Device Control Functionality Test............. "); + stepinfo("\n"); + + /* 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(); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* 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_host_change_function); + UX_TEST_CHECK_SUCCESS(status); + + /* Register Audio class. */ + status = ux_host_stack_class_register(_ux_host_class_dummy_name, _ux_host_class_dummy_entry); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Set the parameters for callback when insertion/extraction of a Audio 1.0 device, with IAD. */ + ux_utility_memory_set(&slave_audio_parameter, 0, sizeof(slave_audio_parameter)); + ux_utility_memory_set(slave_audio_stream_parameter, 0, sizeof(slave_audio_stream_parameter)); + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_thread_entry = ux_device_class_audio_write_thread_entry; + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_change = slave_audio_tx_stream_change; + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_frame_done = slave_audio_tx_done; + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_max_frame_buffer_size = 256; + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_max_frame_buffer_nb = 8; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_thread_entry = ux_device_class_audio_read_thread_entry; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_change = slave_audio_rx_stream_change; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_frame_done = slave_audio_rx_done; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_max_frame_buffer_size = 256; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_max_frame_buffer_nb = 8; + slave_audio_parameter.ux_device_class_audio_parameter_streams = slave_audio_stream_parameter; + slave_audio_parameter.ux_device_class_audio_parameter_streams_nb = 2; + + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_slave_class_audio_instance_activate = slave_audio_activate; + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_slave_class_audio_instance_deactivate = slave_audio_deactivate; + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_device_class_audio_control_process = slave_audio_control_process; + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_device_class_audio_arg = UX_NULL; + +#if defined(UX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT) + slave_audio_parameter.ux_device_class_audio_parameter_status_queue_size = 2; + slave_audio_parameter.ux_device_class_audio_parameter_status_size = 6; +#endif + + g_slave_audio10_control[0].ux_device_class_audio10_control_fu_id = 2; + g_slave_audio10_control[0].ux_device_class_audio10_control_mute[0] = 0; + g_slave_audio10_control[0].ux_device_class_audio10_control_volume[0] = 0; + + g_slave_audio10_control[1].ux_device_class_audio10_control_fu_id = 5; + g_slave_audio10_control[1].ux_device_class_audio10_control_mute[0] = 0; + g_slave_audio10_control[1].ux_device_class_audio10_control_volume[0] = 0; + + g_slave_audio10_control[0].ux_device_class_audio10_control_ep_addr = 0x02; + g_slave_audio10_control[0].ux_device_class_audio10_control_sam_freq_types = UX_NULL; + g_slave_audio10_control[0].ux_device_class_audio10_control_sam_freq = 48000; + + g_slave_audio10_control[1].ux_device_class_audio10_control_ep_addr = 0x81; + g_slave_audio10_control[1].ux_device_class_audio10_control_sam_freq_types = UX_NULL; + g_slave_audio10_control[1].ux_device_class_audio10_control_sam_freq = 48000; + + /* Initialize the device Audio class. This class owns interfaces starting with 0, 1, 2. */ + status = ux_device_stack_class_register(_ux_system_slave_class_audio_name, ux_device_class_audio_entry, + 1, 0, &slave_audio_parameter); + UX_TEST_CHECK_SUCCESS(status); + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx demo host simulation", tx_test_thread_host_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx demo slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_CHECK_SUCCESS(status); +} + +static UINT test_wait_until_expected(VOID **ptr, ULONG loop, VOID *expected) +{ + while(loop) + { + _ux_utility_delay_ms(10); + if (*ptr == expected) + return UX_SUCCESS; + } + return UX_ERROR; +} +static UINT test_wait_until_not_expected(VOID **ptr, ULONG loop, VOID *expected) +{ + while(loop) + { + _ux_utility_delay_ms(10); + if (*ptr != expected) + return UX_SUCCESS; + } + return UX_ERROR; +} +#define test_wait_until_not_null(ptr, loop) test_wait_until_not_expected(ptr, loop, UX_NULL) +#define test_wait_until_null(ptr, loop) test_wait_until_expected(ptr, loop, UX_NULL) + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +UX_INTERFACE *interface_inst[3][2]; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UCHAR test_tmp[32]; + + + /* Test connect. */ + status = test_wait_until_not_null((void**)&dummy_control, 100); + status |= test_wait_until_not_null((void**)&dummy_tx, 100); + status |= test_wait_until_not_null((void**)&dummy_rx, 100); + status |= test_wait_until_not_null((void**)&slave_audio_tx_stream, 100); + status |= test_wait_until_not_null((void**)&slave_audio_rx_stream, 100); + UX_TEST_CHECK_SUCCESS(status); + + /* Validate configuration descriptors. */ + /* ... */ + + /* Get testing instances. */ + + status = ux_host_stack_device_get(0, &device); + UX_TEST_CHECK_SUCCESS(status); + + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + status = ux_host_stack_device_configuration_get(device, 0, &configuration); + UX_TEST_CHECK_SUCCESS(status); + + interface = configuration -> ux_configuration_first_interface; + while(interface) + { + // printf("Interface: %ld.%ld\n", interface -> ux_interface_descriptor.bInterfaceNumber, interface -> ux_interface_descriptor.bAlternateSetting); + interface_inst[interface -> ux_interface_descriptor.bInterfaceNumber][interface -> ux_interface_descriptor.bAlternateSetting] = interface; + interface = interface -> ux_interface_next_interface; + } + + /**************************************************************************/ + + /* Control requests test. */ + + transfer_request -> ux_transfer_request_data_pointer = buffer; + + test_tmp[0] = 2; + test_tmp[1] = 5; + + for (test_n = 0; test_n < 2; test_n ++) + { + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_AUDIO10_SET_CUR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + + /* Issue SetFeatureMute(test_tmp[test_n], 0). */ + transfer_request -> ux_transfer_request_requested_length = 1; + transfer_request -> ux_transfer_request_index = (test_tmp[test_n] << 8) | 1; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO10_FU_MUTE_CONTROL << 8) | 0; + buffer[0] = 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio10_control[test_n].ux_device_class_audio10_control_changed == 0); + + /* Issue SetFeatureMute(test_tmp[test_n], 1). */ + buffer[0] = 1; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio10_control[test_n].ux_device_class_audio10_control_changed == UX_DEVICE_CLASS_AUDIO10_CONTROL_MUTE_CHANGED); + UX_TEST_ASSERT(g_slave_audio10_control[test_n].ux_device_class_audio10_control_mute[0] == 1); + + /* Issue SetFeatureMute(test_tmp[test_n], 0). */ + buffer[0] = 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio10_control[test_n].ux_device_class_audio10_control_changed == UX_DEVICE_CLASS_AUDIO10_CONTROL_MUTE_CHANGED); + UX_TEST_ASSERT(g_slave_audio10_control[test_n].ux_device_class_audio10_control_mute[0] == 0); + + /* Issue SetFeatureMute(test_tmp[test_n], 1). */ + buffer[0] = 1; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio10_control[test_n].ux_device_class_audio10_control_changed == UX_DEVICE_CLASS_AUDIO10_CONTROL_MUTE_CHANGED); + UX_TEST_ASSERT(g_slave_audio10_control[test_n].ux_device_class_audio10_control_mute[0] == 1); + + /* Issue SetFeatureVolume(test_tmp[test_n], 0x0003). */ + transfer_request -> ux_transfer_request_requested_length = 2; + transfer_request -> ux_transfer_request_index = (test_tmp[test_n] << 8) | 1; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO10_FU_VOLUME_CONTROL << 8) | 0; + buffer[0] = 3; buffer[1] = 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio10_control[test_n].ux_device_class_audio10_control_changed == UX_DEVICE_CLASS_AUDIO10_CONTROL_VOLUME_CHANGED); + UX_TEST_ASSERT(g_slave_audio10_control[test_n].ux_device_class_audio10_control_volume[0] == 0x0003); + + /* Issue SetFeatureVolume(test_tmp[test_n], 0x0103). */ + buffer[1] = 1; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio10_control[test_n].ux_device_class_audio10_control_changed == UX_DEVICE_CLASS_AUDIO10_CONTROL_VOLUME_CHANGED); + UX_TEST_ASSERT(g_slave_audio10_control[test_n].ux_device_class_audio10_control_volume[0] == 0x0103); + + /* Issue SetFeatureVolume(test_tmp[test_n], 0x0103). */ + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio10_control[test_n].ux_device_class_audio10_control_changed == 0); + + /* Issue GetFeatureMute(test_tmp[test_n]). */ + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_AUDIO10_GET_CUR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + + transfer_request -> ux_transfer_request_requested_length = 1; + transfer_request -> ux_transfer_request_index = (test_tmp[test_n] << 8) | 1; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO10_FU_MUTE_CONTROL << 8) | 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(transfer_request -> ux_transfer_request_actual_length == 1); + UX_TEST_ASSERT(buffer[0] == 1); + + /* Issue GetFeatureMute(test_tmp[test_n]). */ + transfer_request -> ux_transfer_request_requested_length = 2; + transfer_request -> ux_transfer_request_index = (test_tmp[test_n] << 8) | 1; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO10_FU_VOLUME_CONTROL << 8) | 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(transfer_request -> ux_transfer_request_actual_length == 2); + UX_TEST_ASSERT(buffer[0] == 3); + UX_TEST_ASSERT(buffer[1] == 1); + } + + /* SetSamFreq(0x81, 44100): nothing changed. */ + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_AUDIO10_SET_CUR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_ENDPOINT; + transfer_request -> ux_transfer_request_requested_length = 3; + transfer_request -> ux_transfer_request_index = 0x81; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO10_EP_SAMPLING_FREQ_CONTROL << 8) | 0; + ux_utility_long_put(transfer_request -> ux_transfer_request_data_pointer, 44100); + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(transfer_request -> ux_transfer_request_actual_length == 3); + UX_TEST_ASSERT(g_slave_audio10_control[1].ux_device_class_audio10_control_sam_freq == 48000); + + /* SetSamFreq(0x00, 44100): STALL. */ + transfer_request -> ux_transfer_request_index = 0x00; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_CODE(UX_TRANSFER_STALLED, status); + + /* Modify sampling frequency type ... */ + const UCHAR freq_types_continuous[] = { + 0, + UX_DW0( 8000), UX_DW1( 8000), UX_DW2( 8000), + UX_DW0(48000), UX_DW1(48000), UX_DW2(48000), + }; + g_slave_audio10_control[1].ux_device_class_audio10_control_sam_freq_types = (UCHAR *)freq_types_continuous; + + /* SetSamFreq(0x81, 96000): nothing changed. */ + transfer_request -> ux_transfer_request_index = 0x81; + ux_utility_long_put(transfer_request -> ux_transfer_request_data_pointer, 96000); + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(transfer_request -> ux_transfer_request_actual_length == 3); + UX_TEST_ASSERT(g_slave_audio10_control[1].ux_device_class_audio10_control_sam_freq == 48000); + + /* SetSamFreq(0x81, 44100): changed. */ + ux_utility_long_put(transfer_request -> ux_transfer_request_data_pointer, 44100); + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(transfer_request -> ux_transfer_request_actual_length == 3); + UX_TEST_ASSERT(g_slave_audio10_control[1].ux_device_class_audio10_control_sam_freq == 44100); + + /* GetSamFreq(0x81). */ + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_AUDIO10_GET_CUR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_ENDPOINT; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(buffer[0] == UX_DW0(44100)); + UX_TEST_ASSERT(buffer[1] == UX_DW1(44100)); + UX_TEST_ASSERT(buffer[2] == UX_DW2(44100)); + + /* Modify sampling frequency type ... */ + const UCHAR freq_types_list[] = { + 3, + UX_DW0( 8000), UX_DW1( 8000), UX_DW2( 8000), + UX_DW0(48000), UX_DW1(48000), UX_DW2(48000), + UX_DW0(96000), UX_DW1(96000), UX_DW2(96000), + }; + g_slave_audio10_control[1].ux_device_class_audio10_control_sam_freq_types = (UCHAR *)freq_types_list; + + /* SetSamFreq(0x81, 4000): changed to min - 8000. */ + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_AUDIO10_SET_CUR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_ENDPOINT; + transfer_request -> ux_transfer_request_index = 0x81; + ux_utility_long_put(transfer_request -> ux_transfer_request_data_pointer, 4000); + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(transfer_request -> ux_transfer_request_actual_length == 3); + UX_TEST_ASSERT(g_slave_audio10_control[1].ux_device_class_audio10_control_sam_freq == 8000); + + /* SetSamFreq(0x81, 128000): changed to max - 96000. */ + ux_utility_long_put(transfer_request -> ux_transfer_request_data_pointer, 128000); + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(transfer_request -> ux_transfer_request_actual_length == 3); + UX_TEST_ASSERT(g_slave_audio10_control[1].ux_device_class_audio10_control_sam_freq == 96000); + + /* SetSamFreq(0x81, 48000): changed. */ + ux_utility_long_put(transfer_request -> ux_transfer_request_data_pointer, 48000); + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(transfer_request -> ux_transfer_request_actual_length == 3); + UX_TEST_ASSERT(g_slave_audio10_control[1].ux_device_class_audio10_control_sam_freq == 48000); + + /* GetSamFreq(0x81). */ + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_AUDIO10_GET_CUR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_ENDPOINT; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(buffer[0] == UX_DW0(48000)); + UX_TEST_ASSERT(buffer[1] == UX_DW1(48000)); + UX_TEST_ASSERT(buffer[2] == UX_DW2(48000)); + + /* Wait pending threads. */ + _ux_utility_thread_sleep(1); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + ux_device_stack_class_unregister(_ux_system_slave_class_audio_name, ux_device_class_audio_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + while(1) + { + + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); + } +} diff --git a/test/regression/usbx_audio10_iad_device_interrupt_test.c b/test/regression/usbx_audio10_iad_device_interrupt_test.c new file mode 100644 index 00000000..70cbd2c6 --- /dev/null +++ b/test/regression/usbx_audio10_iad_device_interrupt_test.c @@ -0,0 +1,1103 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" + +#include "fx_api.h" + +#include "ux_device_class_audio.h" +#include "ux_device_class_audio10.h" +#include "ux_device_stack.h" + +#include "ux_host_class_audio.h" +#include "ux_host_class_dummy.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_DEMO_REQUEST_MAX_LENGTH \ + ((UX_HCD_SIM_HOST_MAX_PAYLOAD) > (UX_SLAVE_REQUEST_DATA_MAX_LENGTH) ? \ + (UX_HCD_SIM_HOST_MAX_PAYLOAD) : (UX_SLAVE_REQUEST_DATA_MAX_LENGTH)) + +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_DEMO_REQUEST_MAX_LENGTH + 1) +#define UX_DEMO_MEMORY_SIZE (128*1024) + +#define UX_TEST_LOG_SIZE (64) + +#define UX_TEST_STATUS_QUEUE_MAX_SIZE 8 + + +/* Define local/extern function prototypes. */ +static void test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static void tx_test_thread_host_simulation_entry(ULONG); +static void tx_test_thread_slave_simulation_entry(ULONG); + + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[64]; + +static UX_HOST_CLASS_DUMMY *dummy_control; +static UX_HOST_CLASS_DUMMY *dummy_tx; +static UX_HOST_CLASS_DUMMY *dummy_rx; + +static UX_DEVICE_CLASS_AUDIO *slave_audio; +static UX_DEVICE_CLASS_AUDIO_PARAMETER slave_audio_parameter; +static UX_DEVICE_CLASS_AUDIO_STREAM_PARAMETER slave_audio_stream_parameter[2]; + +static UX_DEVICE_CLASS_AUDIO_STREAM *slave_audio_tx_stream; + +static UX_DEVICE_CLASS_AUDIO_STREAM *slave_audio_rx_stream; +static UX_SLAVE_TRANSFER *slave_audio_rx_transfer; + +static UX_HOST_CLASS_AUDIO *audio; + +static UX_DEVICE_CLASS_AUDIO10_CONTROL g_slave_audio10_control[2]; + +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_audio_sem_usage; +static ULONG rsc_audio_sem_get_count; +static ULONG rsc_audio_mutex_usage; +static ULONG rsc_audio_mem_usage; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +static struct BUFFER_LOG_STRUCT { + ULONG length; + UCHAR data[256]; +} buffer_log[UX_TEST_LOG_SIZE]; +static ULONG buffer_log_count = 0; +#define SAVE_BUFFER_LOG(buf,siz) do { \ + if (buffer_log_count < UX_TEST_LOG_SIZE) { \ + ULONG __local_size__ = ((siz) > 256) ? 256 : (siz); \ + buffer_log[buffer_log_count].length = (siz); \ + _ux_utility_memory_copy(buffer_log[buffer_log_count].data, (buf), __local_size__); \ + } \ + buffer_log_count ++; \ +} while(0) + +static ULONG test_tx_ack_count = 0xFFFFFFFF; +static ULONG test_tx_ins_count = 0; +static ULONG test_tx_ins_way = 0; + +static struct CALLBACK_INVOKE_LOG_STRUCT { + VOID *func; + VOID *param1; + VOID *param2; + VOID *param3; +} callback_invoke_log[UX_TEST_LOG_SIZE]; +static ULONG callback_invoke_count = 0; + +#define SAVE_CALLBACK_INVOKE_LOG(f,p1,p2,p3) do { \ + if (callback_invoke_count < UX_TEST_LOG_SIZE) { \ + callback_invoke_log[callback_invoke_count].func = (VOID *)(f); \ + callback_invoke_log[callback_invoke_count].param1 = (VOID *)(p1); \ + callback_invoke_log[callback_invoke_count].param2 = (VOID *)(p2); \ + callback_invoke_log[callback_invoke_count].param3 = (VOID *)(p3); \ + callback_invoke_count++; \ + } \ +} while(0) +#define RESET_CALLBACK_INVOKE_LOG() do { \ + callback_invoke_count = 0; \ +} while(0) + +/* Define device framework. */ + +#define D3(d) ((UCHAR)((d) >> 24)) +#define D2(d) ((UCHAR)((d) >> 16)) +#define D1(d) ((UCHAR)((d) >> 8)) +#define D0(d) ((UCHAR)((d) >> 0)) + +static unsigned char device_framework_full_speed[] = { + +/* --------------------------------------- Device Descriptor */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 0x08, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x01, 0x00, +/* 12 bcdDevice */ D0(0x100),D1(0x100), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* -------------------------------- Configuration Descriptor *//* 9+8+88+52*2=209 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(209),D1(209), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------ Interface Association Descriptor */ +/* 0 bLength, bDescriptorType */ 8, 0x0B, +/* 2 bFirstInterface, bInterfaceCount */ 0, 3, +/* 4 bFunctionClass, bFunctionSubClass, bFunctionProtocol */ 0x01, 0x01, 0x00, +/* 7 iFunction */ 0, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+72+7=88) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x00, +/* 8 iInterface */ 0, +/* ---------------- Audio 1.0 AC Interface Header Descriptor *//* (10+12*2+10*2+9*2=72) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x01, +/* 3 bcdADC */ 0x00, 0x01, +/* 5 wTotalLength, bInCollection */ D0(72),D1(72), 2, +/* 8 baInterfaceNr(1) ... baInterfaceNr(n) */ 1, 2, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x02, +/* 8 iTerminal */ 0, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x05, +/* 8 iTerminal */ 0, +/* --------------- Audio 1.0 AC Interrupt Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x83, 0x03, +/* 4 wMaxPacketSize, bInterval */ D0(8),D1(8), 1, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x03, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 1, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x04, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 1, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { +/* --------------------------------------- Device Descriptor */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x01, 0x00, +/* 12 bcdDevice */ D0(0x100),D1(0x100), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* ----------------------------- Device Qualifier Descriptor */ +/* 0 bLength, bDescriptorType */ 10, 0x06, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 bNumConfigurations */ 1, +/* 9 bReserved */ 0, + +/* -------------------------------- Configuration Descriptor *//* 9+8+88+52*2=209 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(209),D1(209), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------ Interface Association Descriptor */ +/* 0 bLength, bDescriptorType */ 8, 0x0B, +/* 2 bFirstInterface, bInterfaceCount */ 0, 3, +/* 4 bFunctionClass, bFunctionSubClass, bFunctionProtocol */ 0x01, 0x01, 0x00, +/* 7 iFunction */ 0, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+72+7=88) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x00, +/* 8 iInterface */ 0, +/* ---------------- Audio 1.0 AC Interface Header Descriptor *//* (10+12*2+10*2+9*2=72) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x01, +/* 3 bcdADC */ 0x00, 0x01, +/* 5 wTotalLength, bInCollection */ D0(72),D1(72), 2, +/* 8 baInterfaceNr(1) ... baInterfaceNr(n) */ 1, 2, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x02, +/* 8 iTerminal */ 0, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x05, +/* 8 iTerminal */ 0, +/* --------------- Audio 1.0 AC Interrupt Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x83, 0x03, +/* 4 wMaxPacketSize, bInterval */ D0(8),D1(8), 1, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x03, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 4, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x04, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 4, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + +/* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + +/* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + +/* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; +static UX_TEST_SETUP _GetCfgDescr = UX_TEST_SETUP_GetCfgDescr; +static UX_TEST_SETUP _SetAddress = UX_TEST_SETUP_SetAddress; +static UX_TEST_SETUP _GetDeviceDescriptor = UX_TEST_SETUP_GetDevDescr; +static UX_TEST_SETUP _GetConfigDescriptor = UX_TEST_SETUP_GetCfgDescr; + +/* Interaction define */ + +/* Hooks define */ + +static VOID ux_device_class_audio_tx_hook(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *p = (UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *)params; +UX_SLAVE_TRANSFER *transfer = (UX_SLAVE_TRANSFER *)p -> parameter; +UCHAR tmp[32] = {'i','n','s','e','r','t','A',0}; + + + (void)params; + // printf("tTX\n"); + + /* Acknowledge frame sent. */ + if (test_tx_ack_count) + { + SAVE_BUFFER_LOG(transfer -> ux_slave_transfer_request_data_pointer, transfer -> ux_slave_transfer_request_requested_length); + transfer -> ux_slave_transfer_request_actual_length = transfer -> ux_slave_transfer_request_requested_length; + transfer -> ux_slave_transfer_request_completion_code = UX_SUCCESS; + ux_test_dcd_sim_slave_transfer_done(transfer, UX_SUCCESS); + } + if (test_tx_ack_count != 0xFFFFFFFF && test_tx_ack_count > 0) + test_tx_ack_count --; + + /* Insert frames when sent. */ + if (test_tx_ins_count) + { + tmp[6] = (test_tx_ins_count % 26) + 'A'; + if (test_tx_ins_way == 0) + ux_device_class_audio_frame_write(slave_audio_tx_stream, tmp, 32); + else + { + + UCHAR *frame; + ULONG frame_length; + + + ux_device_class_audio_write_frame_get(slave_audio_tx_stream, &frame, &frame_length); + _ux_utility_memory_copy(frame, tmp, 32); + ux_device_class_audio_write_frame_commit(slave_audio_tx_stream, 32); + } + } + if (test_tx_ins_count != 0xFFFFFFFF && test_tx_ins_count > 0) + test_tx_ins_count --; +} + +static VOID ux_device_class_audio_rx_hook(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *p = (UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *)params; +UX_SLAVE_TRANSFER *transfer = (UX_SLAVE_TRANSFER *)p -> parameter; + + + (void)action; + (void)params; + (void)p; + (void)transfer; + // printf("tRX\n"); + slave_audio_rx_transfer = transfer; +} +static VOID slave_audio_rx_simulate_one_frame(UCHAR *frame, ULONG frame_length) +{ + UX_TEST_ASSERT(slave_audio_rx_transfer); + if (frame_length) + { + _ux_utility_memory_copy(slave_audio_rx_transfer->ux_slave_transfer_request_data_pointer, frame, frame_length); + slave_audio_rx_transfer->ux_slave_transfer_request_actual_length = frame_length; + slave_audio_rx_transfer->ux_slave_transfer_request_completion_code = UX_SUCCESS; + } + ux_test_dcd_sim_slave_transfer_done(slave_audio_rx_transfer, UX_SUCCESS); + _ux_utility_thread_sleep(1); +} + +static UX_TEST_ACTION ux_device_class_audio_transfer_hook[] = +{ + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .action_func = ux_device_class_audio_tx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x81, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .action_func = ux_device_class_audio_rx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x02, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, +{ 0 }, +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* 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 ++; + // printf("Error #%d, system_level: %d, system_context: %d, error_code: 0x%x\n", __LINE__, system_level, system_context, error_code); + + if (!error_callback_ignore) + { + { + /* Failed test. */ + 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 VOID slave_audio_activate(VOID *audio_instance) +{ + slave_audio = (UX_DEVICE_CLASS_AUDIO *)audio_instance; + ux_device_class_audio_stream_get(slave_audio, 0, &slave_audio_tx_stream); + ux_device_class_audio_stream_get(slave_audio, 1, &slave_audio_rx_stream); + // printf("sAUD:%p;%p,%p\n", audio_instance, slave_audio_tx_stream, slave_audio_rx_stream); +} +static VOID slave_audio_deactivate(VOID *audio_instance) +{ + if ((VOID *)slave_audio == audio_instance) + { + slave_audio = UX_NULL; + slave_audio_tx_stream = UX_NULL; + slave_audio_rx_stream = UX_NULL; + } +} +static VOID slave_audio_feature_change(struct UX_DEVICE_CLASS_AUDIO_STRUCT *audio, VOID *ext, ULONG selector) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_feature_change, audio, ext, (ALIGN_TYPE)selector); +} +static VOID slave_audio_tx_stream_change(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG alt) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_tx_stream_change, audio, (ALIGN_TYPE)alt, 0); +} +static VOID slave_audio_rx_stream_change(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG alt) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_rx_stream_change, audio, (ALIGN_TYPE)alt, 0); + + slave_audio_rx_transfer = UX_NULL; +} +static UINT slave_audio_control_process(UX_DEVICE_CLASS_AUDIO *audio, UX_SLAVE_TRANSFER *transfer) +{ + +UINT status; +UX_DEVICE_CLASS_AUDIO10_CONTROL_GROUP group = + {2, g_slave_audio10_control}; + + + SAVE_CALLBACK_INVOKE_LOG(slave_audio_control_process, audio, transfer, 0); + + status = ux_device_class_audio10_control_process(audio, transfer, &group); + if (status == UX_SUCCESS) + { + if (g_slave_audio10_control[0].ux_device_class_audio10_control_changed == UX_DEVICE_CLASS_AUDIO10_CONTROL_MUTE_CHANGED) + { + /* Mute change! */ + } + if (g_slave_audio10_control[0].ux_device_class_audio10_control_changed == UX_DEVICE_CLASS_AUDIO10_CONTROL_VOLUME_CHANGED) + { + /* Volume change! */ + } + if (g_slave_audio10_control[1].ux_device_class_audio10_control_changed == UX_DEVICE_CLASS_AUDIO10_CONTROL_MUTE_CHANGED) + { + /* Mute change! */ + } + if (g_slave_audio10_control[1].ux_device_class_audio10_control_changed == UX_DEVICE_CLASS_AUDIO10_CONTROL_VOLUME_CHANGED) + { + /* Volume change! */ + } + } + return(status); +} +static VOID slave_audio_tx_done(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG length) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_tx_done, audio, (ALIGN_TYPE)length, 0); +} +static VOID slave_audio_rx_done(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG length) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_rx_done, audio, (ALIGN_TYPE)length, 0); +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_DUMMY *dummy = (UX_HOST_CLASS_DUMMY *) inst; + + + switch(event) + { + + case UX_DEVICE_INSERTION: + + // printf("hINS:%p,%p:%ld\n", cls, inst, dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber); + switch(dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber) + { + case 0: dummy_control = dummy; break; + case 1: dummy_rx = dummy; break; + case 2: dummy_tx = dummy; break; + } + break; + + case UX_DEVICE_REMOVAL: + + // printf("hRMV:%p,%p:%ld\n", cls, inst, dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber); + switch(dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber) + { + case 0: dummy_control = UX_NULL; break; + case 1: dummy_rx = UX_NULL; break; + case 2: dummy_tx = UX_NULL; break; + } + break; + + default: + break; + } + return 0; +} + + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_audio10_iad_device_control_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running Audio 1.0 IAD Device Interrupt Functionality Test........... "); + stepinfo("\n"); + + /* 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(); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* 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_host_change_function); + UX_TEST_CHECK_SUCCESS(status); + + /* Register Audio class. */ + status = ux_host_stack_class_register(_ux_host_class_dummy_name, _ux_host_class_dummy_entry); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Set the parameters for callback when insertion/extraction of a Audio 1.0 device, with IAD. */ + ux_utility_memory_set(&slave_audio_parameter, 0, sizeof(slave_audio_parameter)); + ux_utility_memory_set(slave_audio_stream_parameter, 0, sizeof(slave_audio_stream_parameter)); +#if !defined(UX_DEVICE_STANDALONE) + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_thread_entry = ux_device_class_audio_write_thread_entry; +#else + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_task_function = _ux_device_class_audio_write_task_function; +#endif + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_change = slave_audio_tx_stream_change; + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_frame_done = slave_audio_tx_done; + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_max_frame_buffer_size = 256; + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_max_frame_buffer_nb = 8; + +#if !defined(UX_DEVICE_STANDALONE) + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_thread_entry = ux_device_class_audio_read_thread_entry; +#else + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_task_function = _ux_device_class_audio_read_task_function; +#endif + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_change = slave_audio_rx_stream_change; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_frame_done = slave_audio_rx_done; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_max_frame_buffer_size = 256; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_max_frame_buffer_nb = 8; + slave_audio_parameter.ux_device_class_audio_parameter_streams = slave_audio_stream_parameter; + slave_audio_parameter.ux_device_class_audio_parameter_streams_nb = 2; + + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_slave_class_audio_instance_activate = slave_audio_activate; + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_slave_class_audio_instance_deactivate = slave_audio_deactivate; + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_device_class_audio_control_process = slave_audio_control_process; + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_device_class_audio_arg = UX_NULL; + +#if defined(UX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT) + slave_audio_parameter.ux_device_class_audio_parameter_status_size = 2; /* UAC 1.0. */ + slave_audio_parameter.ux_device_class_audio_parameter_status_queue_size = UX_TEST_STATUS_QUEUE_MAX_SIZE; /* Queue 8 interrupts. */ +#endif + + g_slave_audio10_control[0].ux_device_class_audio10_control_fu_id = 2; + g_slave_audio10_control[0].ux_device_class_audio10_control_mute[0] = 0; + g_slave_audio10_control[0].ux_device_class_audio10_control_volume[0] = 0; + g_slave_audio10_control[1].ux_device_class_audio10_control_fu_id = 5; + g_slave_audio10_control[1].ux_device_class_audio10_control_mute[0] = 0; + g_slave_audio10_control[1].ux_device_class_audio10_control_volume[0] = 0; + + /* Initialize the device Audio class. This class owns interfaces starting with 0, 1, 2. */ + status = ux_device_stack_class_register(_ux_system_slave_class_audio_name, ux_device_class_audio_entry, + 1, 0, &slave_audio_parameter); + UX_TEST_CHECK_SUCCESS(status); + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx demo host simulation", tx_test_thread_host_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx demo slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_CHECK_SUCCESS(status); +} + +static UINT test_wait_until_expected(VOID **ptr, ULONG loop, VOID *expected) +{ + while(loop) + { + _ux_utility_delay_ms(10); + if (*ptr == expected) + return UX_SUCCESS; + } + return UX_ERROR; +} +static UINT test_wait_until_not_expected(VOID **ptr, ULONG loop, VOID *expected) +{ + while(loop) + { + _ux_utility_delay_ms(10); + if (*ptr != expected) + return UX_SUCCESS; + } + return UX_ERROR; +} +#define test_wait_until_not_null(ptr, loop) test_wait_until_not_expected(ptr, loop, UX_NULL) +#define test_wait_until_null(ptr, loop) test_wait_until_expected(ptr, loop, UX_NULL) + +#if defined(UX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT) +static void _test_device_uac_interrupts(ULONG queue_size) +{ +ULONG i, actual; +UINT status; +UCHAR status_word[2]; +UCHAR host_status[2]; + stepinfo("== Device UAC status queue size %ld\n", queue_size); + /* Setup queue size. */ + slave_audio->ux_device_class_audio_status_queue_bytes = queue_size * slave_audio->ux_device_class_audio_status_size; + slave_audio->ux_device_class_audio_status_head = slave_audio->ux_device_class_audio_status_queue; + slave_audio->ux_device_class_audio_status_tail = slave_audio->ux_device_class_audio_status_queue; + + /* Fill status up to size. */ + for (i = 0; i < queue_size; i ++) + { + status_word[0] = i; + status_word[1] = i; + status = ux_device_class_audio_interrupt_send(slave_audio, status_word); + UX_TEST_CHECK_SUCCESS(status); + } + /* Fill one duplicate status, success. */ + status_word[0] = 0; + status_word[1] = 0; + status = ux_device_class_audio_interrupt_send(slave_audio, status_word); + UX_TEST_CHECK_SUCCESS(status); + /* Fill one more status, fail. */ + status_word[0] = i; + status_word[1] = i; + status = ux_device_class_audio_interrupt_send(slave_audio, status_word); + UX_TEST_CHECK_CODE(UX_BUSY, status); + /* Read status on host side up to size. */ + _ux_host_class_dummy_set_timeout(dummy_control, 0x83, 0, 10); + for (i = 0; i < queue_size; i ++) + { + status = _ux_host_class_dummy_transfer(dummy_control, 0x83, 0, host_status, 2, &actual); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(actual == 2); + UX_TEST_ASSERT(host_status[0] == i); + UX_TEST_ASSERT(host_status[1] == i); + } + /* Read one more status, fail. */ + status = _ux_host_class_dummy_transfer(dummy_control, 0x83, 0, host_status, 2, &actual); + UX_TEST_CHECK_NOT_SUCCESS(status); + /* Fill status and read status 2*queue_size times, success. */ + for (i = 0; i < (queue_size * 2); i ++) + { + status_word[0] = i; + status_word[1] = i; + status = ux_device_class_audio_interrupt_send(slave_audio, status_word); + UX_TEST_CHECK_SUCCESS(status); + + status = _ux_host_class_dummy_transfer(dummy_control, 0x83, 0, host_status, 2, &actual); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(actual == 2); + UX_TEST_ASSERT(host_status[0] == i); + UX_TEST_ASSERT(host_status[1] == i); + } + /* The status queue is NULL. */ + UX_TEST_ASSERT((slave_audio->ux_device_class_audio_status_head == slave_audio->ux_device_class_audio_status_tail) && + (slave_audio->ux_device_class_audio_status_queued == 0)); +} +#endif + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +UX_INTERFACE *interface_inst[3][2]; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UCHAR test_tmp[32]; + + + /* Test connect. */ + status = test_wait_until_not_null((void**)&dummy_control, 100); + status |= test_wait_until_not_null((void**)&dummy_tx, 100); + status |= test_wait_until_not_null((void**)&dummy_rx, 100); + status |= test_wait_until_not_null((void**)&slave_audio_tx_stream, 100); + status |= test_wait_until_not_null((void**)&slave_audio_rx_stream, 100); + UX_TEST_CHECK_SUCCESS(status); + + /* Validate configuration descriptors. */ + /* ... */ + + /* Get testing instances. */ + + status = ux_host_stack_device_get(0, &device); + UX_TEST_CHECK_SUCCESS(status); + + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + status = ux_host_stack_device_configuration_get(device, 0, &configuration); + UX_TEST_CHECK_SUCCESS(status); + + interface = configuration -> ux_configuration_first_interface; + while(interface) + { + // printf("Interface: %ld.%ld\n", interface -> ux_interface_descriptor.bInterfaceNumber, interface -> ux_interface_descriptor.bAlternateSetting); + interface_inst[interface -> ux_interface_descriptor.bInterfaceNumber][interface -> ux_interface_descriptor.bAlternateSetting] = interface; + interface = interface -> ux_interface_next_interface; + } + + /**************************************************************************/ + + /* Control requests test. */ + + transfer_request -> ux_transfer_request_data_pointer = buffer; + + test_tmp[0] = 2; + test_tmp[1] = 5; + + for (test_n = 0; test_n < 2; test_n ++) + { + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_AUDIO10_SET_CUR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + + /* Issue SetFeatureMute(test_tmp[test_n], 0). */ + transfer_request -> ux_transfer_request_requested_length = 1; + transfer_request -> ux_transfer_request_index = (test_tmp[test_n] << 8) | 1; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO10_FU_MUTE_CONTROL << 8) | 0; + buffer[0] = 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio10_control[test_n].ux_device_class_audio10_control_changed == 0); + + /* Issue SetFeatureMute(test_tmp[test_n], 1). */ + buffer[0] = 1; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio10_control[test_n].ux_device_class_audio10_control_changed == UX_DEVICE_CLASS_AUDIO10_CONTROL_MUTE_CHANGED); + UX_TEST_ASSERT(g_slave_audio10_control[test_n].ux_device_class_audio10_control_mute[0] == 1); + + /* Issue SetFeatureMute(test_tmp[test_n], 0). */ + buffer[0] = 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio10_control[test_n].ux_device_class_audio10_control_changed == UX_DEVICE_CLASS_AUDIO10_CONTROL_MUTE_CHANGED); + UX_TEST_ASSERT(g_slave_audio10_control[test_n].ux_device_class_audio10_control_mute[0] == 0); + + /* Issue SetFeatureMute(test_tmp[test_n], 1). */ + buffer[0] = 1; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio10_control[test_n].ux_device_class_audio10_control_changed == UX_DEVICE_CLASS_AUDIO10_CONTROL_MUTE_CHANGED); + UX_TEST_ASSERT(g_slave_audio10_control[test_n].ux_device_class_audio10_control_mute[0] == 1); + + /* Issue SetFeatureVolume(test_tmp[test_n], 0x0003). */ + transfer_request -> ux_transfer_request_requested_length = 2; + transfer_request -> ux_transfer_request_index = (test_tmp[test_n] << 8) | 1; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO10_FU_VOLUME_CONTROL << 8) | 0; + buffer[0] = 3; buffer[1] = 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio10_control[test_n].ux_device_class_audio10_control_changed == UX_DEVICE_CLASS_AUDIO10_CONTROL_VOLUME_CHANGED); + UX_TEST_ASSERT(g_slave_audio10_control[test_n].ux_device_class_audio10_control_volume[0] == 0x0003); + + /* Issue SetFeatureVolume(test_tmp[test_n], 0x0103). */ + buffer[1] = 1; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio10_control[test_n].ux_device_class_audio10_control_changed == UX_DEVICE_CLASS_AUDIO10_CONTROL_VOLUME_CHANGED); + UX_TEST_ASSERT(g_slave_audio10_control[test_n].ux_device_class_audio10_control_volume[0] == 0x0103); + + /* Issue SetFeatureVolume(test_tmp[test_n], 0x0103). */ + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio10_control[test_n].ux_device_class_audio10_control_changed == 0); + + /* Issue GetFeatureMute(test_tmp[test_n]). */ + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_AUDIO10_GET_CUR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + + transfer_request -> ux_transfer_request_requested_length = 1; + transfer_request -> ux_transfer_request_index = (test_tmp[test_n] << 8) | 1; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO10_FU_MUTE_CONTROL << 8) | 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(transfer_request -> ux_transfer_request_actual_length == 1); + UX_TEST_ASSERT(buffer[0] == 1); + + /* Issue GetFeatureMute(test_tmp[test_n]). */ + transfer_request -> ux_transfer_request_requested_length = 2; + transfer_request -> ux_transfer_request_index = (test_tmp[test_n] << 8) | 1; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO10_FU_VOLUME_CONTROL << 8) | 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(transfer_request -> ux_transfer_request_actual_length == 2); + UX_TEST_ASSERT(buffer[0] == 3); + UX_TEST_ASSERT(buffer[1] == 1); + } + + /**************************************************************************/ + + /* Interrupt test. */ +#if defined(UX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT) + for (test_n = 1; test_n <= UX_TEST_STATUS_QUEUE_MAX_SIZE; test_n <<= 1) + _test_device_uac_interrupts(test_n); +#endif + + /* Wait pending threads. */ + _ux_utility_thread_sleep(1); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + ux_device_stack_class_unregister(_ux_system_slave_class_audio_name, ux_device_class_audio_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + while(1) + { + +#if defined(UX_DEVICE_STANDALONE) + + /* Standalone background task. */ + ux_system_tasks_run(); +#else + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); +#endif + } +} diff --git a/test/regression/usbx_audio10_iad_host_basic_test.c b/test/regression/usbx_audio10_iad_host_basic_test.c new file mode 100644 index 00000000..3bf41d86 --- /dev/null +++ b/test/regression/usbx_audio10_iad_host_basic_test.c @@ -0,0 +1,1404 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" + +#include "fx_api.h" + +#include "ux_device_class_audio.h" +#include "ux_device_stack.h" + +#include "ux_host_class_audio.h" +#include "ux_host_class_audio.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_DEMO_REQUEST_MAX_LENGTH \ + ((UX_HCD_SIM_HOST_MAX_PAYLOAD) > (UX_SLAVE_REQUEST_DATA_MAX_LENGTH) ? \ + (UX_HCD_SIM_HOST_MAX_PAYLOAD) : (UX_SLAVE_REQUEST_DATA_MAX_LENGTH)) + +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_DEMO_REQUEST_MAX_LENGTH + 1) +#define UX_DEMO_MEMORY_SIZE (128*1024) + +#define UX_TEST_LOG_SIZE (64) + + +/* Define local/extern function prototypes. */ +static void test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static void tx_test_thread_host_simulation_entry(ULONG); +static void tx_test_thread_slave_simulation_entry(ULONG); + + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +#if defined(UX_HOST_CLASS_AUDIO_INTERRUPT_SUPPORT) +static UX_HOST_CLASS_AUDIO_AC *host_audio_ac; +static UCHAR demo_device_interrupt_msg[8]; +static ULONG demo_device_interrupt_len; +static UCHAR demo_host_interrupt_msg[8]; +static ULONG demo_host_interrupt_len; +#endif +static UX_HOST_CLASS_AUDIO *host_audio_tx; +static UX_HOST_CLASS_AUDIO *host_audio_rx; + +static UX_HOST_CLASS_AUDIO_TRANSFER_REQUEST audio_transfer1 = {0}; +static UX_HOST_CLASS_AUDIO_TRANSFER_REQUEST audio_transfer2 = {0}; +UCHAR host_audio_buffer[2][1024 * 3]; + +static UX_DEVICE_CLASS_AUDIO *slave_audio; +static UX_DEVICE_CLASS_AUDIO_PARAMETER slave_audio_parameter; +static UX_DEVICE_CLASS_AUDIO_STREAM_PARAMETER slave_audio_stream_parameter[2]; + +static UX_DEVICE_CLASS_AUDIO_STREAM *slave_audio_tx_stream; + +static UX_DEVICE_CLASS_AUDIO_STREAM *slave_audio_rx_stream; +static UX_SLAVE_TRANSFER *slave_audio_rx_transfer; + +static UX_HOST_CLASS_AUDIO *audio; + +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_mem_alloc_cnt_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_enum_mem_alloc_count; + +static ULONG rsc_audio_sem_usage; +static ULONG rsc_audio_sem_get_count; +static ULONG rsc_audio_mutex_usage; +static ULONG rsc_audio_mem_usage; +static ULONG rsc_audio_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +static struct BUFFER_LOG_STRUCT { + ULONG length; + UCHAR data[256]; +} buffer_log[UX_TEST_LOG_SIZE]; +static ULONG buffer_log_count = 0; +#define SAVE_BUFFER_LOG(buf,siz) do { \ + if (buffer_log_count < UX_TEST_LOG_SIZE) { \ + ULONG __local_size__ = ((siz) > 256) ? 256 : (siz); \ + buffer_log[buffer_log_count].length = (siz); \ + _ux_utility_memory_copy(buffer_log[buffer_log_count].data, (buf), __local_size__); \ + } \ + buffer_log_count ++; \ +} while(0) + +static ULONG test_tx_ack_count = 0xFFFFFFFF; +static ULONG test_tx_ins_count = 0; +static ULONG test_tx_ins_way = 0; + +static struct CALLBACK_INVOKE_LOG_STRUCT { + VOID *func; + VOID *param1; + VOID *param2; + VOID *param3; +} callback_invoke_log[UX_TEST_LOG_SIZE]; +static ULONG callback_invoke_count = 0; + +#define SAVE_CALLBACK_INVOKE_LOG(f,p1,p2,p3) do { \ + if (callback_invoke_count < UX_TEST_LOG_SIZE) { \ + callback_invoke_log[callback_invoke_count].func = (VOID *)(f); \ + callback_invoke_log[callback_invoke_count].param1 = (VOID *)(p1); \ + callback_invoke_log[callback_invoke_count].param2 = (VOID *)(p2); \ + callback_invoke_log[callback_invoke_count].param3 = (VOID *)(p3); \ + callback_invoke_count++; \ + } \ +} while(0) +#define RESET_CALLBACK_INVOKE_LOG() do { \ + callback_invoke_count = 0; \ +} while(0) + +/* Define device framework. */ + +#define D3(d) ((UCHAR)((d) >> 24)) +#define D2(d) ((UCHAR)((d) >> 16)) +#define D1(d) ((UCHAR)((d) >> 8)) +#define D0(d) ((UCHAR)((d) >> 0)) + +static unsigned char device_framework_full_speed[] = { + +/* --------------------------------------- Device Descriptor */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 0x08, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x01, 0x00, +/* 12 bcdDevice */ D0(0x100),D1(0x100), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* -------------------------------- Configuration Descriptor *//* 9+8+88+52*2=209 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(209),D1(209), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------ Interface Association Descriptor */ +/* 0 bLength, bDescriptorType */ 8, 0x0B, +/* 2 bFirstInterface, bInterfaceCount */ 0, 3, +/* 4 bFunctionClass, bFunctionSubClass, bFunctionProtocol */ 0x01, 0x01, 0x00, +/* 7 iFunction */ 0, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+72+7=88) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x00, +/* 8 iInterface */ 0, +/* ---------------- Audio 1.0 AC Interface Header Descriptor *//* (10+12*2+10*2+9*2=72) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x01, +/* 3 bcdADC */ 0x00, 0x01, +/* 5 wTotalLength, bInCollection */ D0(72),D1(72), 2, +/* 8 baInterfaceNr(1) ... baInterfaceNr(n) */ 1, 2, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x02, +/* 8 iTerminal */ 0, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x05, +/* 8 iTerminal */ 0, +/* --------------------- Audio 1.0 AC INT Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x83, 0x03, +/* 4 wMaxPacketSize, bInterval */ D0(8),D1(8), 1, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x03, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 1, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x04, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 1, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { +/* --------------------------------------- Device Descriptor */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x01, 0x00, +/* 12 bcdDevice */ D0(0x100),D1(0x100), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* ----------------------------- Device Qualifier Descriptor */ +/* 0 bLength, bDescriptorType */ 10, 0x06, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 bNumConfigurations */ 1, +/* 9 bReserved */ 0, + +/* -------------------------------- Configuration Descriptor *//* 9+8+88+52*2=209 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(209),D1(209), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------ Interface Association Descriptor */ +/* 0 bLength, bDescriptorType */ 8, 0x0B, +/* 2 bFirstInterface, bInterfaceCount */ 0, 3, +/* 4 bFunctionClass, bFunctionSubClass, bFunctionProtocol */ 0x01, 0x01, 0x00, +/* 7 iFunction */ 0, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+72+7=88) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x00, +/* 8 iInterface */ 0, +/* ---------------- Audio 1.0 AC Interface Header Descriptor *//* (10+12*2+10*2+9*2=72) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x01, +/* 3 bcdADC */ 0x00, 0x01, +/* 5 wTotalLength, bInCollection */ D0(72),D1(72), 2, +/* 8 baInterfaceNr(1) ... baInterfaceNr(n) */ 1, 2, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x02, +/* 8 iTerminal */ 0, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x05, +/* 8 iTerminal */ 0, +/* --------------------- Audio 1.0 AC INT Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x83, 0x03, +/* 4 wMaxPacketSize, bInterval */ D0(8),D1(8), 4, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x03, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 4, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x04, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 4, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + +/* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + +/* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + +/* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; +static UX_TEST_SETUP _GetCfgDescr = UX_TEST_SETUP_GetCfgDescr; +static UX_TEST_SETUP _SetAddress = UX_TEST_SETUP_SetAddress; +static UX_TEST_SETUP _GetDeviceDescriptor = UX_TEST_SETUP_GetDevDescr; +static UX_TEST_SETUP _GetConfigDescriptor = UX_TEST_SETUP_GetCfgDescr; + +/* Interaction define */ + +/* Hooks define */ + +static VOID ux_device_class_audio_tx_hook(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *p = (UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *)params; +UX_SLAVE_TRANSFER *transfer = (UX_SLAVE_TRANSFER *)p -> parameter; +UCHAR tmp[32] = {'i','n','s','e','r','t','A',0}; + + + (void)params; + // printf("tTX\n"); + + /* Acknowledge frame sent. */ + if (test_tx_ack_count) + { + SAVE_BUFFER_LOG(transfer -> ux_slave_transfer_request_data_pointer, transfer -> ux_slave_transfer_request_requested_length); + transfer -> ux_slave_transfer_request_actual_length = transfer -> ux_slave_transfer_request_requested_length; + transfer -> ux_slave_transfer_request_completion_code = UX_SUCCESS; + _ux_utility_semaphore_put(&transfer -> ux_slave_transfer_request_semaphore); + } + if (test_tx_ack_count != 0xFFFFFFFF && test_tx_ack_count > 0) + test_tx_ack_count --; + + /* Insert frames when sent. */ + if (test_tx_ins_count) + { + tmp[6] = (test_tx_ins_count % 26) + 'A'; + if (test_tx_ins_way == 0) + ux_device_class_audio_frame_write(slave_audio_tx_stream, tmp, 32); + else + { + + UCHAR *frame; + ULONG frame_length; + + + ux_device_class_audio_write_frame_get(slave_audio_tx_stream, &frame, &frame_length); + _ux_utility_memory_copy(frame, tmp, 32); + ux_device_class_audio_write_frame_commit(slave_audio_tx_stream, 32); + } + } + if (test_tx_ins_count != 0xFFFFFFFF && test_tx_ins_count > 0) + test_tx_ins_count --; +} + +static VOID ux_device_class_audio_rx_hook(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *p = (UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *)params; +UX_SLAVE_TRANSFER *transfer = (UX_SLAVE_TRANSFER *)p -> parameter; + + + (void)action; + (void)params; + (void)p; + (void)transfer; + // printf("tRX\n"); + slave_audio_rx_transfer = transfer; +} +static VOID slave_audio_rx_simulate_one_frame(UCHAR *frame, ULONG frame_length) +{ + UX_TEST_ASSERT(slave_audio_rx_transfer); + if (frame_length) + { + _ux_utility_memory_copy(slave_audio_rx_transfer->ux_slave_transfer_request_data_pointer, frame, frame_length); + slave_audio_rx_transfer->ux_slave_transfer_request_actual_length = frame_length; + slave_audio_rx_transfer->ux_slave_transfer_request_completion_code = UX_SUCCESS; + } + _ux_utility_semaphore_put(&slave_audio_rx_transfer->ux_slave_transfer_request_semaphore); + _ux_utility_thread_sleep(1); +} + +static UX_TEST_ACTION ux_device_class_audio_transfer_hook[] = +{ + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .action_func = ux_device_class_audio_tx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x81, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .action_func = ux_device_class_audio_rx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x02, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, +{ 0 }, +}; + +static VOID ux_host_class_audio_tx_hook(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ +UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *p = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS*)params; +UX_TRANSFER *transfer = (UX_TRANSFER *)p->parameter; + SAVE_CALLBACK_INVOKE_LOG(ux_host_class_audio_tx_hook, transfer->ux_transfer_request_endpoint->ux_endpoint_descriptor.bEndpointAddress, transfer->ux_transfer_request_requested_length, 0); + // printf("hTxHook %lx %ld\n", transfer->ux_transfer_request_endpoint->ux_endpoint_descriptor.bEndpointAddress, transfer->ux_transfer_request_requested_length); + transfer->ux_transfer_request_actual_length=transfer->ux_transfer_request_requested_length; + transfer->ux_transfer_request_completion_code=UX_SUCCESS; + if (transfer->ux_transfer_request_completion_function) + transfer->ux_transfer_request_completion_function(transfer); +} + +static VOID ux_host_class_audio_rx_hook(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ +UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *p = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS*)params; +UX_TRANSFER *transfer = (UX_TRANSFER *)p->parameter; + SAVE_CALLBACK_INVOKE_LOG(ux_host_class_audio_rx_hook, transfer->ux_transfer_request_endpoint->ux_endpoint_descriptor.bEndpointAddress, transfer->ux_transfer_request_requested_length, 0); + // printf("hRxHook %lx %ld\n", transfer->ux_transfer_request_endpoint->ux_endpoint_descriptor.bEndpointAddress, transfer->ux_transfer_request_requested_length); + transfer->ux_transfer_request_actual_length=transfer->ux_transfer_request_requested_length; + transfer->ux_transfer_request_completion_code=UX_SUCCESS; + if (transfer->ux_transfer_request_completion_function) + transfer->ux_transfer_request_completion_function(transfer); +} + +static UX_TEST_ACTION ux_host_class_audio_transfer_hook[] = +{ + { + .usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + .function = UX_HCD_TRANSFER_REQUEST, + .action_func = ux_host_class_audio_tx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x02, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, + { + .usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + .function = UX_HCD_TRANSFER_REQUEST, + .action_func = ux_host_class_audio_rx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x81, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, +{0}, +}; +static UX_TEST_ACTION ux_host_class_audio_tx_action[] = +{ + { + .usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + .function = UX_HCD_TRANSFER_REQUEST, + .action_func = ux_host_class_audio_tx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x02, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, + { + .usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + .function = UX_HCD_TRANSFER_REQUEST, + .action_func = ux_host_class_audio_tx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x02, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, +{0}, +}; +static UX_TEST_ACTION ux_host_class_audio_rx_action[] = +{ + { + .usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + .function = UX_HCD_TRANSFER_REQUEST, + .action_func = ux_host_class_audio_rx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x81, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, + { + .usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + .function = UX_HCD_TRANSFER_REQUEST, + .action_func = ux_host_class_audio_rx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x81, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, +{0}, +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* 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 ++; + // printf("Error #%d, system_level: %d, system_context: %d, error_code: 0x%x\n", __LINE__, system_level, system_context, error_code); + + if (!error_callback_ignore) + { + { + /* Failed test. */ + 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 VOID slave_audio_activate(VOID *audio_instance) +{ + slave_audio = (UX_DEVICE_CLASS_AUDIO *)audio_instance; + ux_device_class_audio_stream_get(slave_audio, 0, &slave_audio_tx_stream); + ux_device_class_audio_stream_get(slave_audio, 1, &slave_audio_rx_stream); + // printf("sAUD:%p;%p,%p\n", audio_instance, slave_audio_tx_stream, slave_audio_rx_stream); +} +static VOID slave_audio_deactivate(VOID *audio_instance) +{ + if ((VOID *)slave_audio == audio_instance) + { + slave_audio = UX_NULL; + slave_audio_tx_stream = UX_NULL; + slave_audio_rx_stream = UX_NULL; + } +} +static VOID slave_audio_tx_stream_change(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG alt) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_tx_stream_change, audio, (ALIGN_TYPE)alt, 0); +} +static VOID slave_audio_rx_stream_change(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG alt) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_rx_stream_change, audio, (ALIGN_TYPE)alt, 0); + + slave_audio_rx_transfer = UX_NULL; +} +static UINT slave_audio_control_process(UX_DEVICE_CLASS_AUDIO *audio, UX_SLAVE_TRANSFER *transfer) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_control_process, audio, transfer, 0); + return(UX_ERROR); +} +static VOID slave_audio_tx_done(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG length) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_tx_done, audio, (ALIGN_TYPE)length, 0); +} +static VOID slave_audio_rx_done(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG length) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_rx_done, audio, (ALIGN_TYPE)length, 0); +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_AUDIO *audio = (UX_HOST_CLASS_AUDIO *) inst; + + + switch(event) + { + + case UX_DEVICE_INSERTION: + + // printf("hINS:%p,%p:%lx\n", cls, inst, ux_host_class_audio_type_get(audio)); +#if defined(UX_HOST_CLASS_AUDIO_INTERRUPT_SUPPORT) + if (ux_host_class_audio_subclass_get(audio) == UX_HOST_CLASS_AUDIO_SUBCLASS_CONTROL) + host_audio_ac = (UX_HOST_CLASS_AUDIO_AC *)inst; + else +#endif + { + if (ux_host_class_audio_type_get(audio) == UX_HOST_CLASS_AUDIO_INPUT) + host_audio_rx = audio; + else + host_audio_tx = audio; + } + break; + + case UX_DEVICE_REMOVAL: + + // printf("hRMV:%p,%p:%lx\n", cls, inst, ux_host_class_audio_type_get(audio)); +#if defined(UX_HOST_CLASS_AUDIO_INTERRUPT_SUPPORT) + if (ux_host_class_audio_subclass_get(audio) == UX_HOST_CLASS_AUDIO_SUBCLASS_CONTROL) + { + if ((VOID*)host_audio_ac == inst) + host_audio_ac = UX_NULL; + } + else +#endif + { + if (audio == host_audio_rx) + host_audio_rx = UX_NULL; + if (audio == host_audio_tx) + host_audio_tx = UX_NULL; + } + break; + + default: + break; + } + return 0; +} + + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_mem_free_on_set_cfg = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_audio10_iad_device_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + #if !UX_TEST_MULTI_IFC_ON || !UX_TEST_MULTI_ALT_ON || !UX_TEST_MULTI_CLS_ON + printf("Running Audio 1.0 Device Basic Functionality Test...............SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + + printf("Running Audio 1.0 IAD Host Basic Functionality Test................. "); + + stepinfo("\n"); + + /* 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(); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* 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_host_change_function); + UX_TEST_CHECK_SUCCESS(status); + + /* Register Audio class. */ + status = ux_host_stack_class_register(_ux_system_host_class_audio_name, ux_host_class_audio_entry); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Set the parameters for callback when insertion/extraction of a Audio 1.0 device, no IAD. */ + ux_utility_memory_set(&slave_audio_parameter, 0, sizeof(slave_audio_parameter)); + ux_utility_memory_set(slave_audio_stream_parameter, 0, sizeof(slave_audio_stream_parameter)); + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_thread_entry = ux_device_class_audio_write_thread_entry; + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_change = slave_audio_tx_stream_change; + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_frame_done = slave_audio_tx_done; + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_max_frame_buffer_size = 256; + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_max_frame_buffer_nb = 8; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_thread_entry = ux_device_class_audio_read_thread_entry; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_change = slave_audio_rx_stream_change; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_frame_done = slave_audio_rx_done; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_max_frame_buffer_size = 256; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_max_frame_buffer_nb = 8; + slave_audio_parameter.ux_device_class_audio_parameter_streams = slave_audio_stream_parameter; + slave_audio_parameter.ux_device_class_audio_parameter_streams_nb = 2; + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_slave_class_audio_instance_activate = slave_audio_activate; + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_slave_class_audio_instance_deactivate = slave_audio_deactivate; + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_device_class_audio_control_process = slave_audio_control_process; + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_device_class_audio_arg = UX_NULL; + +#if defined(UX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT) + slave_audio_parameter.ux_device_class_audio_parameter_status_queue_size = 2; + slave_audio_parameter.ux_device_class_audio_parameter_status_size = 6; +#endif + +#if 0 + printf("Memory requirement UX_HOST_CLASS_:\n"); + printf(" per _AUDIO: %d bytes\n", sizeof(UX_HOST_CLASS_AUDIO)); + printf(" per _AUDIO_TRANSFER_REQUEST: %d bytes\n", sizeof(UX_HOST_CLASS_AUDIO_TRANSFER_REQUEST)); + printf(" per _AUDIO_CONTROL: %d bytes\n", sizeof(UX_HOST_CLASS_AUDIO_CONTROL)); + printf(" per _AUDIO_SAMPLING: %d bytes\n", sizeof(UX_HOST_CLASS_AUDIO_SAMPLING)); + printf(" per _AUDIO_SAMPLING_ATTR: %d bytes\n", sizeof(UX_HOST_CLASS_AUDIO_SAMPLING_CHARACTERISTICS)); +#endif + + /* Initialize the device Audio class. This class owns interfaces starting with 1, 2. */ + status = ux_device_stack_class_register(_ux_system_slave_class_audio_name, ux_device_class_audio_entry, + 1, 0, &slave_audio_parameter); + UX_TEST_CHECK_SUCCESS(status); + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx demo host simulation", tx_test_thread_host_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx demo slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_CHECK_SUCCESS(status); +} + +static UINT test_wait_until_expected(VOID **ptr, ULONG loop, VOID *expected) +{ + while(loop) + { + _ux_utility_delay_ms(10); + if (*ptr == expected) + return UX_SUCCESS; + } + return UX_ERROR; +} +static UINT test_wait_until_not_expected(VOID **ptr, ULONG loop, VOID *expected) +{ + while(loop) + { + _ux_utility_delay_ms(10); + if (*ptr != expected) + return UX_SUCCESS; + } + return UX_ERROR; +} +#define test_wait_until_not_null(ptr, loop) test_wait_until_not_expected(ptr, loop, UX_NULL) +#define test_wait_until_null(ptr, loop) test_wait_until_expected(ptr, loop, UX_NULL) + +static void _memory_tests(void) +{ +ULONG test_n; +ULONG mem_free; + + /* Test disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Reset testing counts. */ + ux_test_utility_sim_mutex_create_count_reset(); + ux_test_utility_sim_sem_create_count_reset(); + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + /* Save free memory usage. */ + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + tx_thread_sleep(100); + /* Log create counts for further tests. */ + rsc_enum_mutex_usage = rsc_mutex_on_set_cfg; + rsc_enum_sem_usage = rsc_sem_on_set_cfg; + rsc_enum_mem_usage = mem_free - rsc_mem_free_on_set_cfg; + rsc_enum_mem_alloc_count = rsc_mem_alloc_cnt_on_set_cfg; + /* Log create counts when instances active for further tests. */ + rsc_audio_mutex_usage = ux_test_utility_sim_mutex_create_count() - rsc_enum_mutex_usage; + rsc_audio_sem_usage = ux_test_utility_sim_sem_create_count() - rsc_enum_sem_usage; + rsc_audio_mem_usage = rsc_mem_free_on_set_cfg - _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + rsc_audio_mem_alloc_count = ux_test_utility_sim_mem_alloc_count() - rsc_enum_mem_alloc_count; + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + + /* Lock log base for tests. */ + ux_test_utility_sim_mem_alloc_log_lock(); + + stepinfo("enum mem: %ld\n", rsc_enum_mem_alloc_count); + stepinfo("cdc mem : %ld\n", rsc_audio_mem_alloc_count); + stepinfo("mem free: %ld, %ld\n", _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); + + /* Simulate detach and attach for FS enumeration, + and check if there is memory error in normal enumeration. + */ + stepinfo(">>>>>>>>>>>> Enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < 3; test_n++) + { + stepinfo("%4ld / 2\n", test_n); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #11.%ld: Memory level different after re-enumerations %ld <> %ld\n", test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on error. */ + ux_test_breakable_sleep(100, sleep_break_on_error); + + /* Check */ + if (!host_audio_tx || !host_audio_rx) + { + + printf("ERROR #12.%ld: Enumeration fail\n", test_n); + test_control_return(1); + } + } + + /* Simulate detach and attach for FS enumeration, + and test possible memory allocation error handlings. + */ + if (rsc_audio_mem_alloc_count) stepinfo(">>>>>>>>>>>> Memory errors enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_audio_mem_alloc_count; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_audio_mem_alloc_count - 1); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #11.%ld: Memory level different after re-enumerations %ld <> %ld\n", test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Set memory error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n + rsc_enum_mem_alloc_count); + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on errors. */ + ux_test_breakable_sleep(100, sleep_break_on_error); + + /* Check error */ + if (host_audio_tx && host_audio_rx) + { + + printf("ERROR #12.%ld: device detected when there is memory error\n", test_n); + test_control_return(1); + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + } + ux_test_utility_sim_mem_alloc_error_generation_stop(); + if (rsc_audio_mem_alloc_count) stepinfo("\n"); +} + +static void _feature_control_tests(void) +{ +UX_HOST_CLASS_AUDIO_CONTROL audio_control; +UINT status; + +#if !defined(UX_HOST_CLASS_AUDIO_DISABLE_CONTROLS) + RESET_CALLBACK_INVOKE_LOG(); + + audio_control.ux_host_class_audio_control_channel = 1; + audio_control.ux_host_class_audio_control = UX_HOST_CLASS_AUDIO_VOLUME_CONTROL; + status = ux_host_class_audio_control_get(host_audio_tx, &audio_control); + // UX_TEST_ASSERT(status == UX_TRANSFER_STALLED); + UX_TEST_ASSERT(callback_invoke_count == 1); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_control_process); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream->ux_device_class_audio_stream_audio); + + audio_control.ux_host_class_audio_control_channel = 1; + audio_control.ux_host_class_audio_control = UX_HOST_CLASS_AUDIO_VOLUME_CONTROL; + audio_control.ux_host_class_audio_control_cur = 0xfff0; + status = ux_host_class_audio_control_value_set(host_audio_tx, &audio_control); + // UX_TEST_ASSERT(status == UX_TRANSFER_STALLED); + UX_TEST_ASSERT(callback_invoke_count == 2); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_control_process); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_rx_stream->ux_device_class_audio_stream_audio); + + audio_control.ux_host_class_audio_control_channel = 2; + audio_control.ux_host_class_audio_control = UX_HOST_CLASS_AUDIO_VOLUME_CONTROL; + status = ux_host_class_audio_control_get(host_audio_tx, &audio_control); + // UX_TEST_ASSERT(status == UX_TRANSFER_STALLED); + UX_TEST_ASSERT(callback_invoke_count == 3); + UX_TEST_ASSERT(callback_invoke_log[2].func == slave_audio_control_process); + UX_TEST_ASSERT(callback_invoke_log[2].param1 == slave_audio_rx_stream->ux_device_class_audio_stream_audio); + + audio_control.ux_host_class_audio_control_channel = 2; + audio_control.ux_host_class_audio_control = UX_HOST_CLASS_AUDIO_VOLUME_CONTROL; + audio_control.ux_host_class_audio_control_cur = 0xfff0; + status = ux_host_class_audio_control_value_set(host_audio_tx, &audio_control); + // UX_TEST_ASSERT(status == UX_TRANSFER_STALLED); + UX_TEST_ASSERT(callback_invoke_count == 4); + UX_TEST_ASSERT(callback_invoke_log[3].func == slave_audio_control_process); + UX_TEST_ASSERT(callback_invoke_log[3].param1 == slave_audio_rx_stream->ux_device_class_audio_stream_audio); +#endif + + RESET_CALLBACK_INVOKE_LOG(); + + audio_control.ux_host_class_audio_control_entity = 0x05; + audio_control.ux_host_class_audio_control_size = 2; + audio_control.ux_host_class_audio_control = UX_HOST_CLASS_AUDIO_VOLUME_CONTROL; + + audio_control.ux_host_class_audio_control_channel = 1; + status = ux_host_class_audio_entity_control_get(host_audio_tx, &audio_control); + UX_TEST_ASSERT(callback_invoke_count == 1); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_control_process); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream->ux_device_class_audio_stream_audio); + + audio_control.ux_host_class_audio_control_cur = 0xfff0; + status = ux_host_class_audio_entity_control_value_set(host_audio_tx, &audio_control); + UX_TEST_ASSERT(callback_invoke_count == 2); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_control_process); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_rx_stream->ux_device_class_audio_stream_audio); + + audio_control.ux_host_class_audio_control_channel = 2; + status = ux_host_class_audio_entity_control_get(host_audio_tx, &audio_control); + UX_TEST_ASSERT(callback_invoke_count == 3); + UX_TEST_ASSERT(callback_invoke_log[2].func == slave_audio_control_process); + UX_TEST_ASSERT(callback_invoke_log[2].param1 == slave_audio_rx_stream->ux_device_class_audio_stream_audio); + + audio_control.ux_host_class_audio_control_cur = 0xfff0; + status = ux_host_class_audio_entity_control_value_set(host_audio_tx, &audio_control); + UX_TEST_ASSERT(callback_invoke_count == 4); + UX_TEST_ASSERT(callback_invoke_log[3].func == slave_audio_control_process); + UX_TEST_ASSERT(callback_invoke_log[3].param1 == slave_audio_rx_stream->ux_device_class_audio_stream_audio); + +} + +static void _sampling_control_tests(void) +{ +UINT status; +UX_HOST_CLASS_AUDIO_SAMPLING sampling; + + RESET_CALLBACK_INVOKE_LOG(); + + sampling.ux_host_class_audio_sampling_channels = 2; + sampling.ux_host_class_audio_sampling_frequency = 44100; + sampling.ux_host_class_audio_sampling_resolution = 16; + status = ux_host_class_audio_streaming_sampling_set(host_audio_tx, &sampling); + UX_TEST_CHECK_NOT_SUCCESS(status); + + sampling.ux_host_class_audio_sampling_channels = 4; + sampling.ux_host_class_audio_sampling_frequency = 48000; + sampling.ux_host_class_audio_sampling_resolution = 16; + status = ux_host_class_audio_streaming_sampling_set(host_audio_tx, &sampling); + UX_TEST_CHECK_NOT_SUCCESS(status); + + sampling.ux_host_class_audio_sampling_channels = 2; + sampling.ux_host_class_audio_sampling_frequency = 48000; + sampling.ux_host_class_audio_sampling_resolution = 32; + status = ux_host_class_audio_streaming_sampling_set(host_audio_tx, &sampling); + UX_TEST_CHECK_NOT_SUCCESS(status); + + sampling.ux_host_class_audio_sampling_channels = 2; + sampling.ux_host_class_audio_sampling_frequency = 48000; + sampling.ux_host_class_audio_sampling_resolution = 16; + status = ux_host_class_audio_streaming_sampling_set(host_audio_tx, &sampling); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(callback_invoke_count == 1); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_rx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(ux_host_class_audio_max_packet_size_get(host_audio_tx) == 256); + UX_TEST_ASSERT(host_audio_tx->ux_host_class_audio_packet_fraction == 0); + UX_TEST_ASSERT(host_audio_tx->ux_host_class_audio_packet_freq == 1000); + UX_TEST_ASSERT(host_audio_tx->ux_host_class_audio_packet_size == 192); + + sampling.ux_host_class_audio_sampling_channels = 2; + sampling.ux_host_class_audio_sampling_frequency = 48000; + sampling.ux_host_class_audio_sampling_resolution = 16; + status = ux_host_class_audio_streaming_sampling_set(host_audio_rx, &sampling); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(callback_invoke_count == 2); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_tx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_tx_stream); + UX_TEST_ASSERT(ux_host_class_audio_max_packet_size_get(host_audio_rx) == 256); + UX_TEST_ASSERT(host_audio_rx->ux_host_class_audio_packet_fraction == 0); + UX_TEST_ASSERT(host_audio_rx->ux_host_class_audio_packet_freq == 1000); + UX_TEST_ASSERT(host_audio_rx->ux_host_class_audio_packet_size == 192); +} + +static void _audio_request_completion(UX_HOST_CLASS_AUDIO_TRANSFER_REQUEST *transfer) +{ + UX_PARAMETER_NOT_USED(transfer); + SAVE_CALLBACK_INVOKE_LOG(_audio_request_completion, transfer, 0, 0); +} +static void _audio_requests_tests(void) +{ +UINT status; + + // ux_test_link_hooks_from_array(ux_host_class_audio_transfer_hook); + RESET_CALLBACK_INVOKE_LOG(); + + /* Prepare the 2 audio transfer_requests */ + audio_transfer1.ux_host_class_audio_transfer_request_completion_function = _audio_request_completion; + audio_transfer2.ux_host_class_audio_transfer_request_completion_function = _audio_request_completion; + audio_transfer1.ux_host_class_audio_transfer_request_class_instance = host_audio_tx; + audio_transfer2.ux_host_class_audio_transfer_request_class_instance = host_audio_tx; + audio_transfer1.ux_host_class_audio_transfer_request_next_audio_transfer_request = &audio_transfer1; + audio_transfer2.ux_host_class_audio_transfer_request_next_audio_transfer_request = UX_NULL; + + audio_transfer1.ux_host_class_audio_transfer_request_data_pointer = host_audio_buffer[0]; + audio_transfer1.ux_host_class_audio_transfer_request_requested_length = sizeof(host_audio_buffer[0]); + audio_transfer1.ux_host_class_audio_transfer_request.ux_transfer_request_packet_length = 192; + + audio_transfer2.ux_host_class_audio_transfer_request_data_pointer = host_audio_buffer[1]; + audio_transfer2.ux_host_class_audio_transfer_request_requested_length = sizeof(host_audio_buffer[1]); + audio_transfer2.ux_host_class_audio_transfer_request.ux_transfer_request_packet_length = 192; + + ux_test_set_main_action_list_from_array(ux_host_class_audio_tx_action); + + status = ux_host_class_audio_write(host_audio_tx, &audio_transfer1); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(callback_invoke_count == 2); + UX_TEST_ASSERT(callback_invoke_log[0].func == ux_host_class_audio_tx_hook); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == (void*)0x02); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (void*)sizeof(host_audio_buffer[0])); + UX_TEST_ASSERT(callback_invoke_log[1].func == _audio_request_completion); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == &audio_transfer1); + + status = ux_host_class_audio_write(host_audio_tx, &audio_transfer2); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(callback_invoke_count == 4); + UX_TEST_ASSERT(callback_invoke_log[2].func == ux_host_class_audio_tx_hook); + UX_TEST_ASSERT(callback_invoke_log[2].param1 == (void*)0x02); + UX_TEST_ASSERT(callback_invoke_log[2].param2 == (void*)sizeof(host_audio_buffer[1])); + UX_TEST_ASSERT(callback_invoke_log[3].func == _audio_request_completion); + UX_TEST_ASSERT(callback_invoke_log[3].param1 == &audio_transfer2); + + ux_test_set_main_action_list_from_array(ux_host_class_audio_rx_action); + + status = ux_host_class_audio_read(host_audio_rx, &audio_transfer1); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(callback_invoke_count == 6); + UX_TEST_ASSERT(callback_invoke_log[4].func == ux_host_class_audio_rx_hook); + UX_TEST_ASSERT(callback_invoke_log[4].param1 == (void*)0x81); + UX_TEST_ASSERT(callback_invoke_log[4].param2 == (void*)256); + UX_TEST_ASSERT(callback_invoke_log[5].func == _audio_request_completion); + UX_TEST_ASSERT(callback_invoke_log[5].param1 == &audio_transfer1); + + status = ux_host_class_audio_read(host_audio_rx, &audio_transfer2); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(callback_invoke_count == 8); + UX_TEST_ASSERT(callback_invoke_log[6].func == ux_host_class_audio_rx_hook); + UX_TEST_ASSERT(callback_invoke_log[6].param1 == (void*)0x81); + UX_TEST_ASSERT(callback_invoke_log[6].param2 == (void*)256); + UX_TEST_ASSERT(callback_invoke_log[7].func == _audio_request_completion); + UX_TEST_ASSERT(callback_invoke_log[7].param1 == &audio_transfer2); +} + +#if defined(UX_HOST_CLASS_AUDIO_INTERRUPT_SUPPORT) +#define DEMO_AUDIO_INTERRUPT_ARG (VOID*)(100) +static VOID demo_audio_interrupt_callback(UX_HOST_CLASS_AUDIO_AC *ac, + UCHAR *message, ULONG length, + VOID *arg) +{ + UX_TEST_ASSERT(arg == DEMO_AUDIO_INTERRUPT_ARG); + UX_TEST_ASSERT(length > 0 && length < 8); + /* Save message. */ + ux_utility_memory_copy(demo_host_interrupt_msg, message, length); + demo_host_interrupt_len = length; +} +static void _audio_interrupt_tests(void) +{ +UINT status; +UX_SLAVE_INTERFACE *device_ifc; +UX_SLAVE_ENDPOINT *device_ep; +UX_SLAVE_TRANSFER *device_tr; +ULONG test_n; + status = ux_host_class_audio_interrupt_start(host_audio_ac, demo_audio_interrupt_callback, DEMO_AUDIO_INTERRUPT_ARG); + UX_TEST_CHECK_SUCCESS(status); + /* Issue a message from device side. */ + UX_TEST_ASSERT(slave_audio != UX_NULL); + device_ifc = slave_audio -> ux_device_class_audio_interface; + UX_TEST_ASSERT(device_ifc != UX_NULL); + device_ep = device_ifc -> ux_slave_interface_first_endpoint; + UX_TEST_ASSERT(device_ep != UX_NULL); + device_tr = &device_ep -> ux_slave_endpoint_transfer_request; + device_tr -> ux_slave_transfer_request_timeout = 100; + for (test_n = 1; test_n < 7; test_n ++) + { + ux_utility_memory_set(demo_device_interrupt_msg, (test_n % 10) + '0', test_n); + demo_device_interrupt_len = test_n; + + ux_utility_memory_copy(device_tr->ux_slave_transfer_request_data_pointer, demo_device_interrupt_msg, demo_device_interrupt_len); + status = ux_device_stack_transfer_request(device_tr, demo_device_interrupt_len, demo_device_interrupt_len); + UX_TEST_CHECK_SUCCESS(status); + + /* Wait a while. */ + tx_thread_sleep(1); + + UX_TEST_ASSERT(demo_device_interrupt_len == demo_host_interrupt_len); + status = ux_utility_memory_compare(demo_device_interrupt_msg, demo_host_interrupt_msg, demo_device_interrupt_len); + UX_TEST_CHECK_SUCCESS(status); + } +} +#endif + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +UCHAR test_cmp[32]; +ULONG temp; + + + /* Test connect. */ + status = test_wait_until_not_null((void**)&host_audio_rx, 100); + status |= test_wait_until_not_null((void**)&host_audio_tx, 100); +#if defined(UX_HOST_CLASS_AUDIO_INTERRUPT_SUPPORT) + status |= test_wait_until_not_null((void**)&host_audio_ac, 100); +#endif + status |= test_wait_until_not_null((void**)&slave_audio_tx_stream, 100); + status |= test_wait_until_not_null((void**)&slave_audio_rx_stream, 100); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(ux_host_class_audio_protocol_get(host_audio_rx) == UX_HOST_CLASS_AUDIO_PROTOCOL_IP_VERSION_01_00); + UX_TEST_ASSERT(ux_host_class_audio_type_get(host_audio_rx) == UX_HOST_CLASS_AUDIO_INPUT); + UX_TEST_ASSERT(ux_host_class_audio_speed_get(host_audio_rx) == UX_FULL_SPEED_DEVICE); + + /* Check enumeration information. */ + UX_TEST_ASSERT(host_audio_rx->ux_host_class_audio_control_interface_number == 0); + UX_TEST_ASSERT(host_audio_rx->ux_host_class_audio_streaming_interface->ux_interface_descriptor.bInterfaceNumber == 1); + UX_TEST_ASSERT(host_audio_tx->ux_host_class_audio_control_interface_number == 0); + UX_TEST_ASSERT(host_audio_tx->ux_host_class_audio_streaming_interface->ux_interface_descriptor.bInterfaceNumber == 2); + + _memory_tests(); + + _feature_control_tests(); + + _sampling_control_tests(); + + _audio_requests_tests(); + +#if defined(UX_HOST_CLASS_AUDIO_INTERRUPT_SUPPORT) + _audio_interrupt_tests(); +#endif + + /* Wait pending threads. */ + _ux_utility_thread_sleep(1); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + ux_device_stack_class_unregister(_ux_system_slave_class_audio_name, ux_device_class_audio_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + while(1) + { + + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); + } +} diff --git a/test/regression/usbx_audio20_device_basic_test.c b/test/regression/usbx_audio20_device_basic_test.c new file mode 100644 index 00000000..202a0daa --- /dev/null +++ b/test/regression/usbx_audio20_device_basic_test.c @@ -0,0 +1,1397 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" + +#include "fx_api.h" + +#include "ux_device_class_audio.h" +#include "ux_device_class_audio20.h" +#include "ux_device_stack.h" + +#include "ux_host_class_audio.h" +#include "ux_host_class_dummy.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_DEMO_REQUEST_MAX_LENGTH \ + ((UX_HCD_SIM_HOST_MAX_PAYLOAD) > (UX_SLAVE_REQUEST_DATA_MAX_LENGTH) ? \ + (UX_HCD_SIM_HOST_MAX_PAYLOAD) : (UX_SLAVE_REQUEST_DATA_MAX_LENGTH)) + +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_DEMO_REQUEST_MAX_LENGTH + 1) +#define UX_DEMO_MEMORY_SIZE (128*1024) + +#define UX_TEST_LOG_SIZE (64) + + +/* Define local/extern function prototypes. */ +static void test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static void tx_test_thread_host_simulation_entry(ULONG); +static void tx_test_thread_slave_simulation_entry(ULONG); + + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[64]; + +static UX_HOST_CLASS_DUMMY *dummy_control; +static UX_HOST_CLASS_DUMMY *dummy_tx; +static UX_HOST_CLASS_DUMMY *dummy_rx; + +static UX_DEVICE_CLASS_AUDIO *slave_audio; +static UX_DEVICE_CLASS_AUDIO_PARAMETER slave_audio_parameter; +static UX_DEVICE_CLASS_AUDIO_STREAM_PARAMETER slave_audio_stream_parameter[2]; + +static UX_DEVICE_CLASS_AUDIO_STREAM *slave_audio_tx_stream; + +static UX_DEVICE_CLASS_AUDIO_STREAM *slave_audio_rx_stream; +static UX_SLAVE_TRANSFER *slave_audio_rx_transfer; + +static UX_HOST_CLASS_AUDIO *audio; + +static UX_DEVICE_CLASS_AUDIO20_CONTROL g_slave_audio20_control[2]; + +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_audio_sem_usage; +static ULONG rsc_audio_sem_get_count; +static ULONG rsc_audio_mutex_usage; +static ULONG rsc_audio_mem_usage; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +static struct BUFFER_LOG_STRUCT { + ULONG length; + UCHAR data[256]; +} buffer_log[UX_TEST_LOG_SIZE]; +static ULONG buffer_log_count = 0; +#define SAVE_BUFFER_LOG(buf,siz) do { \ + if (buffer_log_count < UX_TEST_LOG_SIZE) { \ + ULONG __local_size__ = ((siz) > 256) ? 256 : (siz); \ + buffer_log[buffer_log_count].length = (siz); \ + _ux_utility_memory_copy(buffer_log[buffer_log_count].data, (buf), __local_size__); \ + } \ + buffer_log_count ++; \ +} while(0) + +static ULONG test_tx_ack_count = 0xFFFFFFFF; +static ULONG test_tx_ins_count = 0; +static ULONG test_tx_ins_way = 0; + +static struct CALLBACK_INVOKE_LOG_STRUCT { + VOID *func; + VOID *param1; + VOID *param2; + VOID *param3; +} callback_invoke_log[UX_TEST_LOG_SIZE]; +static ULONG callback_invoke_count = 0; + +#define SAVE_CALLBACK_INVOKE_LOG(f,p1,p2,p3) do { \ + if (callback_invoke_count < UX_TEST_LOG_SIZE) { \ + callback_invoke_log[callback_invoke_count].func = (VOID *)(f); \ + callback_invoke_log[callback_invoke_count].param1 = (VOID *)(p1); \ + callback_invoke_log[callback_invoke_count].param2 = (VOID *)(p2); \ + callback_invoke_log[callback_invoke_count].param3 = (VOID *)(p3); \ + callback_invoke_count++; \ + } \ +} while(0) +#define RESET_CALLBACK_INVOKE_LOG() do { \ + callback_invoke_count = 0; \ +} while(0) + +/* Define device framework. */ + +#define D3(d) ((UCHAR)((d) >> 24)) +#define D2(d) ((UCHAR)((d) >> 16)) +#define D1(d) ((UCHAR)((d) >> 8)) +#define D0(d) ((UCHAR)((d) >> 0)) + +static unsigned char device_framework_full_speed[] = { + +/* --------------------------------------- Device Descriptor */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x02, 0x00, +/* 12 bcdDevice */ D0(0x200),D1(0x200), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* ----------------------------- Device Qualifier Descriptor */ +/* 0 bLength, bDescriptorType */ 10, 0x06, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 bNumConfigurations */ 1, +/* 9 bReserved */ 0, + +/* -------------------------------- Configuration Descriptor *//* 9+8+120+55*2=247 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(247),D1(247), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------ Interface Association Descriptor */ +/* 0 bLength, bDescriptorType */ 8, 0x0B, +/* 2 bFirstInterface, bInterfaceCount */ 0, 3, +/* 4 bFunctionClass, bFunctionSubClass, bFunctionProtocol */ 0x01, 0x00, 0x20, +/* 7 iFunction */ 0, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+111=120) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x20, +/* 8 iInterface */ 0, +/* ---------------- Audio 2.0 AC Interface Header Descriptor *//* (9+8+17*2+18*2+12*2=111) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x01, +/* 3 bcdADC, bCategory */ D0(0x200),D1(0x200), 0x08, +/* 6 wTotalLength */ D0(111),D1(111), +/* 8 bmControls */ 0x00, +/* -------------------- Audio 2.0 AC Clock Source Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x24, 0x0A, +/* 3 bClockID, bmAttributes, bmControls */ 0x10, 0x05, 0x01, +/* 6 bAssocTerminal, iClockSource */ 0x00, 0, +/* ------------------- Audio 2.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 17, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, bCSourceID */ 0x00, 0x10, +/* 8 bNrChannels, bmChannelConfig */ 0x02, D0(0),D1(0),D2(0),D3(0), +/* 13 iChannelNames, bmControls, iTerminal */ 0, D0(0),D1(0), 0, +/* --------------------- Audio 2.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 18, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bmaControls(0), bmaControls(...) ... */ D0(0xF),D1(0xF),D2(0xF),D3(0xF), D0(0),D1(0),D2(0),D3(0), D0(0),D1(0),D2(0),D3(0), +/* . iFeature */ 0, +/* ------------------ Audio 2.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID, bCSourceID */ 0x00, 0x02, 0x10, +/* 9 bmControls, iTerminal */ D0(0),D1(0), 0, +/* ------------------- Audio 2.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 17, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bCSourceID */ 0x00, 0x10, +/* 8 bNrChannels, bmChannelConfig */ 0x02, D0(0),D1(0),D2(0),D3(0), +/* 13 iChannelNames, bmControls, iTerminal */ 0, D0(0),D1(0), 0, +/* --------------------- Audio 2.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 18, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bmaControls(0), bmaControls(...) ... */ D0(0xF),D1(0xF),D2(0xF),D3(0xF), D0(0),D1(0),D2(0),D3(0), D0(0),D1(0),D2(0),D3(0), +/* . iFeature */ 0, +/* ------------------ Audio 2.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID, bCSourceID */ 0x00, 0x05, 0x10, +/* 9 bmControls, iTerminal */ D0(0),D1(0), 0, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+16+6+7+8=55) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------ Audio 2.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 16, 0x24, 0x01, +/* 3 bTerminalLink, bmControls */ 0x03,0x00, +/* 5 bFormatType, bmFormats */ 0x01,D0(1),D1(1),D2(1),D3(1), +/* 10 bNrChannels, bmChannelConfig */ 2, D0(0),D1(0),D2(0),D3(0), +/* 15 iChannelNames */ 0, +/* -------------------- Audio 2.0 AS Format Type I Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 6, 0x24, 0x02, +/* 3 bFormatType, bSubslotSize, bBitResolution */ 0x01, 2, 16, +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x0D, +/* 4 wMaxPacketSize, bInterval */ D0(256),D1(256), 1, +/* ---------- Audio 2.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x25, 0x01, +/* 3 bmAttributes, bmControls */ 0x00, 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+16+6+7+8=55) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------ Audio 2.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 16, 0x24, 0x01, +/* 3 bTerminalLink, bmControls */ 0x04,0x00, +/* 5 bFormatType, bmFormats */ 0x01,D0(1),D1(1),D2(1),D3(1), +/* 10 bNrChannels, bmChannelConfig */ 2, D0(0),D1(0),D2(0),D3(0), +/* 15 iChannelNames */ 0, +/* ---------------------- Audio 2.0 AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 6, 0x24, 0x02, +/* 3 bFormatType, bSubslotSize, bBitResolution */ 0x01, 2, 16, +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x0D, +/* 4 wMaxPacketSize, bInterval */ D0(256),D1(256), 1, +/* ---------- Audio 2.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x25, 0x01, +/* 3 bmAttributes, bmControls */ 0x00, 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), + +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { +/* --------------------------------------- Device Descriptor */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 0x08, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x02, 0x00, +/* 12 bcdDevice */ D0(0x200),D1(0x200), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* ----------------------------- Device Qualifier Descriptor */ +/* 0 bLength, bDescriptorType */ 10, 0x06, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 bNumConfigurations */ 1, +/* 9 bReserved */ 0, + +/* -------------------------------- Configuration Descriptor *//* 9+8+120+55*2=247 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(247),D1(247), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------ Interface Association Descriptor */ +/* 0 bLength, bDescriptorType */ 8, 0x0B, +/* 2 bFirstInterface, bInterfaceCount */ 0, 3, +/* 4 bFunctionClass, bFunctionSubClass, bFunctionProtocol */ 0x01, 0x00, 0x20, +/* 7 iFunction */ 0, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+111=120) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x20, +/* 8 iInterface */ 0, +/* ---------------- Audio 2.0 AC Interface Header Descriptor *//* (9+8+17*2+18*2+12*2=111) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x01, +/* 3 bcdADC, bCategory */ D0(0x200),D1(0x200), 0x08, +/* 6 wTotalLength */ D0(111),D1(111), +/* 8 bmControls */ 0x00, +/* -------------------- Audio 2.0 AC Clock Source Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x24, 0x0A, +/* 3 bClockID, bmAttributes, bmControls */ 0x10, 0x05, 0x01, +/* 6 bAssocTerminal, iClockSource */ 0x00, 0, +/* ------------------- Audio 2.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 17, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, bCSourceID */ 0x00, 0x10, +/* 8 bNrChannels, bmChannelConfig */ 0x02, D0(0),D1(0),D2(0),D3(0), +/* 13 iChannelNames, bmControls, iTerminal */ 0, D0(0),D1(0), 0, +/* --------------------- Audio 2.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 18, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bmaControls(0), bmaControls(...) ... */ D0(0xF),D1(0xF),D2(0xF),D3(0xF), D0(0),D1(0),D2(0),D3(0), D0(0),D1(0),D2(0),D3(0), +/* . iFeature */ 0, +/* ------------------ Audio 2.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID, bCSourceID */ 0x00, 0x02, 0x10, +/* 9 bmControls, iTerminal */ D0(0),D1(0), 0, +/* ------------------- Audio 2.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 17, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bCSourceID */ 0x00, 0x10, +/* 8 bNrChannels, bmChannelConfig */ 0x02, D0(0),D1(0),D2(0),D3(0), +/* 13 iChannelNames, bmControls, iTerminal */ 0, D0(0),D1(0), 0, +/* --------------------- Audio 2.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 18, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bmaControls(0), bmaControls(...) ... */ D0(0xF),D1(0xF),D2(0xF),D3(0xF), D0(0),D1(0),D2(0),D3(0), D0(0),D1(0),D2(0),D3(0), +/* . iFeature */ 0, +/* ------------------ Audio 2.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID, bCSourceID */ 0x00, 0x05, 0x10, +/* 9 bmControls, iTerminal */ D0(0),D1(0), 0, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+16+6+7+8=55) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------ Audio 2.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 16, 0x24, 0x01, +/* 3 bTerminalLink, bmControls */ 0x03,0x00, +/* 5 bFormatType, bmFormats */ 0x01,D0(1),D1(1),D2(1),D3(1), +/* 10 bNrChannels, bmChannelConfig */ 2, D0(0),D1(0),D2(0),D3(0), +/* 15 iChannelNames */ 0, +/* -------------------- Audio 2.0 AS Format Type I Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 6, 0x24, 0x02, +/* 3 bFormatType, bSubslotSize, bBitResolution */ 0x01, 2, 16, +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x0D, +/* 4 wMaxPacketSize, bInterval */ D0(256),D1(256), 4, +/* ---------- Audio 2.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x25, 0x01, +/* 3 bmAttributes, bmControls */ 0x00, 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+16+6+7+8=55) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------ Audio 2.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 16, 0x24, 0x01, +/* 3 bTerminalLink, bmControls */ 0x04,0x00, +/* 5 bFormatType, bmFormats */ 0x01,D0(1),D1(1),D2(1),D3(1), +/* 10 bNrChannels, bmChannelConfig */ 2, D0(0),D1(0),D2(0),D3(0), +/* 15 iChannelNames */ 0, +/* ---------------------- Audio 2.0 AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 6, 0x24, 0x02, +/* 3 bFormatType, bSubslotSize, bBitResolution */ 0x01, 2, 16, +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x0D, +/* 4 wMaxPacketSize, bInterval */ D0(256),D1(256), 4, +/* ---------- Audio 2.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x25, 0x01, +/* 3 bmAttributes, bmControls */ 0x00, 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), + +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + +/* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + +/* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + +/* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; +static UX_TEST_SETUP _GetCfgDescr = UX_TEST_SETUP_GetCfgDescr; +static UX_TEST_SETUP _SetAddress = UX_TEST_SETUP_SetAddress; +static UX_TEST_SETUP _GetDeviceDescriptor = UX_TEST_SETUP_GetDevDescr; +static UX_TEST_SETUP _GetConfigDescriptor = UX_TEST_SETUP_GetCfgDescr; + +/* Interaction define */ + +/* Hooks define */ + +static VOID ux_device_class_audio_tx_hook(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *p = (UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *)params; +UX_SLAVE_TRANSFER *transfer = (UX_SLAVE_TRANSFER *)p -> parameter; +UCHAR tmp[32] = {'i','n','s','e','r','t','A',0}; + + + (void)params; + // printf("tTX\n"); + + /* Acknowledge frame sent. */ + if (test_tx_ack_count) + { + SAVE_BUFFER_LOG(transfer -> ux_slave_transfer_request_data_pointer, transfer -> ux_slave_transfer_request_requested_length); + transfer -> ux_slave_transfer_request_actual_length = transfer -> ux_slave_transfer_request_requested_length; + transfer -> ux_slave_transfer_request_completion_code = UX_SUCCESS; + ux_test_dcd_sim_slave_transfer_done(transfer, UX_SUCCESS); + } + if (test_tx_ack_count != 0xFFFFFFFF && test_tx_ack_count > 0) + test_tx_ack_count --; + + /* Insert frames when sent. */ + if (test_tx_ins_count) + { + tmp[6] = (test_tx_ins_count % 26) + 'A'; + if (test_tx_ins_way == 0) + ux_device_class_audio_frame_write(slave_audio_tx_stream, tmp, 32); + else + { + + UCHAR *frame; + ULONG frame_length; + + + ux_device_class_audio_write_frame_get(slave_audio_tx_stream, &frame, &frame_length); + _ux_utility_memory_copy(frame, tmp, 32); + ux_device_class_audio_write_frame_commit(slave_audio_tx_stream, 32); + } + } + if (test_tx_ins_count != 0xFFFFFFFF && test_tx_ins_count > 0) + test_tx_ins_count --; +} + +static VOID ux_device_class_audio_rx_hook(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *p = (UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *)params; +UX_SLAVE_TRANSFER *transfer = (UX_SLAVE_TRANSFER *)p -> parameter; + + + (void)action; + (void)params; + (void)p; + (void)transfer; + // printf("tRX\n"); + slave_audio_rx_transfer = transfer; +} +static VOID slave_audio_rx_simulate_one_frame(UCHAR *frame, ULONG frame_length) +{ + UX_TEST_ASSERT(slave_audio_rx_transfer); + if (frame_length) + { + _ux_utility_memory_copy(slave_audio_rx_transfer->ux_slave_transfer_request_data_pointer, frame, frame_length); + slave_audio_rx_transfer->ux_slave_transfer_request_actual_length = frame_length; + slave_audio_rx_transfer->ux_slave_transfer_request_completion_code = UX_SUCCESS; + } + ux_test_dcd_sim_slave_transfer_done(slave_audio_rx_transfer, UX_SUCCESS); + _ux_utility_thread_sleep(1); +} + +static UX_TEST_ACTION ux_device_class_audio_transfer_hook[] = +{ + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .action_func = ux_device_class_audio_tx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x81, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .action_func = ux_device_class_audio_rx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x02, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, +{ 0 }, +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* 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 ++; + // printf("Error #%d, system_level: %d, system_context: %d, error_code: 0x%x\n", __LINE__, system_level, system_context, error_code); + + if (!error_callback_ignore) + { + { + /* Failed test. */ + 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 VOID slave_audio_activate(VOID *audio_instance) +{ + slave_audio = (UX_DEVICE_CLASS_AUDIO *)audio_instance; + ux_device_class_audio_stream_get(slave_audio, 0, &slave_audio_tx_stream); + ux_device_class_audio_stream_get(slave_audio, 1, &slave_audio_rx_stream); + // printf("sAUD:%p;%p,%p\n", audio_instance, slave_audio_tx_stream, slave_audio_rx_stream); +} +static VOID slave_audio_deactivate(VOID *audio_instance) +{ + if ((VOID *)slave_audio == audio_instance) + { + slave_audio = UX_NULL; + slave_audio_tx_stream = UX_NULL; + slave_audio_rx_stream = UX_NULL; + } +} +static VOID slave_audio_tx_stream_change(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG alt) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_tx_stream_change, audio, (ALIGN_TYPE)alt, 0); +} +static VOID slave_audio_rx_stream_change(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG alt) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_rx_stream_change, audio, (ALIGN_TYPE)alt, 0); + + slave_audio_rx_transfer = UX_NULL; +} +static UINT slave_audio_control_process(UX_DEVICE_CLASS_AUDIO *audio, UX_SLAVE_TRANSFER *transfer) +{ + + +UINT status; +UX_DEVICE_CLASS_AUDIO20_CONTROL_GROUP group = + {2, g_slave_audio20_control}; + + + SAVE_CALLBACK_INVOKE_LOG(slave_audio_control_process, audio, transfer, 0); + + status = ux_device_class_audio20_control_process(audio, transfer, &group); + if (status == UX_SUCCESS) + { + if (g_slave_audio20_control[0].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_MUTE_CHANGED) + { + /* Mute change! */ + } + if (g_slave_audio20_control[0].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_VOLUME_CHANGED) + { + /* Volume change! */ + } + if (g_slave_audio20_control[1].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_MUTE_CHANGED) + { + /* Mute change! */ + } + if (g_slave_audio20_control[1].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_VOLUME_CHANGED) + { + /* Volume change! */ + } + } + return(status); +} +static VOID slave_audio_tx_done(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG length) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_tx_done, audio, (ALIGN_TYPE)length, 0); +} +static VOID slave_audio_rx_done(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG length) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_rx_done, audio, (ALIGN_TYPE)length, 0); +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_DUMMY *dummy = (UX_HOST_CLASS_DUMMY *) inst; + + + switch(event) + { + + case UX_DEVICE_INSERTION: + + // printf("hINS:%p,%p:%ld\n", cls, inst, dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber); + switch(dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber) + { + case 0: dummy_control = dummy; break; + case 1: dummy_rx = dummy; break; + case 2: dummy_tx = dummy; break; + } + break; + + case UX_DEVICE_REMOVAL: + + // printf("hRMV:%p,%p:%ld\n", cls, inst, dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber); + switch(dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber) + { + case 0: dummy_control = UX_NULL; break; + case 1: dummy_rx = UX_NULL; break; + case 2: dummy_tx = UX_NULL; break; + } + break; + + default: + break; + } + return 0; +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_audio20_device_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running Audio 2.0 Device Basic Functionality Test................... "); + stepinfo("\n"); + + /* 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(); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* 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_host_change_function); + UX_TEST_CHECK_SUCCESS(status); + + /* Register Audio class. */ + status = ux_host_stack_class_register(_ux_host_class_dummy_name, _ux_host_class_dummy_entry); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Set the parameters for callback when insertion/extraction of a Audio 2.0 device, no IAD. */ + ux_utility_memory_set(&slave_audio_parameter, 0, sizeof(slave_audio_parameter)); + ux_utility_memory_set(slave_audio_stream_parameter, 0, sizeof(slave_audio_stream_parameter)); +#if !defined(UX_DEVICE_STANDALONE) + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_thread_entry = ux_device_class_audio_write_thread_entry; +#else + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_task_function = _ux_device_class_audio_write_task_function; +#endif + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_change = slave_audio_tx_stream_change; + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_frame_done = slave_audio_tx_done; + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_max_frame_buffer_size = 256; + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_max_frame_buffer_nb = 8; + +#if !defined(UX_DEVICE_STANDALONE) + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_thread_entry = ux_device_class_audio_read_thread_entry; +#else + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_task_function = _ux_device_class_audio_read_task_function; +#endif + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_change = slave_audio_rx_stream_change; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_frame_done = slave_audio_rx_done; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_max_frame_buffer_size = 256; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_max_frame_buffer_nb = 8; + slave_audio_parameter.ux_device_class_audio_parameter_streams = slave_audio_stream_parameter; + slave_audio_parameter.ux_device_class_audio_parameter_streams_nb = 2; + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_slave_class_audio_instance_activate = slave_audio_activate; + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_slave_class_audio_instance_deactivate = slave_audio_deactivate; + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_device_class_audio_control_process = slave_audio_control_process; + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_device_class_audio_arg = UX_NULL; + +#if defined(UX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT) + slave_audio_parameter.ux_device_class_audio_parameter_status_queue_size = 2; + slave_audio_parameter.ux_device_class_audio_parameter_status_size = 6; +#endif + + g_slave_audio20_control[0].ux_device_class_audio20_control_cs_id = 0x10; + g_slave_audio20_control[0].ux_device_class_audio20_control_sampling_frequency = 48000; + g_slave_audio20_control[0].ux_device_class_audio20_control_fu_id = 2; + g_slave_audio20_control[0].ux_device_class_audio20_control_mute[0] = 0; + g_slave_audio20_control[0].ux_device_class_audio20_control_volume[0] = 0; + g_slave_audio20_control[1].ux_device_class_audio20_control_cs_id = 0x10; + g_slave_audio20_control[1].ux_device_class_audio20_control_sampling_frequency = 48000; + g_slave_audio20_control[1].ux_device_class_audio20_control_fu_id = 5; + g_slave_audio20_control[1].ux_device_class_audio20_control_mute[0] = 0; + g_slave_audio20_control[1].ux_device_class_audio20_control_volume[0] = 0; + + /* Initialize the device Audio class. This class owns interfaces starting with 0, 1, 2. */ + status = ux_device_stack_class_register(_ux_system_slave_class_audio_name, ux_device_class_audio_entry, + 1, 0, &slave_audio_parameter); + UX_TEST_CHECK_SUCCESS(status); + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx demo host simulation", tx_test_thread_host_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx demo slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_CHECK_SUCCESS(status); +} + +static UINT test_wait_until_expected(VOID **ptr, ULONG loop, VOID *expected) +{ + while(loop) + { + _ux_utility_delay_ms(10); + if (*ptr == expected) + return UX_SUCCESS; + } + return UX_ERROR; +} +static UINT test_wait_until_not_expected(VOID **ptr, ULONG loop, VOID *expected) +{ + while(loop) + { + _ux_utility_delay_ms(10); + if (*ptr != expected) + return UX_SUCCESS; + } + return UX_ERROR; +} +#define test_wait_until_not_null(ptr, loop) test_wait_until_not_expected(ptr, loop, UX_NULL) +#define test_wait_until_null(ptr, loop) test_wait_until_expected(ptr, loop, UX_NULL) + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +// ULONG mem_free; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +UX_INTERFACE *interface_inst[3][2]; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UCHAR test_tmp[32]; +ULONG temp; + + + /* Test connect. */ + status = test_wait_until_not_null((void**)&dummy_control, 100); + status |= test_wait_until_not_null((void**)&dummy_tx, 100); + status |= test_wait_until_not_null((void**)&dummy_rx, 100); + status |= test_wait_until_not_null((void**)&slave_audio_tx_stream, 100); + status |= test_wait_until_not_null((void**)&slave_audio_rx_stream, 100); + UX_TEST_CHECK_SUCCESS(status); + + // /* Test disconnect. */ + // ux_test_dcd_sim_slave_disconnect(); + // ux_test_hcd_sim_host_disconnect(); + + // /* Reset testing counts. */ + // ux_test_utility_sim_mutex_create_count_reset(); + // ux_test_utility_sim_sem_create_count_reset(); + // ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + // /* Save free memory usage. */ + // mem_free = _ux_system->ux_system_regular_memory_pool_free; + // ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + // ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + // tx_thread_sleep(100); + // /* Log create counts for further tests. */ + // rsc_enum_mutex_usage = rsc_mutex_on_set_cfg; + // rsc_enum_sem_usage = rsc_sem_on_set_cfg; + // rsc_enum_mem_usage = mem_free - rsc_mem_free_on_set_cfg; + // /* Log create counts when instances active for further tests. */ + // rsc_cdc_mutex_usage = ux_test_utility_sim_mutex_create_count() - rsc_enum_mutex_usage; + // rsc_cdc_sem_usage = ux_test_utility_sim_sem_create_count() - rsc_enum_sem_usage; + // rsc_cdc_mem_usage = rsc_mem_free_on_set_cfg - _ux_system->ux_system_regular_memory_pool_free; + // stepinfo("mem free: %ld\n", _ux_system->ux_system_regular_memory_pool_free); + + /* Validate configuration descriptors. */ + /* ... */ + + /* Get testing instances. */ + + status = ux_host_stack_device_get(0, &device); + UX_TEST_CHECK_SUCCESS(status); + + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + status = ux_host_stack_device_configuration_get(device, 0, &configuration); + UX_TEST_CHECK_SUCCESS(status); + + interface = configuration -> ux_configuration_first_interface; + while(interface) + { + // printf("Interface: %ld.%ld\n", interface -> ux_interface_descriptor.bInterfaceNumber, interface -> ux_interface_descriptor.bAlternateSetting); + interface_inst[interface -> ux_interface_descriptor.bInterfaceNumber][interface -> ux_interface_descriptor.bAlternateSetting] = interface; + interface = interface -> ux_interface_next_interface; + } + + /* Test interface change. */ + /* Reset log. */ + RESET_CALLBACK_INVOKE_LOG(); + status = ux_host_stack_interface_setting_select(interface_inst[1][1]); + status |= ux_host_stack_interface_setting_select(interface_inst[1][0]); + status |= ux_host_stack_interface_setting_select(interface_inst[1][1]); + + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(callback_invoke_count == 3); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_tx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_tx_stream); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (VOID*)1); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_tx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_tx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].param2 == 0); + + RESET_CALLBACK_INVOKE_LOG(); + status = ux_host_stack_interface_setting_select(interface_inst[2][1]); + status |= ux_host_stack_interface_setting_select(interface_inst[2][0]); + status |= ux_host_stack_interface_setting_select(interface_inst[2][1]); + + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(callback_invoke_count == 3); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_rx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (VOID*)1); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_rx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].param2 == 0); + + /* Test data streaming. */ + + /* Wrong interface! */ + status = ux_device_class_audio_transmission_start(slave_audio_rx_stream); + status |= ux_device_class_audio_reception_start(slave_audio_tx_stream); + UX_TEST_CHECK_NOT_SUCCESS(status); + + ux_test_link_hooks_from_array(ux_device_class_audio_transfer_hook); + + /* ------------------ Write test. */ + + status = ux_device_class_audio_frame_write(slave_audio_tx_stream, "test0", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test1", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test2", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test3", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test4", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test5", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test6", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test7", 16); + UX_TEST_CHECK_SUCCESS(status); + + error_callback_counter = 0; + status = ux_device_class_audio_frame_write(slave_audio_tx_stream, "test8", 16); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + /* + Keep sending until under-run. + No buffer appended while running. + */ + + buffer_log_count = 0; + test_tx_ack_count = 10; + status = ux_device_class_audio_transmission_start(slave_audio_tx_stream); + UX_TEST_CHECK_SUCCESS(status); + + /* Delay to let thread runs. */ + _ux_utility_delay_ms(100); + + /* Prepare data for checking. */ + _ux_utility_memory_set(test_tmp, 0, 16); + _ux_utility_memory_copy(test_tmp, "test", 4); + + /* 8 frame should be available. */ + for (test_n = 0; test_n < 8; test_n ++) + { + // printf("%ld: %ld: %s\n", test_n, buffer_log[test_n].length, buffer_log[test_n].data); + test_tmp[4] = (UCHAR)(test_n + '0'); + + UX_TEST_ASSERT(buffer_log[test_n].length == 16); + + status = _ux_utility_memory_compare(buffer_log[test_n].data, test_tmp, 6); + UX_TEST_CHECK_SUCCESS(status); + } + /* Then under-run, 0 length packets. */ + for(;test_n < buffer_log_count; test_n ++) + { + // printf("%ld: %ld\n", test_n, buffer_log[test_n].length); + UX_TEST_ASSERT(buffer_log[test_n].length == 0); + } + + /* + Keep sending until under-run. + Specific number of buffer appended while running. + */ + + for (test_tx_ins_way = 0; test_tx_ins_way < 2; test_tx_ins_way ++) + { + + /* Switch interface to clean up status. */ + status = ux_host_stack_interface_setting_select(interface_inst[1][0]); + status |= ux_host_stack_interface_setting_select(interface_inst[1][1]); + + status = ux_device_class_audio_frame_write(slave_audio_tx_stream, "test0", 20); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test1", 20); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test2", 20); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test3", 20); + UX_TEST_CHECK_SUCCESS(status); + + test_tx_ins_count = 10; + test_tx_ack_count = 20; + buffer_log_count = 0; + status = ux_device_class_audio_transmission_start(slave_audio_tx_stream); + UX_TEST_CHECK_SUCCESS(status); + + /* Delay to let thread runs. */ + _ux_utility_delay_ms(300); + + /* Prepare data for checking. */ + _ux_utility_memory_set(test_tmp, 0, 32); + + /* 4 frame should be available. */ + _ux_utility_memory_copy(test_tmp, "test", 4); + for (test_n = 0; test_n < 4; test_n ++) + { + // printf("%ld: %ld: %s\n", test_n, buffer_log[test_n].length, buffer_log[test_n].data); + test_tmp[4] = (UCHAR)(test_n + '0'); + + UX_TEST_ASSERT(buffer_log[test_n].length == 20); + + status = _ux_utility_memory_compare(buffer_log[test_n].data, test_tmp, 6); + UX_TEST_CHECK_SUCCESS(status); + } + /* 10 more frame should be available. */ + _ux_utility_memory_copy(test_tmp, "insert", 6); + for (; test_n < 14; test_n ++) + { + // printf("%ld: %ld: %s\n", test_n, buffer_log[test_n].length, buffer_log[test_n].data); + test_tmp[6] = (UCHAR)(((10 - (test_n - 4)) % 26) + 'A'); + + UX_TEST_ASSERT(buffer_log[test_n].length == 32); + + status = _ux_utility_memory_compare(buffer_log[test_n].data, test_tmp, 8); + UX_TEST_CHECK_SUCCESS(status); + } + /* Then under-run, 0 length packets. */ + for(;test_n < buffer_log_count; test_n ++) + { + // printf("%ld: %ld\n", test_n, buffer_log[test_n].length); + UX_TEST_ASSERT(buffer_log[test_n].length == 0); + } + } + + UX_TEST_ASSERT(slave_audio_tx_stream->ux_device_class_audio_stream_transfer_pos == slave_audio_tx_stream->ux_device_class_audio_stream_access_pos); + + /* ------------------ Read - 8 test. */ + + UX_TEST_ASSERT(slave_audio_rx_transfer == UX_NULL); + + temp = 0; + status = ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + status = ux_device_class_audio_reception_start(slave_audio_rx_stream); + UX_TEST_CHECK_SUCCESS(status); + _ux_utility_thread_sleep(1); + + UX_TEST_ASSERT(slave_audio_rx_transfer != UX_NULL); + + status = ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + RESET_CALLBACK_INVOKE_LOG(); + + slave_audio_rx_simulate_one_frame("012345", 6); + for (test_n = 0; test_n < 6; test_n ++) + { + status = ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(temp == (test_n + '0')); + } + + slave_audio_rx_simulate_one_frame("012345", 6); + slave_audio_rx_simulate_one_frame("67", 2); + slave_audio_rx_simulate_one_frame("89", 2); + + for (test_n = 0; test_n < 10; test_n ++) + { + status = ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(temp == (test_n + '0')); + } + + UX_TEST_ASSERT(callback_invoke_count == 4); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[2].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[2].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[3].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[3].param1 == slave_audio_rx_stream); + + RESET_CALLBACK_INVOKE_LOG(); + error_callback_counter = 0; + for (test_n = 0; test_n < 10; test_n ++) + { + test_tmp[0] = (UCHAR)(test_n + '0'); + slave_audio_rx_simulate_one_frame(test_tmp, 1); + } + + UX_TEST_ASSERT(callback_invoke_count == 10); + UX_TEST_ASSERT(error_callback_counter == 3); + for (test_n = 0; test_n < 7; test_n ++) + { + status = ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp); + UX_TEST_CHECK_SUCCESS(status); + // printf("(%lx)%c\n", temp, (char)temp); + UX_TEST_ASSERT(temp == (test_n + '0')); + } + UX_TEST_CHECK_SUCCESS(ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp)); + UX_TEST_ASSERT(temp == '9'); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp)); + + /* ------------------ Read - 16 test. */ + + status = ux_device_class_audio_sample_read16(slave_audio_rx_stream, (USHORT *)&temp); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + RESET_CALLBACK_INVOKE_LOG(); + slave_audio_rx_simulate_one_frame("012345", 6); + slave_audio_rx_simulate_one_frame("67", 2); + UX_TEST_ASSERT(callback_invoke_count == 2); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (VOID*)6); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].param2 == (VOID*)2); + for (test_n = 0; test_n < 4; test_n ++) + { + status = ux_device_class_audio_sample_read16(slave_audio_rx_stream, (USHORT *)&temp); + UX_TEST_CHECK_SUCCESS(status); + // printf("%lx\n", temp); + test_tmp[0] = (UCHAR)(test_n * 2 + '0'); + test_tmp[1] = (UCHAR)(test_n * 2 + '1'); + UX_TEST_CHECK_SUCCESS(_ux_utility_memory_compare(test_tmp, &temp, 2)); + } + + /* ------------------ Read - 24 test. */ + + status = ux_device_class_audio_sample_read24(slave_audio_rx_stream, &temp); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + RESET_CALLBACK_INVOKE_LOG(); + slave_audio_rx_simulate_one_frame("012345", 6); + slave_audio_rx_simulate_one_frame("678", 3); + UX_TEST_ASSERT(callback_invoke_count == 2); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (VOID*)6); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].param2 == (VOID*)3); + for (test_n = 0; test_n < 3; test_n ++) + { + status = ux_device_class_audio_sample_read24(slave_audio_rx_stream, &temp); + UX_TEST_CHECK_SUCCESS(status); + // printf("%lx\n", temp); + test_tmp[0] = (UCHAR)(test_n * 3 + '0'); + test_tmp[1] = (UCHAR)(test_n * 3 + '1'); + test_tmp[2] = (UCHAR)(test_n * 3 + '2'); + UX_TEST_CHECK_SUCCESS(_ux_utility_memory_compare(test_tmp, &temp, 3)); + } + + /* ------------------ Read - 32 test. */ + + status = ux_device_class_audio_sample_read32(slave_audio_rx_stream, &temp); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + RESET_CALLBACK_INVOKE_LOG(); + slave_audio_rx_simulate_one_frame("01234567", 8); + slave_audio_rx_simulate_one_frame("8901", 4); + UX_TEST_ASSERT(callback_invoke_count == 2); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (VOID*)8); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].param2 == (VOID*)4); + for (test_n = 0; test_n < 3; test_n ++) + { + status = ux_device_class_audio_sample_read32(slave_audio_rx_stream, &temp); + UX_TEST_CHECK_SUCCESS(status); + // printf("%lx\n", temp); + test_tmp[0] = ((test_n * 4 + 0) % 10) + '0'; + test_tmp[1] = ((test_n * 4 + 1) % 10) + '0'; + test_tmp[2] = ((test_n * 4 + 2) % 10) + '0'; + test_tmp[3] = ((test_n * 4 + 3) % 10) + '0'; + UX_TEST_CHECK_SUCCESS(_ux_utility_memory_compare(test_tmp, &temp, 4)); + } + + UX_TEST_ASSERT(slave_audio_tx_stream->ux_device_class_audio_stream_transfer_pos == slave_audio_tx_stream->ux_device_class_audio_stream_access_pos); + + /**************************************************************************/ + + /* Control requests test. */ + + transfer_request -> ux_transfer_request_data_pointer = buffer; + + test_tmp[0] = 2; + test_tmp[1] = 5; + + for (test_n = 0; test_n < 2; test_n ++) + { + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_AUDIO20_CUR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + + /* Issue SetFeatureMute(test_tmp[test_n], 0). */ + transfer_request -> ux_transfer_request_requested_length = 1; + transfer_request -> ux_transfer_request_index = (test_tmp[test_n] << 8) | 0; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO20_FU_MUTE_CONTROL << 8) | 0; + buffer[0] = 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_changed == 0); + + /* Issue SetFeatureMute(test_tmp[test_n], 1). */ + buffer[0] = 1; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_MUTE_CHANGED); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_mute[0] == 1); + + /* Issue SetFeatureMute(test_tmp[test_n], 0). */ + buffer[0] = 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_MUTE_CHANGED); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_mute[0] == 0); + + /* Issue SetFeatureMute(test_tmp[test_n], 1). */ + buffer[0] = 1; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_MUTE_CHANGED); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_mute[0] == 1); + + /* Issue SetFeatureVolume(test_tmp[test_n], 0x0003). */ + transfer_request -> ux_transfer_request_requested_length = 2; + transfer_request -> ux_transfer_request_index = (test_tmp[test_n] << 8) | 0; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO20_FU_VOLUME_CONTROL << 8) | 0; + buffer[0] = 3; buffer[1] = 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_VOLUME_CHANGED); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_volume[0] == 0x0003); + + /* Issue SetFeatureVolume(test_tmp[test_n], 0x0103). */ + buffer[1] = 1; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_VOLUME_CHANGED); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_volume[0] == 0x0103); + + /* Issue SetFeatureVolume(test_tmp[test_n], 0x0103). */ + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_changed == 0); + + /* Issue GetFeatureMute(test_tmp[test_n]). */ + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_AUDIO20_CUR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + + transfer_request -> ux_transfer_request_requested_length = 1; + transfer_request -> ux_transfer_request_index = (test_tmp[test_n] << 8) | 0; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO20_FU_MUTE_CONTROL << 8) | 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(transfer_request -> ux_transfer_request_actual_length == 1); + UX_TEST_ASSERT(buffer[0] == 1); + + /* Issue GetFeatureMute(test_tmp[test_n]). */ + transfer_request -> ux_transfer_request_requested_length = 2; + transfer_request -> ux_transfer_request_index = (test_tmp[test_n] << 8) | 0; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO20_FU_VOLUME_CONTROL << 8) | 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(transfer_request -> ux_transfer_request_actual_length == 2); + UX_TEST_ASSERT(buffer[0] == 3); + UX_TEST_ASSERT(buffer[1] == 1); + + /* Issue GetClockSamplingFrequency(0x10). */ + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_AUDIO20_CUR; + transfer_request -> ux_transfer_request_requested_length = 4; + transfer_request -> ux_transfer_request_index = (0x10 << 8) | 0; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO20_CS_SAM_FREQ_CONTROL << 8) | 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(transfer_request -> ux_transfer_request_actual_length == 4); + UX_TEST_ASSERT(buffer[0] == D0(48000)); + UX_TEST_ASSERT(buffer[1] == D1(48000)); + UX_TEST_ASSERT(buffer[2] == D2(48000)); + UX_TEST_ASSERT(buffer[3] == D3(48000)); + + /* Issue GetClockSamplingFrequencyRange(0x10). */ + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_AUDIO20_RANGE; + transfer_request -> ux_transfer_request_requested_length = 14; + transfer_request -> ux_transfer_request_index = (0x10 << 8) | 0; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO20_CS_SAM_FREQ_CONTROL << 8) | 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(transfer_request -> ux_transfer_request_actual_length == 14); + UX_TEST_ASSERT(buffer[ 0] == D0(1)); + UX_TEST_ASSERT(buffer[ 1] == D1(1)); + UX_TEST_ASSERT(buffer[ 2] == D0(48000)); + UX_TEST_ASSERT(buffer[ 3] == D1(48000)); + UX_TEST_ASSERT(buffer[ 4] == D2(48000)); + UX_TEST_ASSERT(buffer[ 5] == D3(48000)); + UX_TEST_ASSERT(buffer[ 6] == D0(48000)); + UX_TEST_ASSERT(buffer[ 7] == D1(48000)); + UX_TEST_ASSERT(buffer[ 8] == D2(48000)); + UX_TEST_ASSERT(buffer[ 9] == D3(48000)); + } + + /* Wait pending threads. */ + _ux_utility_thread_sleep(1); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + ux_device_stack_class_unregister(_ux_system_slave_class_audio_name, ux_device_class_audio_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + + /* Standalone background task. */ + ux_system_tasks_run(); +#else + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); +#endif + } +} diff --git a/test/regression/usbx_audio20_device_controls_test.c b/test/regression/usbx_audio20_device_controls_test.c new file mode 100644 index 00000000..4a616861 --- /dev/null +++ b/test/regression/usbx_audio20_device_controls_test.c @@ -0,0 +1,1265 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" + +#include "fx_api.h" + +#include "ux_device_class_audio.h" +#include "ux_device_class_audio20.h" +#include "ux_device_stack.h" + +#include "ux_host_class_audio.h" +#include "ux_host_class_dummy.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_DEMO_REQUEST_MAX_LENGTH \ + ((UX_HCD_SIM_HOST_MAX_PAYLOAD) > (UX_SLAVE_REQUEST_DATA_MAX_LENGTH) ? \ + (UX_HCD_SIM_HOST_MAX_PAYLOAD) : (UX_SLAVE_REQUEST_DATA_MAX_LENGTH)) + +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_DEMO_REQUEST_MAX_LENGTH + 1) +#define UX_DEMO_MEMORY_SIZE (128*1024) + +#define UX_TEST_LOG_SIZE (64) + + +/* Define local/extern function prototypes. */ +static void test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static void tx_test_thread_host_simulation_entry(ULONG); +static void tx_test_thread_slave_simulation_entry(ULONG); + + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[64]; + +static UX_HOST_CLASS_DUMMY *dummy_control; +static UX_HOST_CLASS_DUMMY *dummy_tx; +static UX_HOST_CLASS_DUMMY *dummy_rx; + +static UX_DEVICE_CLASS_AUDIO *slave_audio; +static UX_DEVICE_CLASS_AUDIO_PARAMETER slave_audio_parameter; +static UX_DEVICE_CLASS_AUDIO_STREAM_PARAMETER slave_audio_stream_parameter[2]; + +static UX_DEVICE_CLASS_AUDIO_STREAM *slave_audio_tx_stream; + +static UX_DEVICE_CLASS_AUDIO_STREAM *slave_audio_rx_stream; +static UX_SLAVE_TRANSFER *slave_audio_rx_transfer; + +static ULONG device_audio_tx_feedback; +static UCHAR* device_audio_tx_feedback_u8a = (UCHAR*)&device_audio_tx_feedback; +static ULONG device_audio_tx_feedback_count; +static ULONG device_audio_rx_feedback; +static UCHAR* device_audio_rx_feedback_u8a = (UCHAR*)&device_audio_rx_feedback; +static ULONG device_audio_rx_feedback_count; + + +static UX_HOST_CLASS_AUDIO *audio; + +static UX_DEVICE_CLASS_AUDIO20_CONTROL g_slave_audio20_control[2]; +static UCHAR audio20_cs_range[] = { + UX_W0 ( 2), UX_W0 ( 2), /* Number of subs. */ + + UX_DW0(44100), UX_DW1(44100), UX_DW2(44100), UX_DW3(44100), /* dMIN */ + UX_DW0(44100), UX_DW1(44100), UX_DW2(44100), UX_DW3(44100), /* dMAX */ + UX_DW0( 0), UX_DW1( 0), UX_DW2( 0), UX_DW3( 0), /* dRES */ + + UX_DW0( 8000), UX_DW1( 8000), UX_DW2( 8000), UX_DW3( 8000), /* dMIN */ + UX_DW0(48000), UX_DW1(48000), UX_DW2(48000), UX_DW3(48000), /* dMAX */ + UX_DW0( 8000), UX_DW1( 8000), UX_DW2( 8000), UX_DW3( 8000), /* dRES */ +}; + +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_audio_sem_usage; +static ULONG rsc_audio_sem_get_count; +static ULONG rsc_audio_mutex_usage; +static ULONG rsc_audio_mem_usage; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +static struct BUFFER_LOG_STRUCT { + ULONG length; + UCHAR data[256]; +} buffer_log[UX_TEST_LOG_SIZE]; +static ULONG buffer_log_count = 0; +#define SAVE_BUFFER_LOG(buf,siz) do { \ + if (buffer_log_count < UX_TEST_LOG_SIZE) { \ + ULONG __local_size__ = ((siz) > 256) ? 256 : (siz); \ + buffer_log[buffer_log_count].length = (siz); \ + _ux_utility_memory_copy(buffer_log[buffer_log_count].data, (buf), __local_size__); \ + } \ + buffer_log_count ++; \ +} while(0) + +static ULONG test_tx_ack_count = 0xFFFFFFFF; +static ULONG test_tx_ins_count = 0; +static ULONG test_tx_ins_way = 0; + +static struct CALLBACK_INVOKE_LOG_STRUCT { + VOID *func; + VOID *param1; + VOID *param2; + VOID *param3; +} callback_invoke_log[UX_TEST_LOG_SIZE]; +static ULONG callback_invoke_count = 0; + +#define SAVE_CALLBACK_INVOKE_LOG(f,p1,p2,p3) do { \ + if (callback_invoke_count < UX_TEST_LOG_SIZE) { \ + callback_invoke_log[callback_invoke_count].func = (VOID *)(f); \ + callback_invoke_log[callback_invoke_count].param1 = (VOID *)(p1); \ + callback_invoke_log[callback_invoke_count].param2 = (VOID *)(p2); \ + callback_invoke_log[callback_invoke_count].param3 = (VOID *)(p3); \ + callback_invoke_count++; \ + } \ +} while(0) +#define RESET_CALLBACK_INVOKE_LOG() do { \ + callback_invoke_count = 0; \ +} while(0) + +/* Define device framework. */ + +#define D3(d) ((UCHAR)((d) >> 24)) +#define D2(d) ((UCHAR)((d) >> 16)) +#define D1(d) ((UCHAR)((d) >> 8)) +#define D0(d) ((UCHAR)((d) >> 0)) + +static unsigned char device_framework_full_speed[] = { + +/* --------------------------------------- Device Descriptor */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x02, 0x00, +/* 12 bcdDevice */ D0(0x200),D1(0x200), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* ----------------------------- Device Qualifier Descriptor */ +/* 0 bLength, bDescriptorType */ 10, 0x06, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 bNumConfigurations */ 1, +/* 9 bReserved */ 0, + +/* -------------------------------- Configuration Descriptor *//* 9+8+120+55*2=247 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(247+14),D1(247+14), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------ Interface Association Descriptor */ +/* 0 bLength, bDescriptorType */ 8, 0x0B, +/* 2 bFirstInterface, bInterfaceCount */ 0, 3, +/* 4 bFunctionClass, bFunctionSubClass, bFunctionProtocol */ 0x01, 0x00, 0x20, +/* 7 iFunction */ 0, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+111=120) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x20, +/* 8 iInterface */ 0, +/* ---------------- Audio 2.0 AC Interface Header Descriptor *//* (9+8+17*2+18*2+12*2=111) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x01, +/* 3 bcdADC, bCategory */ D0(0x200),D1(0x200), 0x08, +/* 6 wTotalLength */ D0(111),D1(111), +/* 8 bmControls */ 0x00, +/* -------------------- Audio 2.0 AC Clock Source Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x24, 0x0A, +/* 3 bClockID, bmAttributes, bmControls */ 0x10, 0x05, 0x01, +/* 6 bAssocTerminal, iClockSource */ 0x00, 0, +/* ------------------- Audio 2.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 17, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, bCSourceID */ 0x00, 0x10, +/* 8 bNrChannels, bmChannelConfig */ 0x02, D0(0),D1(0),D2(0),D3(0), +/* 13 iChannelNames, bmControls, iTerminal */ 0, D0(0),D1(0), 0, +/* --------------------- Audio 2.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 18, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bmaControls(0), bmaControls(...) ... */ D0(0xF),D1(0xF),D2(0xF),D3(0xF), D0(0),D1(0),D2(0),D3(0), D0(0),D1(0),D2(0),D3(0), +/* . iFeature */ 0, +/* ------------------ Audio 2.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID, bCSourceID */ 0x00, 0x02, 0x10, +/* 9 bmControls, iTerminal */ D0(0),D1(0), 0, +/* ------------------- Audio 2.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 17, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bCSourceID */ 0x00, 0x10, +/* 8 bNrChannels, bmChannelConfig */ 0x02, D0(0),D1(0),D2(0),D3(0), +/* 13 iChannelNames, bmControls, iTerminal */ 0, D0(0),D1(0), 0, +/* --------------------- Audio 2.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 18, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bmaControls(0), bmaControls(...) ... */ D0(0xF),D1(0xF),D2(0xF),D3(0xF), D0(0),D1(0),D2(0),D3(0), D0(0),D1(0),D2(0),D3(0), +/* . iFeature */ 0, +/* ------------------ Audio 2.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID, bCSourceID */ 0x00, 0x05, 0x10, +/* 9 bmControls, iTerminal */ D0(0),D1(0), 0, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+16+6+7+8=55) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 2, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------ Audio 2.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 16, 0x24, 0x01, +/* 3 bTerminalLink, bmControls */ 0x03,0x00, +/* 5 bFormatType, bmFormats */ 0x01,D0(1),D1(1),D2(1),D3(1), +/* 10 bNrChannels, bmChannelConfig */ 2, D0(0),D1(0),D2(0),D3(0), +/* 15 iChannelNames */ 0, +/* -------------------- Audio 2.0 AS Format Type I Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 6, 0x24, 0x02, +/* 3 bFormatType, bSubslotSize, bBitResolution */ 0x01, 2, 16, +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x0D, +/* 4 wMaxPacketSize, bInterval */ D0(256),D1(256), 1, +/* ---------- Audio 2.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x25, 0x01, +/* 3 bmAttributes, bmControls */ 0x00, 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x01, 0x11, +/* 4 wMaxPacketSize, bInterval */ D0(4),D1(4), 1, + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+16+6+7+8=55) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 2, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------ Audio 2.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 16, 0x24, 0x01, +/* 3 bTerminalLink, bmControls */ 0x04,0x00, +/* 5 bFormatType, bmFormats */ 0x01,D0(1),D1(1),D2(1),D3(1), +/* 10 bNrChannels, bmChannelConfig */ 2, D0(0),D1(0),D2(0),D3(0), +/* 15 iChannelNames */ 0, +/* ---------------------- Audio 2.0 AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 6, 0x24, 0x02, +/* 3 bFormatType, bSubslotSize, bBitResolution */ 0x01, 2, 16, +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x0D, +/* 4 wMaxPacketSize, bInterval */ D0(256),D1(256), 1, +/* ---------- Audio 2.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x25, 0x01, +/* 3 bmAttributes, bmControls */ 0x00, 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x82, 0x11, +/* 4 wMaxPacketSize, bInterval */ D0(4),D1(4), 1, + +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { +/* --------------------------------------- Device Descriptor */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 0x08, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x02, 0x00, +/* 12 bcdDevice */ D0(0x200),D1(0x200), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* ----------------------------- Device Qualifier Descriptor */ +/* 0 bLength, bDescriptorType */ 10, 0x06, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 bNumConfigurations */ 1, +/* 9 bReserved */ 0, + +/* -------------------------------- Configuration Descriptor *//* 9+8+120+55*2=247 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(247+14),D1(247+14), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------ Interface Association Descriptor */ +/* 0 bLength, bDescriptorType */ 8, 0x0B, +/* 2 bFirstInterface, bInterfaceCount */ 0, 3, +/* 4 bFunctionClass, bFunctionSubClass, bFunctionProtocol */ 0x01, 0x00, 0x20, +/* 7 iFunction */ 0, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+111=120) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x20, +/* 8 iInterface */ 0, +/* ---------------- Audio 2.0 AC Interface Header Descriptor *//* (9+8+17*2+18*2+12*2=111) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x01, +/* 3 bcdADC, bCategory */ D0(0x200),D1(0x200), 0x08, +/* 6 wTotalLength */ D0(111),D1(111), +/* 8 bmControls */ 0x00, +/* -------------------- Audio 2.0 AC Clock Source Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x24, 0x0A, +/* 3 bClockID, bmAttributes, bmControls */ 0x10, 0x05, 0x01, +/* 6 bAssocTerminal, iClockSource */ 0x00, 0, +/* ------------------- Audio 2.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 17, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, bCSourceID */ 0x00, 0x10, +/* 8 bNrChannels, bmChannelConfig */ 0x02, D0(0),D1(0),D2(0),D3(0), +/* 13 iChannelNames, bmControls, iTerminal */ 0, D0(0),D1(0), 0, +/* --------------------- Audio 2.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 18, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bmaControls(0), bmaControls(...) ... */ D0(0xF),D1(0xF),D2(0xF),D3(0xF), D0(0),D1(0),D2(0),D3(0), D0(0),D1(0),D2(0),D3(0), +/* . iFeature */ 0, +/* ------------------ Audio 2.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID, bCSourceID */ 0x00, 0x02, 0x10, +/* 9 bmControls, iTerminal */ D0(0),D1(0), 0, +/* ------------------- Audio 2.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 17, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bCSourceID */ 0x00, 0x10, +/* 8 bNrChannels, bmChannelConfig */ 0x02, D0(0),D1(0),D2(0),D3(0), +/* 13 iChannelNames, bmControls, iTerminal */ 0, D0(0),D1(0), 0, +/* --------------------- Audio 2.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 18, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bmaControls(0), bmaControls(...) ... */ D0(0xF),D1(0xF),D2(0xF),D3(0xF), D0(0),D1(0),D2(0),D3(0), D0(0),D1(0),D2(0),D3(0), +/* . iFeature */ 0, +/* ------------------ Audio 2.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID, bCSourceID */ 0x00, 0x05, 0x10, +/* 9 bmControls, iTerminal */ D0(0),D1(0), 0, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+16+6+7+8=55) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 2, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------ Audio 2.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 16, 0x24, 0x01, +/* 3 bTerminalLink, bmControls */ 0x03,0x00, +/* 5 bFormatType, bmFormats */ 0x01,D0(1),D1(1),D2(1),D3(1), +/* 10 bNrChannels, bmChannelConfig */ 2, D0(0),D1(0),D2(0),D3(0), +/* 15 iChannelNames */ 0, +/* -------------------- Audio 2.0 AS Format Type I Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 6, 0x24, 0x02, +/* 3 bFormatType, bSubslotSize, bBitResolution */ 0x01, 2, 16, +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x0D, +/* 4 wMaxPacketSize, bInterval */ D0(256),D1(256), 4, +/* ---------- Audio 2.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x25, 0x01, +/* 3 bmAttributes, bmControls */ 0x00, 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x01, 0x11, +/* 4 wMaxPacketSize, bInterval */ D0(4),D1(4), 1, + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+16+6+7+8=55) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 2, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------ Audio 2.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 16, 0x24, 0x01, +/* 3 bTerminalLink, bmControls */ 0x04,0x00, +/* 5 bFormatType, bmFormats */ 0x01,D0(1),D1(1),D2(1),D3(1), +/* 10 bNrChannels, bmChannelConfig */ 2, D0(0),D1(0),D2(0),D3(0), +/* 15 iChannelNames */ 0, +/* ---------------------- Audio 2.0 AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 6, 0x24, 0x02, +/* 3 bFormatType, bSubslotSize, bBitResolution */ 0x01, 2, 16, +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x0D, +/* 4 wMaxPacketSize, bInterval */ D0(256),D1(256), 4, +/* ---------- Audio 2.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x25, 0x01, +/* 3 bmAttributes, bmControls */ 0x00, 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x82, 0x11, +/* 4 wMaxPacketSize, bInterval */ D0(4),D1(4), 1, + +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + +/* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + +/* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + +/* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; +static UX_TEST_SETUP _GetCfgDescr = UX_TEST_SETUP_GetCfgDescr; +static UX_TEST_SETUP _SetAddress = UX_TEST_SETUP_SetAddress; +static UX_TEST_SETUP _GetDeviceDescriptor = UX_TEST_SETUP_GetDevDescr; +static UX_TEST_SETUP _GetConfigDescriptor = UX_TEST_SETUP_GetCfgDescr; + +/* Interaction define */ + +/* Hooks define */ + +static VOID ux_device_class_audio_tx_hook(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *p = (UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *)params; +UX_SLAVE_TRANSFER *transfer = (UX_SLAVE_TRANSFER *)p -> parameter; +UCHAR tmp[32] = {'i','n','s','e','r','t','A',0}; + + + (void)params; + // printf("tTX\n"); + + /* Acknowledge frame sent. */ + if (test_tx_ack_count) + { + SAVE_BUFFER_LOG(transfer -> ux_slave_transfer_request_data_pointer, transfer -> ux_slave_transfer_request_requested_length); + transfer -> ux_slave_transfer_request_actual_length = transfer -> ux_slave_transfer_request_requested_length; + transfer -> ux_slave_transfer_request_completion_code = UX_SUCCESS; + _ux_utility_semaphore_put(&transfer -> ux_slave_transfer_request_semaphore); + } + if (test_tx_ack_count != 0xFFFFFFFF && test_tx_ack_count > 0) + test_tx_ack_count --; + + /* Insert frames when sent. */ + if (test_tx_ins_count) + { + tmp[6] = (test_tx_ins_count % 26) + 'A'; + if (test_tx_ins_way == 0) + ux_device_class_audio_frame_write(slave_audio_tx_stream, tmp, 32); + else + { + + UCHAR *frame; + ULONG frame_length; + + + ux_device_class_audio_write_frame_get(slave_audio_tx_stream, &frame, &frame_length); + _ux_utility_memory_copy(frame, tmp, 32); + ux_device_class_audio_write_frame_commit(slave_audio_tx_stream, 32); + } + } + if (test_tx_ins_count != 0xFFFFFFFF && test_tx_ins_count > 0) + test_tx_ins_count --; +} + +static VOID ux_device_class_audio_rx_hook(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *p = (UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *)params; +UX_SLAVE_TRANSFER *transfer = (UX_SLAVE_TRANSFER *)p -> parameter; + + + (void)action; + (void)params; + (void)p; + (void)transfer; + // printf("tRX\n"); + slave_audio_rx_transfer = transfer; +} + +static VOID ux_device_class_audio_feedback_hook(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *p = (UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *)params; +UX_SLAVE_TRANSFER *transfer = (UX_SLAVE_TRANSFER *)p -> parameter; +ULONG length; + + (void)action; + (void)params; + (void)p; + (void)transfer; + length = UX_MIN(4, transfer->ux_slave_transfer_request_requested_length); + if (transfer->ux_slave_transfer_request_endpoint->ux_slave_endpoint_descriptor.bEndpointAddress & 0x80) + { + device_audio_rx_feedback_count ++; + /* IN for OUT(RX/read) feedback. */ + device_audio_rx_feedback = 0; + _ux_utility_memory_copy(device_audio_rx_feedback_u8a, + transfer->ux_slave_transfer_request_data_pointer, length); + transfer -> ux_slave_transfer_request_completion_code = UX_SUCCESS; + transfer -> ux_slave_transfer_request_actual_length = length; + } + else + { + device_audio_tx_feedback_count ++; + /* OUT for IN(TX/write) feedback. */ + _ux_utility_memory_copy(transfer->ux_slave_transfer_request_data_pointer, + device_audio_tx_feedback_u8a, length); + transfer -> ux_slave_transfer_request_completion_code = UX_SUCCESS; + transfer -> ux_slave_transfer_request_actual_length = length; + } + _ux_utility_semaphore_put(&transfer->ux_slave_transfer_request_semaphore); + _ux_utility_thread_sleep(1); +} + +static VOID slave_audio_rx_simulate_one_frame(UCHAR *frame, ULONG frame_length) +{ + UX_TEST_ASSERT(slave_audio_rx_transfer); + if (frame_length) + { + _ux_utility_memory_copy(slave_audio_rx_transfer->ux_slave_transfer_request_data_pointer, frame, frame_length); + slave_audio_rx_transfer->ux_slave_transfer_request_actual_length = frame_length; + slave_audio_rx_transfer->ux_slave_transfer_request_completion_code = UX_SUCCESS; + } + _ux_utility_semaphore_put(&slave_audio_rx_transfer->ux_slave_transfer_request_semaphore); + _ux_utility_thread_sleep(1); +} + +static UX_TEST_ACTION ux_device_class_audio_transfer_hook[] = +{ + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .action_func = ux_device_class_audio_tx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x81, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .action_func = ux_device_class_audio_rx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x02, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .action_func = ux_device_class_audio_feedback_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x82, + .req_status = UX_SUCCESS, + .status = UX_SUCCESS, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .action_func = ux_device_class_audio_feedback_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x01, + .req_status = UX_SUCCESS, + .status = UX_SUCCESS, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, +{ 0 }, +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* 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 ++; + // printf("Error #%d, system_level: %d, system_context: %d, error_code: 0x%x\n", __LINE__, system_level, system_context, error_code); + + if (!error_callback_ignore) + { + { + /* Failed test. */ + 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 VOID slave_audio_activate(VOID *audio_instance) +{ + slave_audio = (UX_DEVICE_CLASS_AUDIO *)audio_instance; + ux_device_class_audio_stream_get(slave_audio, 0, &slave_audio_tx_stream); + ux_device_class_audio_stream_get(slave_audio, 1, &slave_audio_rx_stream); + // printf("sAUD:%p;%p,%p\n", audio_instance, slave_audio_tx_stream, slave_audio_rx_stream); +} +static VOID slave_audio_deactivate(VOID *audio_instance) +{ + if ((VOID *)slave_audio == audio_instance) + { + slave_audio = UX_NULL; + slave_audio_tx_stream = UX_NULL; + slave_audio_rx_stream = UX_NULL; + } +} +static VOID slave_audio_tx_stream_change(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG alt) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_tx_stream_change, audio, (ALIGN_TYPE)alt, 0); +} +static VOID slave_audio_rx_stream_change(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG alt) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_rx_stream_change, audio, (ALIGN_TYPE)alt, 0); + + slave_audio_rx_transfer = UX_NULL; +} +static UINT slave_audio_control_process(UX_DEVICE_CLASS_AUDIO *audio, UX_SLAVE_TRANSFER *transfer) +{ + + +UINT status; +UX_DEVICE_CLASS_AUDIO20_CONTROL_GROUP group = + {2, g_slave_audio20_control}; + + + SAVE_CALLBACK_INVOKE_LOG(slave_audio_control_process, audio, transfer, 0); + + status = ux_device_class_audio20_control_process(audio, transfer, &group); + if (status == UX_SUCCESS) + { + if (g_slave_audio20_control[0].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_MUTE_CHANGED) + { + /* Mute change! */ + } + if (g_slave_audio20_control[0].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_VOLUME_CHANGED) + { + /* Volume change! */ + } + if (g_slave_audio20_control[1].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_MUTE_CHANGED) + { + /* Mute change! */ + } + if (g_slave_audio20_control[1].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_VOLUME_CHANGED) + { + /* Volume change! */ + } + } + return(status); +} +static VOID slave_audio_tx_done(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG length) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_tx_done, audio, (ALIGN_TYPE)length, 0); +} +static VOID slave_audio_rx_done(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG length) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_rx_done, audio, (ALIGN_TYPE)length, 0); +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_DUMMY *dummy = (UX_HOST_CLASS_DUMMY *) inst; + + + switch(event) + { + + case UX_DEVICE_INSERTION: + + // printf("hINS:%p,%p:%ld\n", cls, inst, dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber); + switch(dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber) + { + case 0: dummy_control = dummy; break; + case 1: dummy_rx = dummy; break; + case 2: dummy_tx = dummy; break; + } + break; + + case UX_DEVICE_REMOVAL: + + // printf("hRMV:%p,%p:%ld\n", cls, inst, dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber); + switch(dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber) + { + case 0: dummy_control = UX_NULL; break; + case 1: dummy_rx = UX_NULL; break; + case 2: dummy_tx = UX_NULL; break; + } + break; + + default: + break; + } + return 0; +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_audio20_device_feedback_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running Audio 2.0 Device Feedback Functionality Test................ "); +#if !UX_TEST_MULTI_IFC_ON || !UX_TEST_MULTI_ALT_ON || !UX_TEST_MULTI_CLS_ON || !UX_TEST_MULTI_EP_OVER(4) ||\ + !defined(UX_DEVICE_BIDIRECTIONAL_ENDPOINT_SUPPORT) ||\ + (UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH < (247 + 14)) + printf("SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + stepinfo("\n"); + + /* 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(); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* 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_host_change_function); + UX_TEST_CHECK_SUCCESS(status); + + /* Register Audio class. */ + status = ux_host_stack_class_register(_ux_host_class_dummy_name, _ux_host_class_dummy_entry); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Set the parameters for callback when insertion/extraction of a Audio 2.0 device, no IAD. */ + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_thread_entry = ux_device_class_audio_write_thread_entry; + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_change = slave_audio_tx_stream_change; + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_frame_done = slave_audio_tx_done; + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_max_frame_buffer_size = 256; + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_max_frame_buffer_nb = 8; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_thread_entry = ux_device_class_audio_read_thread_entry; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_change = slave_audio_rx_stream_change; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_frame_done = slave_audio_rx_done; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_max_frame_buffer_size = 256; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_max_frame_buffer_nb = 8; + slave_audio_parameter.ux_device_class_audio_parameter_streams = slave_audio_stream_parameter; + slave_audio_parameter.ux_device_class_audio_parameter_streams_nb = 2; + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_slave_class_audio_instance_activate = slave_audio_activate; + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_slave_class_audio_instance_deactivate = slave_audio_deactivate; + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_device_class_audio_control_process = slave_audio_control_process; + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_device_class_audio_arg = UX_NULL; + +#if defined(UX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT) + slave_audio_parameter.ux_device_class_audio_parameter_status_queue_size = 2; + slave_audio_parameter.ux_device_class_audio_parameter_status_size = 6; +#endif + + g_slave_audio20_control[0].ux_device_class_audio20_control_cs_id = 0x10; + g_slave_audio20_control[0].ux_device_class_audio20_control_sampling_frequency = 48000; + g_slave_audio20_control[0].ux_device_class_audio20_control_fu_id = 2; + g_slave_audio20_control[0].ux_device_class_audio20_control_mute[0] = 0; + g_slave_audio20_control[0].ux_device_class_audio20_control_volume[0] = 0; + g_slave_audio20_control[1].ux_device_class_audio20_control_cs_id = 0x10; + g_slave_audio20_control[1].ux_device_class_audio20_control_sampling_frequency = 48000; + g_slave_audio20_control[1].ux_device_class_audio20_control_fu_id = 5; + g_slave_audio20_control[1].ux_device_class_audio20_control_mute[0] = 0; + g_slave_audio20_control[1].ux_device_class_audio20_control_volume[0] = 0; + + /* Initialize the device Audio class. This class owns interfaces starting with 0, 1, 2. */ + status = ux_device_stack_class_register(_ux_system_slave_class_audio_name, ux_device_class_audio_entry, + 1, 0, &slave_audio_parameter); + UX_TEST_CHECK_SUCCESS(status); + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx demo host simulation", tx_test_thread_host_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx demo slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_CHECK_SUCCESS(status); +} + +static UINT test_wait_until_expected(VOID **ptr, ULONG loop, VOID *expected) +{ + while(loop) + { + _ux_utility_delay_ms(10); + if (*ptr == expected) + return UX_SUCCESS; + } + return UX_ERROR; +} +static UINT test_wait_until_not_expected(VOID **ptr, ULONG loop, VOID *expected) +{ + while(loop) + { + _ux_utility_delay_ms(10); + if (*ptr != expected) + return UX_SUCCESS; + } + return UX_ERROR; +} +#define test_wait_until_not_null(ptr, loop) test_wait_until_not_expected(ptr, loop, UX_NULL) +#define test_wait_until_null(ptr, loop) test_wait_until_expected(ptr, loop, UX_NULL) + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +UX_INTERFACE *interface_inst[3][2]; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UCHAR test_tmp[32]; +ULONG temp; + + + /* Test connect. */ + status = test_wait_until_not_null((void**)&dummy_control, 100); + status |= test_wait_until_not_null((void**)&dummy_tx, 100); + status |= test_wait_until_not_null((void**)&dummy_rx, 100); + status |= test_wait_until_not_null((void**)&slave_audio_tx_stream, 100); + status |= test_wait_until_not_null((void**)&slave_audio_rx_stream, 100); + UX_TEST_CHECK_SUCCESS(status); + + /* Get testing instances. */ + + status = ux_host_stack_device_get(0, &device); + UX_TEST_CHECK_SUCCESS(status); + + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + status = ux_host_stack_device_configuration_get(device, 0, &configuration); + UX_TEST_CHECK_SUCCESS(status); + + interface = configuration -> ux_configuration_first_interface; + while(interface) + { + // printf("Interface: %ld.%ld\n", interface -> ux_interface_descriptor.bInterfaceNumber, interface -> ux_interface_descriptor.bAlternateSetting); + interface_inst[interface -> ux_interface_descriptor.bInterfaceNumber][interface -> ux_interface_descriptor.bAlternateSetting] = interface; + interface = interface -> ux_interface_next_interface; + } + + ux_test_link_hooks_from_array(ux_device_class_audio_transfer_hook); + + /* Test interface change. */ + /* Reset log. */ + RESET_CALLBACK_INVOKE_LOG(); + status = ux_host_stack_interface_setting_select(interface_inst[1][1]); + status |= ux_host_stack_interface_setting_select(interface_inst[1][0]); + status |= ux_host_stack_interface_setting_select(interface_inst[1][1]); + + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(callback_invoke_count == 3); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_tx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_tx_stream); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (VOID*)1); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_tx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_tx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].param2 == 0); + + RESET_CALLBACK_INVOKE_LOG(); + status = ux_host_stack_interface_setting_select(interface_inst[2][1]); + status |= ux_host_stack_interface_setting_select(interface_inst[2][0]); + status |= ux_host_stack_interface_setting_select(interface_inst[2][1]); + + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(callback_invoke_count == 3); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_rx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (VOID*)1); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_rx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].param2 == 0); + + /**************************************************************************/ + + /* Control requests test. */ + + transfer_request -> ux_transfer_request_data_pointer = buffer; + + test_tmp[0] = 2; + test_tmp[1] = 5; + + for (test_n = 0; test_n < 2; test_n ++) + { + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_AUDIO20_CUR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + + /* Issue SetFeatureMute(test_tmp[test_n], 0). */ + transfer_request -> ux_transfer_request_requested_length = 1; + transfer_request -> ux_transfer_request_index = (test_tmp[test_n] << 8) | 0; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO20_FU_MUTE_CONTROL << 8) | 0; + buffer[0] = 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_changed == 0); + + /* Issue SetFeatureMute(test_tmp[test_n], 1). */ + buffer[0] = 1; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_MUTE_CHANGED); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_mute[0] == 1); + + /* Issue SetFeatureMute(test_tmp[test_n], 0). */ + buffer[0] = 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_MUTE_CHANGED); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_mute[0] == 0); + + /* Issue SetFeatureMute(test_tmp[test_n], 1). */ + buffer[0] = 1; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_MUTE_CHANGED); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_mute[0] == 1); + + /* Issue SetFeatureVolume(test_tmp[test_n], 0x0003). */ + transfer_request -> ux_transfer_request_requested_length = 2; + transfer_request -> ux_transfer_request_index = (test_tmp[test_n] << 8) | 0; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO20_FU_VOLUME_CONTROL << 8) | 0; + buffer[0] = 3; buffer[1] = 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_VOLUME_CHANGED); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_volume[0] == 0x0003); + + /* Issue SetFeatureVolume(test_tmp[test_n], 0x0103). */ + buffer[1] = 1; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_VOLUME_CHANGED); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_volume[0] == 0x0103); + + /* Issue SetFeatureVolume(test_tmp[test_n], 0x0103). */ + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_changed == 0); + + /* Issue GetFeatureMute(test_tmp[test_n]). */ + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_AUDIO20_CUR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + + transfer_request -> ux_transfer_request_requested_length = 1; + transfer_request -> ux_transfer_request_index = (test_tmp[test_n] << 8) | 0; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO20_FU_MUTE_CONTROL << 8) | 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(transfer_request -> ux_transfer_request_actual_length == 1); + UX_TEST_ASSERT(buffer[0] == 1); + + /* Issue GetFeatureMute(test_tmp[test_n]). */ + transfer_request -> ux_transfer_request_requested_length = 2; + transfer_request -> ux_transfer_request_index = (test_tmp[test_n] << 8) | 0; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO20_FU_VOLUME_CONTROL << 8) | 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(transfer_request -> ux_transfer_request_actual_length == 2); + UX_TEST_ASSERT(buffer[0] == 3); + UX_TEST_ASSERT(buffer[1] == 1); + + /* Issue GetClockSamplingFrequency(0x10). */ + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_AUDIO20_CUR; + transfer_request -> ux_transfer_request_requested_length = 4; + transfer_request -> ux_transfer_request_index = (0x10 << 8) | 0; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO20_CS_SAM_FREQ_CONTROL << 8) | 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(transfer_request -> ux_transfer_request_actual_length == 4); + UX_TEST_ASSERT(buffer[0] == D0(48000)); + UX_TEST_ASSERT(buffer[1] == D1(48000)); + UX_TEST_ASSERT(buffer[2] == D2(48000)); + UX_TEST_ASSERT(buffer[3] == D3(48000)); + + /* Issue GetClockSamplingFrequencyRange(0x10). */ + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_AUDIO20_RANGE; + transfer_request -> ux_transfer_request_requested_length = 14; + transfer_request -> ux_transfer_request_index = (0x10 << 8) | 0; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO20_CS_SAM_FREQ_CONTROL << 8) | 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(transfer_request -> ux_transfer_request_actual_length == 14); + UX_TEST_ASSERT(buffer[ 0] == D0(1)); + UX_TEST_ASSERT(buffer[ 1] == D1(1)); + UX_TEST_ASSERT(buffer[ 2] == D0(48000)); + UX_TEST_ASSERT(buffer[ 3] == D1(48000)); + UX_TEST_ASSERT(buffer[ 4] == D2(48000)); + UX_TEST_ASSERT(buffer[ 5] == D3(48000)); + UX_TEST_ASSERT(buffer[ 6] == D0(48000)); + UX_TEST_ASSERT(buffer[ 7] == D1(48000)); + UX_TEST_ASSERT(buffer[ 8] == D2(48000)); + UX_TEST_ASSERT(buffer[ 9] == D3(48000)); + } + + /* Issue SetClockSamplingFrequency(0x10) - STALL. */ + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_AUDIO20_CUR; + transfer_request -> ux_transfer_request_index = (0x10 << 8) | 0; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO20_CS_SAM_FREQ_CONTROL << 8) | 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_CODE(UX_TRANSFER_STALLED, status); + + /* Prepare new RANGE settings. */ + g_slave_audio20_control[0].ux_device_class_audio20_control_sampling_frequency = 0; + g_slave_audio20_control[0].ux_device_class_audio20_control_sampling_frequency_cur = 44100; + g_slave_audio20_control[0].ux_device_class_audio20_control_sampling_frequency_range = audio20_cs_range; + + /* Issue GetClockSamplingFrequency(0x10). */ + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_AUDIO20_CUR; + transfer_request -> ux_transfer_request_requested_length = 4; + transfer_request -> ux_transfer_request_index = (0x10 << 8) | 0; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO20_CS_SAM_FREQ_CONTROL << 8) | 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(transfer_request -> ux_transfer_request_actual_length == 4); + UX_TEST_ASSERT(buffer[0] == D0(44100)); + UX_TEST_ASSERT(buffer[1] == D1(44100)); + UX_TEST_ASSERT(buffer[2] == D2(44100)); + UX_TEST_ASSERT(buffer[3] == D3(44100)); + + /* Issue GetClockSamplingFrequencyRange(0x10). */ + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_AUDIO20_RANGE; + transfer_request -> ux_transfer_request_requested_length = 14; + transfer_request -> ux_transfer_request_index = (0x10 << 8) | 0; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO20_CS_SAM_FREQ_CONTROL << 8) | 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(transfer_request -> ux_transfer_request_actual_length == sizeof(audio20_cs_range)); + UX_TEST_ASSERT(buffer[ 0] == D0(2)); + UX_TEST_ASSERT(buffer[ 1] == D1(2)); + UX_TEST_ASSERT(buffer[ 2] == D0(44100)); + UX_TEST_ASSERT(buffer[ 3] == D1(44100)); + UX_TEST_ASSERT(buffer[ 4] == D2(44100)); + UX_TEST_ASSERT(buffer[ 5] == D3(44100)); + UX_TEST_ASSERT(buffer[ 6] == D0(44100)); + UX_TEST_ASSERT(buffer[ 7] == D1(44100)); + UX_TEST_ASSERT(buffer[ 8] == D2(44100)); + UX_TEST_ASSERT(buffer[ 9] == D3(44100)); + UX_TEST_ASSERT(UX_SUCCESS == ux_utility_memory_compare(audio20_cs_range, buffer, sizeof(audio20_cs_range))); + + /* Issue SetClockSamplingFrequency(0x10) - STALL. */ + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_AUDIO20_CUR; + transfer_request -> ux_transfer_request_index = (0x10 << 8) | 0; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO20_CS_SAM_FREQ_CONTROL << 8) | 0; + ux_utility_long_put(transfer_request -> ux_transfer_request_data_pointer, 64000); + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_CODE(UX_TRANSFER_STALLED, status); + + /* Issue SetClockSamplingFrequency(0x10) - OK. */ + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_AUDIO20_CUR; + transfer_request -> ux_transfer_request_index = (0x10 << 8) | 0; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO20_CS_SAM_FREQ_CONTROL << 8) | 0; + ux_utility_long_put(transfer_request -> ux_transfer_request_data_pointer, 48000); + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio20_control[0].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_FREQUENCY_CHANGED); + UX_TEST_ASSERT(g_slave_audio20_control[0].ux_device_class_audio20_control_sampling_frequency_cur == 48000); + + /* Issue GetClockSamplingFrequency(0x10) - OK. */ + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_AUDIO20_CUR; + transfer_request -> ux_transfer_request_index = (0x10 << 8) | 0; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO20_CS_SAM_FREQ_CONTROL << 8) | 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(transfer_request -> ux_transfer_request_actual_length == 4); + UX_TEST_ASSERT(buffer[0] == D0(48000)); + UX_TEST_ASSERT(buffer[1] == D1(48000)); + UX_TEST_ASSERT(buffer[2] == D2(48000)); + UX_TEST_ASSERT(buffer[3] == D3(48000)); + + /* Wait pending threads. */ + _ux_utility_thread_sleep(1); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + ux_device_stack_class_unregister(_ux_system_slave_class_audio_name, ux_device_class_audio_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + while(1) + { + + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); + } +} diff --git a/test/regression/usbx_audio20_device_feedback_test.c b/test/regression/usbx_audio20_device_feedback_test.c new file mode 100644 index 00000000..37887f5b --- /dev/null +++ b/test/regression/usbx_audio20_device_feedback_test.c @@ -0,0 +1,1517 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" + +#include "fx_api.h" + +#include "ux_device_class_audio.h" +#include "ux_device_class_audio20.h" +#include "ux_device_stack.h" + +#include "ux_host_class_audio.h" +#include "ux_host_class_dummy.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_DEMO_REQUEST_MAX_LENGTH \ + ((UX_HCD_SIM_HOST_MAX_PAYLOAD) > (UX_SLAVE_REQUEST_DATA_MAX_LENGTH) ? \ + (UX_HCD_SIM_HOST_MAX_PAYLOAD) : (UX_SLAVE_REQUEST_DATA_MAX_LENGTH)) + +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_DEMO_REQUEST_MAX_LENGTH + 1) +#define UX_DEMO_MEMORY_SIZE (128*1024) + +#define UX_TEST_LOG_SIZE (64) + + +/* Define local/extern function prototypes. */ +static void test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static void tx_test_thread_host_simulation_entry(ULONG); +static void tx_test_thread_slave_simulation_entry(ULONG); + + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[64]; + +static UX_HOST_CLASS_DUMMY *dummy_control; +static UX_HOST_CLASS_DUMMY *dummy_tx; +static UX_HOST_CLASS_DUMMY *dummy_rx; + +static UX_DEVICE_CLASS_AUDIO *slave_audio; +static UX_DEVICE_CLASS_AUDIO_PARAMETER slave_audio_parameter; +static UX_DEVICE_CLASS_AUDIO_STREAM_PARAMETER slave_audio_stream_parameter[2]; + +static UX_DEVICE_CLASS_AUDIO_STREAM *slave_audio_tx_stream; + +static UX_DEVICE_CLASS_AUDIO_STREAM *slave_audio_rx_stream; +static UX_SLAVE_TRANSFER *slave_audio_rx_transfer; + +static ULONG device_audio_tx_feedback; +static UCHAR* device_audio_tx_feedback_u8a = (UCHAR*)&device_audio_tx_feedback; +static ULONG device_audio_tx_feedback_count; +static ULONG device_audio_rx_feedback; +static UCHAR* device_audio_rx_feedback_u8a = (UCHAR*)&device_audio_rx_feedback; +static ULONG device_audio_rx_feedback_count; + + +static UX_HOST_CLASS_AUDIO *audio; + +static UX_DEVICE_CLASS_AUDIO20_CONTROL g_slave_audio20_control[2]; + +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_audio_sem_usage; +static ULONG rsc_audio_sem_get_count; +static ULONG rsc_audio_mutex_usage; +static ULONG rsc_audio_mem_usage; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +static struct BUFFER_LOG_STRUCT { + ULONG length; + UCHAR data[256]; +} buffer_log[UX_TEST_LOG_SIZE]; +static ULONG buffer_log_count = 0; +#define SAVE_BUFFER_LOG(buf,siz) do { \ + if (buffer_log_count < UX_TEST_LOG_SIZE) { \ + ULONG __local_size__ = ((siz) > 256) ? 256 : (siz); \ + buffer_log[buffer_log_count].length = (siz); \ + _ux_utility_memory_copy(buffer_log[buffer_log_count].data, (buf), __local_size__); \ + } \ + buffer_log_count ++; \ +} while(0) + +static ULONG test_tx_ack_count = 0xFFFFFFFF; +static ULONG test_tx_ins_count = 0; +static ULONG test_tx_ins_way = 0; + +static struct CALLBACK_INVOKE_LOG_STRUCT { + VOID *func; + VOID *param1; + VOID *param2; + VOID *param3; +} callback_invoke_log[UX_TEST_LOG_SIZE]; +static ULONG callback_invoke_count = 0; + +#define SAVE_CALLBACK_INVOKE_LOG(f,p1,p2,p3) do { \ + if (callback_invoke_count < UX_TEST_LOG_SIZE) { \ + callback_invoke_log[callback_invoke_count].func = (VOID *)(f); \ + callback_invoke_log[callback_invoke_count].param1 = (VOID *)(p1); \ + callback_invoke_log[callback_invoke_count].param2 = (VOID *)(p2); \ + callback_invoke_log[callback_invoke_count].param3 = (VOID *)(p3); \ + callback_invoke_count++; \ + } \ +} while(0) +#define RESET_CALLBACK_INVOKE_LOG() do { \ + callback_invoke_count = 0; \ +} while(0) + +/* Define device framework. */ + +#define D3(d) ((UCHAR)((d) >> 24)) +#define D2(d) ((UCHAR)((d) >> 16)) +#define D1(d) ((UCHAR)((d) >> 8)) +#define D0(d) ((UCHAR)((d) >> 0)) + +static unsigned char device_framework_full_speed[] = { + +/* --------------------------------------- Device Descriptor */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x02, 0x00, +/* 12 bcdDevice */ D0(0x200),D1(0x200), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* ----------------------------- Device Qualifier Descriptor */ +/* 0 bLength, bDescriptorType */ 10, 0x06, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 bNumConfigurations */ 1, +/* 9 bReserved */ 0, + +/* -------------------------------- Configuration Descriptor *//* 9+8+120+55*2=247 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(247+14),D1(247+14), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------ Interface Association Descriptor */ +/* 0 bLength, bDescriptorType */ 8, 0x0B, +/* 2 bFirstInterface, bInterfaceCount */ 0, 3, +/* 4 bFunctionClass, bFunctionSubClass, bFunctionProtocol */ 0x01, 0x00, 0x20, +/* 7 iFunction */ 0, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+111=120) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x20, +/* 8 iInterface */ 0, +/* ---------------- Audio 2.0 AC Interface Header Descriptor *//* (9+8+17*2+18*2+12*2=111) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x01, +/* 3 bcdADC, bCategory */ D0(0x200),D1(0x200), 0x08, +/* 6 wTotalLength */ D0(111),D1(111), +/* 8 bmControls */ 0x00, +/* -------------------- Audio 2.0 AC Clock Source Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x24, 0x0A, +/* 3 bClockID, bmAttributes, bmControls */ 0x10, 0x05, 0x01, +/* 6 bAssocTerminal, iClockSource */ 0x00, 0, +/* ------------------- Audio 2.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 17, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, bCSourceID */ 0x00, 0x10, +/* 8 bNrChannels, bmChannelConfig */ 0x02, D0(0),D1(0),D2(0),D3(0), +/* 13 iChannelNames, bmControls, iTerminal */ 0, D0(0),D1(0), 0, +/* --------------------- Audio 2.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 18, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bmaControls(0), bmaControls(...) ... */ D0(0xF),D1(0xF),D2(0xF),D3(0xF), D0(0),D1(0),D2(0),D3(0), D0(0),D1(0),D2(0),D3(0), +/* . iFeature */ 0, +/* ------------------ Audio 2.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID, bCSourceID */ 0x00, 0x02, 0x10, +/* 9 bmControls, iTerminal */ D0(0),D1(0), 0, +/* ------------------- Audio 2.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 17, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bCSourceID */ 0x00, 0x10, +/* 8 bNrChannels, bmChannelConfig */ 0x02, D0(0),D1(0),D2(0),D3(0), +/* 13 iChannelNames, bmControls, iTerminal */ 0, D0(0),D1(0), 0, +/* --------------------- Audio 2.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 18, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bmaControls(0), bmaControls(...) ... */ D0(0xF),D1(0xF),D2(0xF),D3(0xF), D0(0),D1(0),D2(0),D3(0), D0(0),D1(0),D2(0),D3(0), +/* . iFeature */ 0, +/* ------------------ Audio 2.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID, bCSourceID */ 0x00, 0x05, 0x10, +/* 9 bmControls, iTerminal */ D0(0),D1(0), 0, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+16+6+7+8=55) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 2, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------ Audio 2.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 16, 0x24, 0x01, +/* 3 bTerminalLink, bmControls */ 0x03,0x00, +/* 5 bFormatType, bmFormats */ 0x01,D0(1),D1(1),D2(1),D3(1), +/* 10 bNrChannels, bmChannelConfig */ 2, D0(0),D1(0),D2(0),D3(0), +/* 15 iChannelNames */ 0, +/* -------------------- Audio 2.0 AS Format Type I Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 6, 0x24, 0x02, +/* 3 bFormatType, bSubslotSize, bBitResolution */ 0x01, 2, 16, +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x0D, +/* 4 wMaxPacketSize, bInterval */ D0(256),D1(256), 1, +/* ---------- Audio 2.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x25, 0x01, +/* 3 bmAttributes, bmControls */ 0x00, 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x01, 0x11, +/* 4 wMaxPacketSize, bInterval */ D0(4),D1(4), 1, + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+16+6+7+8=55) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 2, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------ Audio 2.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 16, 0x24, 0x01, +/* 3 bTerminalLink, bmControls */ 0x04,0x00, +/* 5 bFormatType, bmFormats */ 0x01,D0(1),D1(1),D2(1),D3(1), +/* 10 bNrChannels, bmChannelConfig */ 2, D0(0),D1(0),D2(0),D3(0), +/* 15 iChannelNames */ 0, +/* ---------------------- Audio 2.0 AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 6, 0x24, 0x02, +/* 3 bFormatType, bSubslotSize, bBitResolution */ 0x01, 2, 16, +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x0D, +/* 4 wMaxPacketSize, bInterval */ D0(256),D1(256), 1, +/* ---------- Audio 2.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x25, 0x01, +/* 3 bmAttributes, bmControls */ 0x00, 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x82, 0x11, +/* 4 wMaxPacketSize, bInterval */ D0(4),D1(4), 1, + +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { +/* --------------------------------------- Device Descriptor */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 0x08, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x02, 0x00, +/* 12 bcdDevice */ D0(0x200),D1(0x200), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* ----------------------------- Device Qualifier Descriptor */ +/* 0 bLength, bDescriptorType */ 10, 0x06, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 bNumConfigurations */ 1, +/* 9 bReserved */ 0, + +/* -------------------------------- Configuration Descriptor *//* 9+8+120+55*2=247 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(247+14),D1(247+14), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------ Interface Association Descriptor */ +/* 0 bLength, bDescriptorType */ 8, 0x0B, +/* 2 bFirstInterface, bInterfaceCount */ 0, 3, +/* 4 bFunctionClass, bFunctionSubClass, bFunctionProtocol */ 0x01, 0x00, 0x20, +/* 7 iFunction */ 0, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+111=120) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x20, +/* 8 iInterface */ 0, +/* ---------------- Audio 2.0 AC Interface Header Descriptor *//* (9+8+17*2+18*2+12*2=111) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x01, +/* 3 bcdADC, bCategory */ D0(0x200),D1(0x200), 0x08, +/* 6 wTotalLength */ D0(111),D1(111), +/* 8 bmControls */ 0x00, +/* -------------------- Audio 2.0 AC Clock Source Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x24, 0x0A, +/* 3 bClockID, bmAttributes, bmControls */ 0x10, 0x05, 0x01, +/* 6 bAssocTerminal, iClockSource */ 0x00, 0, +/* ------------------- Audio 2.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 17, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, bCSourceID */ 0x00, 0x10, +/* 8 bNrChannels, bmChannelConfig */ 0x02, D0(0),D1(0),D2(0),D3(0), +/* 13 iChannelNames, bmControls, iTerminal */ 0, D0(0),D1(0), 0, +/* --------------------- Audio 2.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 18, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bmaControls(0), bmaControls(...) ... */ D0(0xF),D1(0xF),D2(0xF),D3(0xF), D0(0),D1(0),D2(0),D3(0), D0(0),D1(0),D2(0),D3(0), +/* . iFeature */ 0, +/* ------------------ Audio 2.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID, bCSourceID */ 0x00, 0x02, 0x10, +/* 9 bmControls, iTerminal */ D0(0),D1(0), 0, +/* ------------------- Audio 2.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 17, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bCSourceID */ 0x00, 0x10, +/* 8 bNrChannels, bmChannelConfig */ 0x02, D0(0),D1(0),D2(0),D3(0), +/* 13 iChannelNames, bmControls, iTerminal */ 0, D0(0),D1(0), 0, +/* --------------------- Audio 2.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 18, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bmaControls(0), bmaControls(...) ... */ D0(0xF),D1(0xF),D2(0xF),D3(0xF), D0(0),D1(0),D2(0),D3(0), D0(0),D1(0),D2(0),D3(0), +/* . iFeature */ 0, +/* ------------------ Audio 2.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID, bCSourceID */ 0x00, 0x05, 0x10, +/* 9 bmControls, iTerminal */ D0(0),D1(0), 0, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+16+6+7+8=55) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 2, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------ Audio 2.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 16, 0x24, 0x01, +/* 3 bTerminalLink, bmControls */ 0x03,0x00, +/* 5 bFormatType, bmFormats */ 0x01,D0(1),D1(1),D2(1),D3(1), +/* 10 bNrChannels, bmChannelConfig */ 2, D0(0),D1(0),D2(0),D3(0), +/* 15 iChannelNames */ 0, +/* -------------------- Audio 2.0 AS Format Type I Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 6, 0x24, 0x02, +/* 3 bFormatType, bSubslotSize, bBitResolution */ 0x01, 2, 16, +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x0D, +/* 4 wMaxPacketSize, bInterval */ D0(256),D1(256), 4, +/* ---------- Audio 2.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x25, 0x01, +/* 3 bmAttributes, bmControls */ 0x00, 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x01, 0x11, +/* 4 wMaxPacketSize, bInterval */ D0(4),D1(4), 1, + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+16+6+7+8=55) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 2, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------ Audio 2.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 16, 0x24, 0x01, +/* 3 bTerminalLink, bmControls */ 0x04,0x00, +/* 5 bFormatType, bmFormats */ 0x01,D0(1),D1(1),D2(1),D3(1), +/* 10 bNrChannels, bmChannelConfig */ 2, D0(0),D1(0),D2(0),D3(0), +/* 15 iChannelNames */ 0, +/* ---------------------- Audio 2.0 AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 6, 0x24, 0x02, +/* 3 bFormatType, bSubslotSize, bBitResolution */ 0x01, 2, 16, +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x0D, +/* 4 wMaxPacketSize, bInterval */ D0(256),D1(256), 4, +/* ---------- Audio 2.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x25, 0x01, +/* 3 bmAttributes, bmControls */ 0x00, 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x82, 0x11, +/* 4 wMaxPacketSize, bInterval */ D0(4),D1(4), 1, + +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + +/* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + +/* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + +/* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; +static UX_TEST_SETUP _GetCfgDescr = UX_TEST_SETUP_GetCfgDescr; +static UX_TEST_SETUP _SetAddress = UX_TEST_SETUP_SetAddress; +static UX_TEST_SETUP _GetDeviceDescriptor = UX_TEST_SETUP_GetDevDescr; +static UX_TEST_SETUP _GetConfigDescriptor = UX_TEST_SETUP_GetCfgDescr; + +/* Interaction define */ + +/* Hooks define */ + +static VOID ux_device_class_audio_tx_hook(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *p = (UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *)params; +UX_SLAVE_TRANSFER *transfer = (UX_SLAVE_TRANSFER *)p -> parameter; +UCHAR tmp[32] = {'i','n','s','e','r','t','A',0}; + + + (void)params; + // printf("tTX\n"); + + /* Acknowledge frame sent. */ + if (test_tx_ack_count) + { + SAVE_BUFFER_LOG(transfer -> ux_slave_transfer_request_data_pointer, transfer -> ux_slave_transfer_request_requested_length); + transfer -> ux_slave_transfer_request_actual_length = transfer -> ux_slave_transfer_request_requested_length; + transfer -> ux_slave_transfer_request_completion_code = UX_SUCCESS; + ux_test_dcd_sim_slave_transfer_done(transfer, UX_SUCCESS); + } + if (test_tx_ack_count != 0xFFFFFFFF && test_tx_ack_count > 0) + test_tx_ack_count --; + + /* Insert frames when sent. */ + if (test_tx_ins_count) + { + tmp[6] = (test_tx_ins_count % 26) + 'A'; + if (test_tx_ins_way == 0) + ux_device_class_audio_frame_write(slave_audio_tx_stream, tmp, 32); + else + { + + UCHAR *frame; + ULONG frame_length; + + + ux_device_class_audio_write_frame_get(slave_audio_tx_stream, &frame, &frame_length); + _ux_utility_memory_copy(frame, tmp, 32); + ux_device_class_audio_write_frame_commit(slave_audio_tx_stream, 32); + } + } + if (test_tx_ins_count != 0xFFFFFFFF && test_tx_ins_count > 0) + test_tx_ins_count --; +} + +static VOID ux_device_class_audio_rx_hook(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *p = (UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *)params; +UX_SLAVE_TRANSFER *transfer = (UX_SLAVE_TRANSFER *)p -> parameter; + + + (void)action; + (void)params; + (void)p; + (void)transfer; + // printf("tRX\n"); + slave_audio_rx_transfer = transfer; +} + +static VOID ux_device_class_audio_feedback_hook(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *p = (UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *)params; +UX_SLAVE_TRANSFER *transfer = (UX_SLAVE_TRANSFER *)p -> parameter; +ULONG length; + + (void)action; + (void)params; + (void)p; + (void)transfer; + length = UX_MIN(4, transfer->ux_slave_transfer_request_requested_length); + if (transfer->ux_slave_transfer_request_endpoint->ux_slave_endpoint_descriptor.bEndpointAddress & 0x80) + { + device_audio_rx_feedback_count ++; + /* IN for OUT(RX/read) feedback. */ + device_audio_rx_feedback = 0; + _ux_utility_memory_copy(device_audio_rx_feedback_u8a, + transfer->ux_slave_transfer_request_data_pointer, length); + transfer -> ux_slave_transfer_request_completion_code = UX_SUCCESS; + transfer -> ux_slave_transfer_request_actual_length = length; + } + else + { + device_audio_tx_feedback_count ++; + /* OUT for IN(TX/write) feedback. */ + _ux_utility_memory_copy(transfer->ux_slave_transfer_request_data_pointer, + device_audio_tx_feedback_u8a, length); + transfer -> ux_slave_transfer_request_completion_code = UX_SUCCESS; + transfer -> ux_slave_transfer_request_actual_length = length; + } + ux_test_dcd_sim_slave_transfer_done(transfer, UX_SUCCESS); + _ux_utility_thread_sleep(1); +} + +static VOID slave_audio_rx_simulate_one_frame(UCHAR *frame, ULONG frame_length) +{ + UX_TEST_ASSERT(slave_audio_rx_transfer); + if (frame_length) + { + _ux_utility_memory_copy(slave_audio_rx_transfer->ux_slave_transfer_request_data_pointer, frame, frame_length); + slave_audio_rx_transfer->ux_slave_transfer_request_actual_length = frame_length; + slave_audio_rx_transfer->ux_slave_transfer_request_completion_code = UX_SUCCESS; + } + ux_test_dcd_sim_slave_transfer_done(slave_audio_rx_transfer, UX_SUCCESS); + _ux_utility_delay_ms(100); +} + +static UX_TEST_ACTION ux_device_class_audio_transfer_hook[] = +{ + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .action_func = ux_device_class_audio_tx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x81, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .action_func = ux_device_class_audio_rx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x02, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .action_func = ux_device_class_audio_feedback_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x82, + .req_status = UX_SUCCESS, + .status = UX_SUCCESS, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .action_func = ux_device_class_audio_feedback_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x01, + .req_status = UX_SUCCESS, + .status = UX_SUCCESS, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, +{ 0 }, +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* 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 ++; + // printf("Error #%d, system_level: %d, system_context: %d, error_code: 0x%x\n", __LINE__, system_level, system_context, error_code); + + if (!error_callback_ignore) + { + { + /* Failed test. */ + 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 VOID slave_audio_activate(VOID *audio_instance) +{ + slave_audio = (UX_DEVICE_CLASS_AUDIO *)audio_instance; + ux_device_class_audio_stream_get(slave_audio, 0, &slave_audio_tx_stream); + ux_device_class_audio_stream_get(slave_audio, 1, &slave_audio_rx_stream); + // printf("sAUD:%p;%p,%p\n", audio_instance, slave_audio_tx_stream, slave_audio_rx_stream); +} +static VOID slave_audio_deactivate(VOID *audio_instance) +{ + if ((VOID *)slave_audio == audio_instance) + { + slave_audio = UX_NULL; + slave_audio_tx_stream = UX_NULL; + slave_audio_rx_stream = UX_NULL; + } +} +static VOID slave_audio_tx_stream_change(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG alt) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_tx_stream_change, audio, (ALIGN_TYPE)alt, 0); +} +static VOID slave_audio_rx_stream_change(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG alt) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_rx_stream_change, audio, (ALIGN_TYPE)alt, 0); + + slave_audio_rx_transfer = UX_NULL; +} +static UINT slave_audio_control_process(UX_DEVICE_CLASS_AUDIO *audio, UX_SLAVE_TRANSFER *transfer) +{ + + +UINT status; +UX_DEVICE_CLASS_AUDIO20_CONTROL_GROUP group = + {2, g_slave_audio20_control}; + + + SAVE_CALLBACK_INVOKE_LOG(slave_audio_control_process, audio, transfer, 0); + + status = ux_device_class_audio20_control_process(audio, transfer, &group); + if (status == UX_SUCCESS) + { + if (g_slave_audio20_control[0].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_MUTE_CHANGED) + { + /* Mute change! */ + } + if (g_slave_audio20_control[0].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_VOLUME_CHANGED) + { + /* Volume change! */ + } + if (g_slave_audio20_control[1].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_MUTE_CHANGED) + { + /* Mute change! */ + } + if (g_slave_audio20_control[1].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_VOLUME_CHANGED) + { + /* Volume change! */ + } + } + return(status); +} +static VOID slave_audio_tx_done(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG length) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_tx_done, audio, (ALIGN_TYPE)length, 0); +} +static VOID slave_audio_rx_done(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG length) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_rx_done, audio, (ALIGN_TYPE)length, 0); +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_DUMMY *dummy = (UX_HOST_CLASS_DUMMY *) inst; + + + switch(event) + { + + case UX_DEVICE_INSERTION: + + // printf("hINS:%p,%p:%ld\n", cls, inst, dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber); + switch(dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber) + { + case 0: dummy_control = dummy; break; + case 1: dummy_rx = dummy; break; + case 2: dummy_tx = dummy; break; + } + break; + + case UX_DEVICE_REMOVAL: + + // printf("hRMV:%p,%p:%ld\n", cls, inst, dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber); + switch(dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber) + { + case 0: dummy_control = UX_NULL; break; + case 1: dummy_rx = UX_NULL; break; + case 2: dummy_tx = UX_NULL; break; + } + break; + + default: + break; + } + return 0; +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_audio20_device_feedback_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running Audio 2.0 Device Feedback Functionality Test................ "); +#if !UX_TEST_MULTI_IFC_ON || !UX_TEST_MULTI_ALT_ON || !UX_TEST_MULTI_CLS_ON || !UX_TEST_MULTI_EP_OVER(4) ||\ + !defined(UX_DEVICE_BIDIRECTIONAL_ENDPOINT_SUPPORT) ||\ + (UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH < (247 + 14)) + printf("SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + stepinfo("\n"); + + /* 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(); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* 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_host_change_function); + UX_TEST_CHECK_SUCCESS(status); + + /* Register Audio class. */ + status = ux_host_stack_class_register(_ux_host_class_dummy_name, _ux_host_class_dummy_entry); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Set the parameters for callback when insertion/extraction of a Audio 2.0 device, no IAD. */ +#if !defined(UX_DEVICE_STANDALONE) + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_thread_entry = ux_device_class_audio_write_thread_entry; +#else + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_task_function = ux_device_class_audio_write_task_function; +#endif + +#if defined(UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT) +#if !defined(UX_DEVICE_STANDALONE) + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_feedback_thread_entry = ux_device_class_audio_feedback_thread_entry; +#else + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_feedback_task_function = _ux_device_class_audio_feedback_task_function; +#endif +#endif + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_change = slave_audio_tx_stream_change; + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_frame_done = slave_audio_tx_done; + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_max_frame_buffer_size = 256; + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_max_frame_buffer_nb = 8; +#if !defined(UX_DEVICE_STANDALONE) + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_thread_entry = ux_device_class_audio_read_thread_entry; +#else + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_task_function = ux_device_class_audio_read_task_function; +#endif +#if defined(UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT) +#if !defined(UX_DEVICE_STANDALONE) + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_feedback_thread_entry = ux_device_class_audio_feedback_thread_entry; +#else + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_feedback_task_function = _ux_device_class_audio_feedback_task_function; +#endif +#endif + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_change = slave_audio_rx_stream_change; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_frame_done = slave_audio_rx_done; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_max_frame_buffer_size = 256; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_max_frame_buffer_nb = 8; + slave_audio_parameter.ux_device_class_audio_parameter_streams = slave_audio_stream_parameter; + slave_audio_parameter.ux_device_class_audio_parameter_streams_nb = 2; + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_slave_class_audio_instance_activate = slave_audio_activate; + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_slave_class_audio_instance_deactivate = slave_audio_deactivate; + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_device_class_audio_control_process = slave_audio_control_process; + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_device_class_audio_arg = UX_NULL; + +#if defined(UX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT) + slave_audio_parameter.ux_device_class_audio_parameter_status_queue_size = 2; + slave_audio_parameter.ux_device_class_audio_parameter_status_size = 6; +#endif + + g_slave_audio20_control[0].ux_device_class_audio20_control_cs_id = 0x10; + g_slave_audio20_control[0].ux_device_class_audio20_control_sampling_frequency = 48000; + g_slave_audio20_control[0].ux_device_class_audio20_control_fu_id = 2; + g_slave_audio20_control[0].ux_device_class_audio20_control_mute[0] = 0; + g_slave_audio20_control[0].ux_device_class_audio20_control_volume[0] = 0; + g_slave_audio20_control[1].ux_device_class_audio20_control_cs_id = 0x10; + g_slave_audio20_control[1].ux_device_class_audio20_control_sampling_frequency = 48000; + g_slave_audio20_control[1].ux_device_class_audio20_control_fu_id = 5; + g_slave_audio20_control[1].ux_device_class_audio20_control_mute[0] = 0; + g_slave_audio20_control[1].ux_device_class_audio20_control_volume[0] = 0; + + /* Initialize the device Audio class. This class owns interfaces starting with 0, 1, 2. */ + status = ux_device_stack_class_register(_ux_system_slave_class_audio_name, ux_device_class_audio_entry, + 1, 0, &slave_audio_parameter); + UX_TEST_CHECK_SUCCESS(status); + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx demo host simulation", tx_test_thread_host_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx demo slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_CHECK_SUCCESS(status); +} + +static UINT test_wait_until_expected(VOID **ptr, ULONG loop, VOID *expected) +{ + while(loop) + { + _ux_utility_delay_ms(10); + if (*ptr == expected) + return UX_SUCCESS; + } + return UX_ERROR; +} +static UINT test_wait_until_not_expected(VOID **ptr, ULONG loop, VOID *expected) +{ + while(loop) + { + _ux_utility_delay_ms(10); + if (*ptr != expected) + return UX_SUCCESS; + } + return UX_ERROR; +} +#define test_wait_until_not_null(ptr, loop) test_wait_until_not_expected(ptr, loop, UX_NULL) +#define test_wait_until_null(ptr, loop) test_wait_until_expected(ptr, loop, UX_NULL) + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +UX_INTERFACE *interface_inst[3][2]; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UCHAR test_tmp[32]; +ULONG temp; + + + /* Test connect. */ + status = test_wait_until_not_null((void**)&dummy_control, 100); + status |= test_wait_until_not_null((void**)&dummy_tx, 100); + status |= test_wait_until_not_null((void**)&dummy_rx, 100); + status |= test_wait_until_not_null((void**)&slave_audio_tx_stream, 100); + status |= test_wait_until_not_null((void**)&slave_audio_rx_stream, 100); + UX_TEST_CHECK_SUCCESS(status); + + /* Get testing instances. */ + + status = ux_host_stack_device_get(0, &device); + UX_TEST_CHECK_SUCCESS(status); + + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + status = ux_host_stack_device_configuration_get(device, 0, &configuration); + UX_TEST_CHECK_SUCCESS(status); + + interface = configuration -> ux_configuration_first_interface; + while(interface) + { + // printf("Interface: %ld.%ld\n", interface -> ux_interface_descriptor.bInterfaceNumber, interface -> ux_interface_descriptor.bAlternateSetting); + interface_inst[interface -> ux_interface_descriptor.bInterfaceNumber][interface -> ux_interface_descriptor.bAlternateSetting] = interface; + interface = interface -> ux_interface_next_interface; + } + + ux_test_link_hooks_from_array(ux_device_class_audio_transfer_hook); + + /* Test interface change. */ + /* Reset log. */ + RESET_CALLBACK_INVOKE_LOG(); + status = ux_host_stack_interface_setting_select(interface_inst[1][1]); + status |= ux_host_stack_interface_setting_select(interface_inst[1][0]); + status |= ux_host_stack_interface_setting_select(interface_inst[1][1]); + + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(callback_invoke_count == 3); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_tx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_tx_stream); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (VOID*)1); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_tx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_tx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].param2 == 0); + + RESET_CALLBACK_INVOKE_LOG(); + status = ux_host_stack_interface_setting_select(interface_inst[2][1]); + status |= ux_host_stack_interface_setting_select(interface_inst[2][0]); + status |= ux_host_stack_interface_setting_select(interface_inst[2][1]); + + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(callback_invoke_count == 3); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_rx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (VOID*)1); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_rx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].param2 == 0); + + +#if defined(UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT) + /* Test feedbacks. */ + + /* Read/write feedback test, pass any data of 4 bytes. */ + _ux_system_slave->ux_system_slave_speed = UX_HIGH_SPEED_DEVICE; + slave_audio_rx_stream->ux_device_class_audio_stream_feedback->ux_slave_endpoint_transfer_request.ux_slave_transfer_request_requested_length = 4; + slave_audio_tx_stream->ux_device_class_audio_stream_feedback->ux_slave_endpoint_transfer_request.ux_slave_transfer_request_requested_length = 4; + temp = 0x1234567; + ux_device_class_audio_feedback_set(slave_audio_rx_stream, (UCHAR *)&temp); + temp = device_audio_rx_feedback_count; + while(device_audio_rx_feedback_count == temp) + tx_thread_sleep(1); + UX_TEST_ASSERT(device_audio_rx_feedback == 0x1234567); + + device_audio_tx_feedback = 0xabcd1234; + temp = device_audio_tx_feedback_count; + while(device_audio_tx_feedback_count != (temp + 2)) + tx_thread_sleep(1); + status = ux_device_class_audio_feedback_get(slave_audio_tx_stream, (UCHAR *)&temp); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(temp == 0xabcd1234); + + /* Read/write feedback test full speed, pass any data of 3 bytes. */ + _ux_system_slave->ux_system_slave_speed = UX_FULL_SPEED_DEVICE; + slave_audio_rx_stream->ux_device_class_audio_stream_feedback->ux_slave_endpoint_transfer_request.ux_slave_transfer_request_requested_length = 3; + slave_audio_tx_stream->ux_device_class_audio_stream_feedback->ux_slave_endpoint_transfer_request.ux_slave_transfer_request_requested_length = 3; + temp = 0x7654321; + ux_device_class_audio_feedback_set(slave_audio_rx_stream, (UCHAR *)&temp); + temp = device_audio_rx_feedback_count; + while(device_audio_rx_feedback_count == temp) + tx_thread_sleep(1); + UX_TEST_ASSERT(device_audio_rx_feedback == 0x654321); + + device_audio_tx_feedback = 0x4321dcba; + temp = device_audio_tx_feedback_count; + while(device_audio_tx_feedback_count != (temp + 2)) + tx_thread_sleep(1); + status = ux_device_class_audio_feedback_get(slave_audio_tx_stream, (UCHAR *)&temp); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(temp == 0x21dcba); +#endif + + + /* Test data streaming. */ + + /* Wrong interface! */ + status = ux_device_class_audio_transmission_start(slave_audio_rx_stream); + status |= ux_device_class_audio_reception_start(slave_audio_tx_stream); + UX_TEST_CHECK_NOT_SUCCESS(status); + + /* ------------------ Write test. */ + + status = ux_device_class_audio_frame_write(slave_audio_tx_stream, "test0", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test1", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test2", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test3", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test4", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test5", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test6", 16); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test7", 16); + UX_TEST_CHECK_SUCCESS(status); + + error_callback_counter = 0; + status = ux_device_class_audio_frame_write(slave_audio_tx_stream, "test8", 16); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + /* + Keep sending until under-run. + No buffer appended while running. + */ + + buffer_log_count = 0; + test_tx_ack_count = 10; + status = ux_device_class_audio_transmission_start(slave_audio_tx_stream); + UX_TEST_CHECK_SUCCESS(status); + + /* Delay to let thread runs. */ + _ux_utility_delay_ms(500); + + /* Prepare data for checking. */ + _ux_utility_memory_set(test_tmp, 0, 16); + _ux_utility_memory_copy(test_tmp, "test", 4); + + /* 8 frame should be available. */ + for (test_n = 0; test_n < 8; test_n ++) + { + // printf("%ld: %ld: %s\n", test_n, buffer_log[test_n].length, buffer_log[test_n].data); + test_tmp[4] = (UCHAR)(test_n + '0'); + + UX_TEST_ASSERT(buffer_log[test_n].length == 16); + + status = _ux_utility_memory_compare(buffer_log[test_n].data, test_tmp, 6); + UX_TEST_CHECK_SUCCESS(status); + } + /* Then under-run, 0 length packets. */ + for(;test_n < buffer_log_count; test_n ++) + { + // printf("%ld: %ld\n", test_n, buffer_log[test_n].length); + UX_TEST_ASSERT(buffer_log[test_n].length == 0); + } + + /* + Keep sending until under-run. + Specific number of buffer appended while running. + */ + + for (test_tx_ins_way = 0; test_tx_ins_way < 2; test_tx_ins_way ++) + { + + /* Switch interface to clean up status. */ + status = ux_host_stack_interface_setting_select(interface_inst[1][0]); + status |= ux_host_stack_interface_setting_select(interface_inst[1][1]); + + status = ux_device_class_audio_frame_write(slave_audio_tx_stream, "test0", 20); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test1", 20); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test2", 20); + status |= ux_device_class_audio_frame_write(slave_audio_tx_stream, "test3", 20); + UX_TEST_CHECK_SUCCESS(status); + + test_tx_ins_count = 10; + test_tx_ack_count = 20; + buffer_log_count = 0; + status = ux_device_class_audio_transmission_start(slave_audio_tx_stream); + UX_TEST_CHECK_SUCCESS(status); + + /* Delay to let thread runs. */ + _ux_utility_delay_ms(500); + + /* Prepare data for checking. */ + _ux_utility_memory_set(test_tmp, 0, 32); + + /* 4 frame should be available. */ + _ux_utility_memory_copy(test_tmp, "test", 4); + for (test_n = 0; test_n < 4; test_n ++) + { + // printf("%ld: %ld: %s\n", test_n, buffer_log[test_n].length, buffer_log[test_n].data); + test_tmp[4] = (UCHAR)(test_n + '0'); + + UX_TEST_ASSERT(buffer_log[test_n].length == 20); + + status = _ux_utility_memory_compare(buffer_log[test_n].data, test_tmp, 6); + UX_TEST_CHECK_SUCCESS(status); + } + /* 10 more frame should be available. */ + _ux_utility_memory_copy(test_tmp, "insert", 6); + for (; test_n < 14; test_n ++) + { + // printf("%ld: %ld: %s\n", test_n, buffer_log[test_n].length, buffer_log[test_n].data); + test_tmp[6] = (UCHAR)(((10 - (test_n - 4)) % 26) + 'A'); + + UX_TEST_ASSERT(buffer_log[test_n].length == 32); + + status = _ux_utility_memory_compare(buffer_log[test_n].data, test_tmp, 8); + UX_TEST_CHECK_SUCCESS(status); + } + /* Then under-run, 0 length packets. */ + for(;test_n < buffer_log_count; test_n ++) + { + // printf("%ld: %ld\n", test_n, buffer_log[test_n].length); + UX_TEST_ASSERT(buffer_log[test_n].length == 0); + } + } + + UX_TEST_ASSERT(slave_audio_tx_stream->ux_device_class_audio_stream_transfer_pos == slave_audio_tx_stream->ux_device_class_audio_stream_access_pos); + + /* ------------------ Read - 8 test. */ + + UX_TEST_ASSERT(slave_audio_rx_transfer == UX_NULL); + + temp = 0; + status = ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + status = ux_device_class_audio_reception_start(slave_audio_rx_stream); + UX_TEST_CHECK_SUCCESS(status); + _ux_utility_thread_sleep(1); + + UX_TEST_ASSERT(slave_audio_rx_transfer != UX_NULL); + + status = ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + RESET_CALLBACK_INVOKE_LOG(); + + slave_audio_rx_simulate_one_frame("012345", 6); + for (test_n = 0; test_n < 6; test_n ++) + { + status = ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(temp == (test_n + '0')); + } + + slave_audio_rx_simulate_one_frame("012345", 6); + slave_audio_rx_simulate_one_frame("67", 2); + slave_audio_rx_simulate_one_frame("89", 2); + for (test_n = 0; test_n < 10; test_n ++) + { + status = ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(temp == (test_n + '0')); + } + + UX_TEST_ASSERT(callback_invoke_count == 4); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[2].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[2].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[3].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[3].param1 == slave_audio_rx_stream); + + RESET_CALLBACK_INVOKE_LOG(); + error_callback_counter = 0; + for (test_n = 0; test_n < 10; test_n ++) + { + test_tmp[0] = (UCHAR)(test_n + '0'); + slave_audio_rx_simulate_one_frame(test_tmp, 1); + } + + UX_TEST_ASSERT(callback_invoke_count == 10); + UX_TEST_ASSERT(error_callback_counter == 3); + for (test_n = 0; test_n < 7; test_n ++) + { + status = ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp); + UX_TEST_CHECK_SUCCESS(status); + // printf("(%lx)%c\n", temp, (char)temp); + UX_TEST_ASSERT(temp == (test_n + '0')); + } + UX_TEST_CHECK_SUCCESS(ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp)); + UX_TEST_ASSERT(temp == '9'); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, ux_device_class_audio_sample_read8(slave_audio_rx_stream, (UCHAR *)&temp)); + + /* ------------------ Read - 16 test. */ + + status = ux_device_class_audio_sample_read16(slave_audio_rx_stream, (USHORT *)&temp); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + RESET_CALLBACK_INVOKE_LOG(); + slave_audio_rx_simulate_one_frame("012345", 6); + slave_audio_rx_simulate_one_frame("67", 2); + UX_TEST_ASSERT(callback_invoke_count == 2); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (VOID*)6); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].param2 == (VOID*)2); + for (test_n = 0; test_n < 4; test_n ++) + { + status = ux_device_class_audio_sample_read16(slave_audio_rx_stream, (USHORT *)&temp); + UX_TEST_CHECK_SUCCESS(status); + // printf("%lx\n", temp); + test_tmp[0] = (UCHAR)(test_n * 2 + '0'); + test_tmp[1] = (UCHAR)(test_n * 2 + '1'); + UX_TEST_CHECK_SUCCESS(_ux_utility_memory_compare(test_tmp, &temp, 2)); + } + + /* ------------------ Read - 24 test. */ + + status = ux_device_class_audio_sample_read24(slave_audio_rx_stream, &temp); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + RESET_CALLBACK_INVOKE_LOG(); + slave_audio_rx_simulate_one_frame("012345", 6); + slave_audio_rx_simulate_one_frame("678", 3); + UX_TEST_ASSERT(callback_invoke_count == 2); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (VOID*)6); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].param2 == (VOID*)3); + for (test_n = 0; test_n < 3; test_n ++) + { + status = ux_device_class_audio_sample_read24(slave_audio_rx_stream, &temp); + UX_TEST_CHECK_SUCCESS(status); + // printf("%lx\n", temp); + test_tmp[0] = (UCHAR)(test_n * 3 + '0'); + test_tmp[1] = (UCHAR)(test_n * 3 + '1'); + test_tmp[2] = (UCHAR)(test_n * 3 + '2'); + UX_TEST_CHECK_SUCCESS(_ux_utility_memory_compare(test_tmp, &temp, 3)); + } + + /* ------------------ Read - 32 test. */ + + status = ux_device_class_audio_sample_read32(slave_audio_rx_stream, &temp); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + RESET_CALLBACK_INVOKE_LOG(); + slave_audio_rx_simulate_one_frame("01234567", 8); + slave_audio_rx_simulate_one_frame("8901", 4); + UX_TEST_ASSERT(callback_invoke_count == 2); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (VOID*)8); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_rx_done); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].param2 == (VOID*)4); + for (test_n = 0; test_n < 3; test_n ++) + { + status = ux_device_class_audio_sample_read32(slave_audio_rx_stream, &temp); + UX_TEST_CHECK_SUCCESS(status); + // printf("%lx\n", temp); + test_tmp[0] = ((test_n * 4 + 0) % 10) + '0'; + test_tmp[1] = ((test_n * 4 + 1) % 10) + '0'; + test_tmp[2] = ((test_n * 4 + 2) % 10) + '0'; + test_tmp[3] = ((test_n * 4 + 3) % 10) + '0'; + UX_TEST_CHECK_SUCCESS(_ux_utility_memory_compare(test_tmp, &temp, 4)); + } + + UX_TEST_ASSERT(slave_audio_tx_stream->ux_device_class_audio_stream_transfer_pos == slave_audio_tx_stream->ux_device_class_audio_stream_access_pos); + + /**************************************************************************/ + + /* Control requests test. */ + + transfer_request -> ux_transfer_request_data_pointer = buffer; + + test_tmp[0] = 2; + test_tmp[1] = 5; + + for (test_n = 0; test_n < 2; test_n ++) + { + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_AUDIO20_CUR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + + /* Issue SetFeatureMute(test_tmp[test_n], 0). */ + transfer_request -> ux_transfer_request_requested_length = 1; + transfer_request -> ux_transfer_request_index = (test_tmp[test_n] << 8) | 0; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO20_FU_MUTE_CONTROL << 8) | 0; + buffer[0] = 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_changed == 0); + + /* Issue SetFeatureMute(test_tmp[test_n], 1). */ + buffer[0] = 1; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_MUTE_CHANGED); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_mute[0] == 1); + + /* Issue SetFeatureMute(test_tmp[test_n], 0). */ + buffer[0] = 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_MUTE_CHANGED); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_mute[0] == 0); + + /* Issue SetFeatureMute(test_tmp[test_n], 1). */ + buffer[0] = 1; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_MUTE_CHANGED); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_mute[0] == 1); + + /* Issue SetFeatureVolume(test_tmp[test_n], 0x0003). */ + transfer_request -> ux_transfer_request_requested_length = 2; + transfer_request -> ux_transfer_request_index = (test_tmp[test_n] << 8) | 0; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO20_FU_VOLUME_CONTROL << 8) | 0; + buffer[0] = 3; buffer[1] = 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_VOLUME_CHANGED); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_volume[0] == 0x0003); + + /* Issue SetFeatureVolume(test_tmp[test_n], 0x0103). */ + buffer[1] = 1; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_VOLUME_CHANGED); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_volume[0] == 0x0103); + + /* Issue SetFeatureVolume(test_tmp[test_n], 0x0103). */ + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(g_slave_audio20_control[test_n].ux_device_class_audio20_control_changed == 0); + + /* Issue GetFeatureMute(test_tmp[test_n]). */ + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_AUDIO20_CUR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + + transfer_request -> ux_transfer_request_requested_length = 1; + transfer_request -> ux_transfer_request_index = (test_tmp[test_n] << 8) | 0; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO20_FU_MUTE_CONTROL << 8) | 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(transfer_request -> ux_transfer_request_actual_length == 1); + UX_TEST_ASSERT(buffer[0] == 1); + + /* Issue GetFeatureMute(test_tmp[test_n]). */ + transfer_request -> ux_transfer_request_requested_length = 2; + transfer_request -> ux_transfer_request_index = (test_tmp[test_n] << 8) | 0; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO20_FU_VOLUME_CONTROL << 8) | 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(transfer_request -> ux_transfer_request_actual_length == 2); + UX_TEST_ASSERT(buffer[0] == 3); + UX_TEST_ASSERT(buffer[1] == 1); + + /* Issue GetClockSamplingFrequency(0x10). */ + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_AUDIO20_CUR; + transfer_request -> ux_transfer_request_requested_length = 4; + transfer_request -> ux_transfer_request_index = (0x10 << 8) | 0; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO20_CS_SAM_FREQ_CONTROL << 8) | 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(transfer_request -> ux_transfer_request_actual_length == 4); + UX_TEST_ASSERT(buffer[0] == D0(48000)); + UX_TEST_ASSERT(buffer[1] == D1(48000)); + UX_TEST_ASSERT(buffer[2] == D2(48000)); + UX_TEST_ASSERT(buffer[3] == D3(48000)); + + /* Issue GetClockSamplingFrequencyRange(0x10). */ + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_AUDIO20_RANGE; + transfer_request -> ux_transfer_request_requested_length = 14; + transfer_request -> ux_transfer_request_index = (0x10 << 8) | 0; + transfer_request -> ux_transfer_request_value = (UX_DEVICE_CLASS_AUDIO20_CS_SAM_FREQ_CONTROL << 8) | 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(transfer_request -> ux_transfer_request_actual_length == 14); + UX_TEST_ASSERT(buffer[ 0] == D0(1)); + UX_TEST_ASSERT(buffer[ 1] == D1(1)); + UX_TEST_ASSERT(buffer[ 2] == D0(48000)); + UX_TEST_ASSERT(buffer[ 3] == D1(48000)); + UX_TEST_ASSERT(buffer[ 4] == D2(48000)); + UX_TEST_ASSERT(buffer[ 5] == D3(48000)); + UX_TEST_ASSERT(buffer[ 6] == D0(48000)); + UX_TEST_ASSERT(buffer[ 7] == D1(48000)); + UX_TEST_ASSERT(buffer[ 8] == D2(48000)); + UX_TEST_ASSERT(buffer[ 9] == D3(48000)); + } + + /* Wait pending threads. */ + _ux_utility_thread_sleep(1); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + ux_device_stack_class_unregister(_ux_system_slave_class_audio_name, ux_device_class_audio_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + while(1) + { + +#if defined(UX_DEVICE_STANDALONE) + + /* Standalone background task. */ + ux_system_tasks_run(); +#else + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); +#endif + } +} diff --git a/test/regression/usbx_audio20_host_basic_test.c b/test/regression/usbx_audio20_host_basic_test.c new file mode 100644 index 00000000..2ec492f2 --- /dev/null +++ b/test/regression/usbx_audio20_host_basic_test.c @@ -0,0 +1,1631 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" + +#include "fx_api.h" + +#include "ux_device_class_audio.h" +#include "ux_device_class_audio20.h" +#include "ux_device_stack.h" + +#include "ux_host_class_audio.h" +#include "ux_host_class_audio.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_DEMO_REQUEST_MAX_LENGTH \ + ((UX_HCD_SIM_HOST_MAX_PAYLOAD) > (UX_SLAVE_REQUEST_DATA_MAX_LENGTH) ? \ + (UX_HCD_SIM_HOST_MAX_PAYLOAD) : (UX_SLAVE_REQUEST_DATA_MAX_LENGTH)) + +#define UX_DEMO_FEEDBACK (\ + defined(UX_DEVICE_BIDIRECTIONAL_ENDPOINT_SUPPORT) && \ + defined(UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT) && \ + defined(UX_HOST_CLASS_AUDIO_FEEDBACK_SUPPORT)) + +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_DEMO_REQUEST_MAX_LENGTH + 1) +#define UX_DEMO_MEMORY_SIZE (128*1024) + +#define UX_TEST_LOG_SIZE (64) + + +/* Define local/extern function prototypes. */ +static void test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static void tx_test_thread_host_simulation_entry(ULONG); +static void tx_test_thread_slave_simulation_entry(ULONG); + +static TX_EVENT_FLAGS_GROUP tx_test_events; + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[64]; + +static UX_HOST_CLASS_AUDIO *host_audio_tx; +static UX_HOST_CLASS_AUDIO *host_audio_rx; + +static UX_HOST_CLASS_AUDIO_TRANSFER_REQUEST audio_transfer1 = {0}; +static UX_HOST_CLASS_AUDIO_TRANSFER_REQUEST audio_transfer2 = {0}; +UCHAR host_audio_buffer[2][1024 * 3]; + +static UX_DEVICE_CLASS_AUDIO *slave_audio; +static UX_DEVICE_CLASS_AUDIO_PARAMETER slave_audio_parameter; +static UX_DEVICE_CLASS_AUDIO_STREAM_PARAMETER slave_audio_stream_parameter[2]; + +static UX_DEVICE_CLASS_AUDIO_STREAM *slave_audio_tx_stream; + +static UX_DEVICE_CLASS_AUDIO_STREAM *slave_audio_rx_stream; +static UX_SLAVE_TRANSFER *slave_audio_rx_transfer; + +static UX_HOST_CLASS_AUDIO *audio; + +static UX_DEVICE_CLASS_AUDIO20_CONTROL g_slave_audio20_control[2]; + +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_mem_alloc_cnt_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_enum_mem_alloc_count; + +static ULONG rsc_audio_sem_usage; +static ULONG rsc_audio_sem_get_count; +static ULONG rsc_audio_mutex_usage; +static ULONG rsc_audio_mem_usage; +static ULONG rsc_audio_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +static struct BUFFER_LOG_STRUCT { + ULONG length; + UCHAR data[256]; +} buffer_log[UX_TEST_LOG_SIZE]; +static ULONG buffer_log_count = 0; +#define SAVE_BUFFER_LOG(buf,siz) do { \ + if (buffer_log_count < UX_TEST_LOG_SIZE) { \ + ULONG __local_size__ = ((siz) > 256) ? 256 : (siz); \ + buffer_log[buffer_log_count].length = (siz); \ + _ux_utility_memory_copy(buffer_log[buffer_log_count].data, (buf), __local_size__); \ + } \ + buffer_log_count ++; \ +} while(0) + +static ULONG test_tx_ack_count = 0xFFFFFFFF; +static ULONG test_tx_ins_count = 0; +static ULONG test_tx_ins_way = 0; + +static struct CALLBACK_INVOKE_LOG_STRUCT { + VOID *func; + VOID *param1; + VOID *param2; + VOID *param3; +} callback_invoke_log[UX_TEST_LOG_SIZE]; +static ULONG callback_invoke_count = 0; + +#define SAVE_CALLBACK_INVOKE_LOG(f,p1,p2,p3) do { \ + if (callback_invoke_count < UX_TEST_LOG_SIZE) { \ + callback_invoke_log[callback_invoke_count].func = (VOID *)(f); \ + callback_invoke_log[callback_invoke_count].param1 = (VOID *)(p1); \ + callback_invoke_log[callback_invoke_count].param2 = (VOID *)(p2); \ + callback_invoke_log[callback_invoke_count].param3 = (VOID *)(p3); \ + callback_invoke_count++; \ + } \ +} while(0) +#define RESET_CALLBACK_INVOKE_LOG() do { \ + callback_invoke_count = 0; \ +} while(0) + +/* Define device framework. */ + +#define D3(d) ((UCHAR)((d) >> 24)) +#define D2(d) ((UCHAR)((d) >> 16)) +#define D1(d) ((UCHAR)((d) >> 8)) +#define D0(d) ((UCHAR)((d) >> 0)) + +static unsigned char device_framework_full_speed[] = { + +/* --------------------------------------- Device Descriptor */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x02, 0x00, +/* 12 bcdDevice */ D0(0x200),D1(0x200), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* ----------------------------- Device Qualifier Descriptor */ +/* 0 bLength, bDescriptorType */ 10, 0x06, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 bNumConfigurations */ 1, +/* 9 bReserved */ 0, + +/* -------------------------------- Configuration Descriptor *//* 9+8+135+55+62=269 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(269),D1(269), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------ Interface Association Descriptor */ +/* 0 bLength, bDescriptorType */ 8, 0x0B, +/* 2 bFirstInterface, bInterfaceCount */ 0, 3, +/* 4 bFunctionClass, bFunctionSubClass, bFunctionProtocol */ 0x01, 0x00, 0x20, +/* 7 iFunction */ 0, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+126=135) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x20, +/* 8 iInterface */ 0, +/* ---------------- Audio 2.0 AC Interface Header Descriptor *//* (9+8+8+7+17*2+18*2+12*2=126) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x01, +/* 3 bcdADC, bCategory */ D0(0x200),D1(0x200), 0x08, +/* 6 wTotalLength */ D0(126),D1(126), +/* 8 bmControls */ 0x00, +/* -------------------- Audio 2.0 AC Clock Source Descriptor (0x11) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x24, 0x0A, +/* 3 bClockID, bmAttributes, bmControls */ 0x11, 0x05, 0x01, +/* 6 bAssocTerminal, iClockSource */ 0x00, 0, +/* -------------------- Audio 2.0 AC Clock Selector Descriptor (1x1, 0x12) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x24, 0x0B, +/* 3 bClockID, bNrInPins, baCSourceID1 */ 0x12, 0x01, 0x11, +/* 6 bmControls, iClockSelector */ 0x01, 0, +/* -------------------- Audio 2.0 AC Clock Multiplier Descriptor (0x10) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x0C, +/* 3 bClockID, bCSourceID, bmControls */ 0x10, 0x12, 0x05, +/* 6 iClockMultiplier */ 0, +/* ------------------- Audio 2.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 17, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, bCSourceID */ 0x00, 0x10, +/* 8 bNrChannels, bmChannelConfig */ 0x02, D0(0),D1(0),D2(0),D3(0), +/* 13 iChannelNames, bmControls, iTerminal */ 0, D0(0),D1(0), 0, +/* --------------------- Audio 2.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 18, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bmaControls(0), bmaControls(...) ... */ D0(0xF),D1(0xF),D2(0xF),D3(0xF), D0(0),D1(0),D2(0),D3(0), D0(0),D1(0),D2(0),D3(0), +/* . iFeature */ 0, +/* ------------------ Audio 2.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID, bCSourceID */ 0x00, 0x02, 0x10, +/* 9 bmControls, iTerminal */ D0(0),D1(0), 0, +/* ------------------- Audio 2.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 17, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bCSourceID */ 0x00, 0x10, +/* 8 bNrChannels, bmChannelConfig */ 0x02, D0(0),D1(0),D2(0),D3(0), +/* 13 iChannelNames, bmControls, iTerminal */ 0, D0(0),D1(0), 0, +/* --------------------- Audio 2.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 18, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bmaControls(0), bmaControls(...) ... */ D0(0xF),D1(0xF),D2(0xF),D3(0xF), D0(0),D1(0),D2(0),D3(0), D0(0),D1(0),D2(0),D3(0), +/* . iFeature */ 0, +/* ------------------ Audio 2.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID, bCSourceID */ 0x00, 0x05, 0x10, +/* 9 bmControls, iTerminal */ D0(0),D1(0), 0, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+16+6+7+8=55) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------ Audio 2.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 16, 0x24, 0x01, +/* 3 bTerminalLink, bmControls */ 0x03,0x00, +/* 5 bFormatType, bmFormats */ 0x01,D0(1),D1(1),D2(1),D3(1), +/* 10 bNrChannels, bmChannelConfig */ 2, D0(0),D1(0),D2(0),D3(0), +/* 15 iChannelNames */ 0, +/* -------------------- Audio 2.0 AS Format Type I Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 6, 0x24, 0x02, +/* 3 bFormatType, bSubslotSize, bBitResolution */ 0x01, 2, 16, +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x0D, +/* 4 wMaxPacketSize, bInterval */ D0(256),D1(256), 1, +/* ---------- Audio 2.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x25, 0x01, +/* 3 bmAttributes, bmControls */ 0x00, 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+16+6+7+8+7=62) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 2, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------ Audio 2.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 16, 0x24, 0x01, +/* 3 bTerminalLink, bmControls */ 0x04,0x00, +/* 5 bFormatType, bmFormats */ 0x01,D0(1),D1(1),D2(1),D3(1), +/* 10 bNrChannels, bmChannelConfig */ 2, D0(0),D1(0),D2(0),D3(0), +/* 15 iChannelNames */ 0, +/* ---------------------- Audio 2.0 AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 6, 0x24, 0x02, +/* 3 bFormatType, bSubslotSize, bBitResolution */ 0x01, 2, 16, +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x0D, +/* 4 wMaxPacketSize, bInterval */ D0(256),D1(256), 1, +/* ---------- Audio 2.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x25, 0x01, +/* 3 bmAttributes, bmControls */ 0x00, 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x82, 0x11, +/* 4 wMaxPacketSize, bInterval */ D0(4),D1(4), 1, + +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { +/* --------------------------------------- Device Descriptor */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 0x08, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x02, 0x00, +/* 12 bcdDevice */ D0(0x200),D1(0x200), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* ----------------------------- Device Qualifier Descriptor */ +/* 0 bLength, bDescriptorType */ 10, 0x06, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 bNumConfigurations */ 1, +/* 9 bReserved */ 0, + +/* -------------------------------- Configuration Descriptor *//* 9+8+135+55+62=269 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(269),D1(269), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------ Interface Association Descriptor */ +/* 0 bLength, bDescriptorType */ 8, 0x0B, +/* 2 bFirstInterface, bInterfaceCount */ 0, 3, +/* 4 bFunctionClass, bFunctionSubClass, bFunctionProtocol */ 0x01, 0x00, 0x20, +/* 7 iFunction */ 0, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+126=135) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x20, +/* 8 iInterface */ 0, +/* ---------------- Audio 2.0 AC Interface Header Descriptor *//* (9+8+8+7+17*2+18*2+12*2=126) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x01, +/* 3 bcdADC, bCategory */ D0(0x200),D1(0x200), 0x08, +/* 6 wTotalLength */ D0(126),D1(126), +/* 8 bmControls */ 0x00, +/* -------------------- Audio 2.0 AC Clock Source Descriptor (0x11) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x24, 0x0A, +/* 3 bClockID, bmAttributes, bmControls */ 0x11, 0x05, 0x01, +/* 6 bAssocTerminal, iClockSource */ 0x00, 0, +/* -------------------- Audio 2.0 AC Clock Selector Descriptor (1x1, 0x12) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x24, 0x0B, +/* 3 bClockID, bNrInPins, baCSourceID1 */ 0x12, 0x01, 0x11, +/* 6 bmControls, iClockSelector */ 0x01, 0, +/* -------------------- Audio 2.0 AC Clock Multiplier Descriptor (0x10) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x0C, +/* 3 bClockID, bCSourceID, bmControls */ 0x10, 0x12, 0x05, +/* 6 iClockMultiplier */ 0, +/* ------------------- Audio 2.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 17, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, bCSourceID */ 0x00, 0x10, +/* 8 bNrChannels, bmChannelConfig */ 0x02, D0(0),D1(0),D2(0),D3(0), +/* 13 iChannelNames, bmControls, iTerminal */ 0, D0(0),D1(0), 0, +/* --------------------- Audio 2.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 18, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bmaControls(0), bmaControls(...) ... */ D0(0xF),D1(0xF),D2(0xF),D3(0xF), D0(0),D1(0),D2(0),D3(0), D0(0),D1(0),D2(0),D3(0), +/* . iFeature */ 0, +/* ------------------ Audio 2.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID, bCSourceID */ 0x00, 0x02, 0x10, +/* 9 bmControls, iTerminal */ D0(0),D1(0), 0, +/* ------------------- Audio 2.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 17, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bCSourceID */ 0x00, 0x10, +/* 8 bNrChannels, bmChannelConfig */ 0x02, D0(0),D1(0),D2(0),D3(0), +/* 13 iChannelNames, bmControls, iTerminal */ 0, D0(0),D1(0), 0, +/* --------------------- Audio 2.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 18, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bmaControls(0), bmaControls(...) ... */ D0(0xF),D1(0xF),D2(0xF),D3(0xF), D0(0),D1(0),D2(0),D3(0), D0(0),D1(0),D2(0),D3(0), +/* . iFeature */ 0, +/* ------------------ Audio 2.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID, bCSourceID */ 0x00, 0x05, 0x10, +/* 9 bmControls, iTerminal */ D0(0),D1(0), 0, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+16+6+7+8=55) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------ Audio 2.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 16, 0x24, 0x01, +/* 3 bTerminalLink, bmControls */ 0x03,0x00, +/* 5 bFormatType, bmFormats */ 0x01,D0(1),D1(1),D2(1),D3(1), +/* 10 bNrChannels, bmChannelConfig */ 2, D0(0),D1(0),D2(0),D3(0), +/* 15 iChannelNames */ 0, +/* -------------------- Audio 2.0 AS Format Type I Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 6, 0x24, 0x02, +/* 3 bFormatType, bSubslotSize, bBitResolution */ 0x01, 2, 16, +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x0D, +/* 4 wMaxPacketSize, bInterval */ D0(256),D1(256), 4, +/* ---------- Audio 2.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x25, 0x01, +/* 3 bmAttributes, bmControls */ 0x00, 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+16+6+7+8+7=62) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 2, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------ Audio 2.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 16, 0x24, 0x01, +/* 3 bTerminalLink, bmControls */ 0x04,0x00, +/* 5 bFormatType, bmFormats */ 0x01,D0(1),D1(1),D2(1),D3(1), +/* 10 bNrChannels, bmChannelConfig */ 2, D0(0),D1(0),D2(0),D3(0), +/* 15 iChannelNames */ 0, +/* ---------------------- Audio 2.0 AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 6, 0x24, 0x02, +/* 3 bFormatType, bSubslotSize, bBitResolution */ 0x01, 2, 16, +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x0D, +/* 4 wMaxPacketSize, bInterval */ D0(256),D1(256), 4, +/* ---------- Audio 2.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x25, 0x01, +/* 3 bmAttributes, bmControls */ 0x00, 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x82, 0x11, +/* 4 wMaxPacketSize, bInterval */ D0(4),D1(4), 1, + +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + +/* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + +/* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + +/* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; +static UX_TEST_SETUP _GetCfgDescr = UX_TEST_SETUP_GetCfgDescr; +static UX_TEST_SETUP _SetAddress = UX_TEST_SETUP_SetAddress; +static UX_TEST_SETUP _GetDeviceDescriptor = UX_TEST_SETUP_GetDevDescr; +static UX_TEST_SETUP _GetConfigDescriptor = UX_TEST_SETUP_GetCfgDescr; + +/* Interaction define */ + +/* Hooks define */ + +static VOID ux_device_class_audio_tx_hook(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *p = (UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *)params; +UX_SLAVE_TRANSFER *transfer = (UX_SLAVE_TRANSFER *)p -> parameter; +UCHAR tmp[32] = {'i','n','s','e','r','t','A',0}; + + + (void)params; + // printf("tTX\n"); + + /* Acknowledge frame sent. */ + if (test_tx_ack_count) + { + SAVE_BUFFER_LOG(transfer -> ux_slave_transfer_request_data_pointer, transfer -> ux_slave_transfer_request_requested_length); + transfer -> ux_slave_transfer_request_actual_length = transfer -> ux_slave_transfer_request_requested_length; + transfer -> ux_slave_transfer_request_completion_code = UX_SUCCESS; + _ux_utility_semaphore_put(&transfer -> ux_slave_transfer_request_semaphore); + } + if (test_tx_ack_count != 0xFFFFFFFF && test_tx_ack_count > 0) + test_tx_ack_count --; + + /* Insert frames when sent. */ + if (test_tx_ins_count) + { + tmp[6] = (test_tx_ins_count % 26) + 'A'; + if (test_tx_ins_way == 0) + ux_device_class_audio_frame_write(slave_audio_tx_stream, tmp, 32); + else + { + + UCHAR *frame; + ULONG frame_length; + + + ux_device_class_audio_write_frame_get(slave_audio_tx_stream, &frame, &frame_length); + _ux_utility_memory_copy(frame, tmp, 32); + ux_device_class_audio_write_frame_commit(slave_audio_tx_stream, 32); + } + } + if (test_tx_ins_count != 0xFFFFFFFF && test_tx_ins_count > 0) + test_tx_ins_count --; +} + +static VOID ux_device_class_audio_rx_hook(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *p = (UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *)params; +UX_SLAVE_TRANSFER *transfer = (UX_SLAVE_TRANSFER *)p -> parameter; + + + (void)action; + (void)params; + (void)p; + (void)transfer; + // printf("tRX\n"); + slave_audio_rx_transfer = transfer; +} +static VOID slave_audio_rx_simulate_one_frame(UCHAR *frame, ULONG frame_length) +{ + UX_TEST_ASSERT(slave_audio_rx_transfer); + if (frame_length) + { + _ux_utility_memory_copy(slave_audio_rx_transfer->ux_slave_transfer_request_data_pointer, frame, frame_length); + slave_audio_rx_transfer->ux_slave_transfer_request_actual_length = frame_length; + slave_audio_rx_transfer->ux_slave_transfer_request_completion_code = UX_SUCCESS; + } + _ux_utility_semaphore_put(&slave_audio_rx_transfer->ux_slave_transfer_request_semaphore); + _ux_utility_thread_sleep(1); +} + +static UX_TEST_ACTION ux_device_class_audio_transfer_hook[] = +{ + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .action_func = ux_device_class_audio_tx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x81, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .action_func = ux_device_class_audio_rx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x02, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, +{ 0 }, +}; + +static VOID ux_host_class_audio_tx_hook(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ +UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *p = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS*)params; +UX_TRANSFER *transfer = (UX_TRANSFER *)p->parameter; + SAVE_CALLBACK_INVOKE_LOG(ux_host_class_audio_tx_hook, transfer->ux_transfer_request_endpoint->ux_endpoint_descriptor.bEndpointAddress, transfer->ux_transfer_request_requested_length, 0); + // printf("hTxHook %lx %ld\n", transfer->ux_transfer_request_endpoint->ux_endpoint_descriptor.bEndpointAddress, transfer->ux_transfer_request_requested_length); + transfer->ux_transfer_request_actual_length=transfer->ux_transfer_request_requested_length; + transfer->ux_transfer_request_completion_code=UX_SUCCESS; + if (transfer->ux_transfer_request_completion_function) + transfer->ux_transfer_request_completion_function(transfer); +} + +static VOID ux_host_class_audio_rx_hook(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ +UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *p = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS*)params; +UX_TRANSFER *transfer = (UX_TRANSFER *)p->parameter; + SAVE_CALLBACK_INVOKE_LOG(ux_host_class_audio_rx_hook, transfer->ux_transfer_request_endpoint->ux_endpoint_descriptor.bEndpointAddress, transfer->ux_transfer_request_requested_length, 0); + // printf("hRxHook %lx %ld\n", transfer->ux_transfer_request_endpoint->ux_endpoint_descriptor.bEndpointAddress, transfer->ux_transfer_request_requested_length); + transfer->ux_transfer_request_actual_length=transfer->ux_transfer_request_requested_length; + transfer->ux_transfer_request_completion_code=UX_SUCCESS; + if (transfer->ux_transfer_request_completion_function) + transfer->ux_transfer_request_completion_function(transfer); +} + +#if UX_DEMO_FEEDBACK +static UX_TRANSFER *feedback_transfer; +static ULONG feedback_data = 0; +static VOID ux_host_class_audio_feedback_hook(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ +UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *p = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS*)params; +UX_TRANSFER *transfer = (UX_TRANSFER *)p->parameter; + // printf("hFeedbackHook %lx %ld, %lx\n", transfer->ux_transfer_request_endpoint->ux_endpoint_descriptor.bEndpointAddress, transfer->ux_transfer_request_requested_length, feedback_data); + feedback_transfer = transfer; + *(ULONG *)transfer -> ux_transfer_request_data_pointer = feedback_data; + if (transfer -> ux_transfer_request_endpoint -> ux_endpoint_device -> ux_device_speed == UX_HIGH_SPEED_DEVICE) + transfer -> ux_transfer_request_actual_length = 4; + else + transfer -> ux_transfer_request_actual_length = 3; + tx_event_flags_set(&tx_test_events, 0x01, TX_OR); +} +#endif + +static UX_TEST_ACTION ux_host_class_audio_transfer_hook[] = +{ + { + .usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + .function = UX_HCD_TRANSFER_REQUEST, + .action_func = ux_host_class_audio_tx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x02, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, + { + .usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + .function = UX_HCD_TRANSFER_REQUEST, + .action_func = ux_host_class_audio_rx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x81, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, +#if UX_DEMO_FEEDBACK + { + .usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + .function = UX_HCD_TRANSFER_REQUEST, + .action_func = ux_host_class_audio_feedback_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x82, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, +#endif +{0}, +}; +static UX_TEST_ACTION ux_host_class_audio_tx_action[] = +{ + { + .usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + .function = UX_HCD_TRANSFER_REQUEST, + .action_func = ux_host_class_audio_tx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x02, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, + { + .usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + .function = UX_HCD_TRANSFER_REQUEST, + .action_func = ux_host_class_audio_tx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x02, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, +{0}, +}; +static UX_TEST_ACTION ux_host_class_audio_rx_action[] = +{ + { + .usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + .function = UX_HCD_TRANSFER_REQUEST, + .action_func = ux_host_class_audio_rx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x81, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, + { + .usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + .function = UX_HCD_TRANSFER_REQUEST, + .action_func = ux_host_class_audio_rx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x81, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, +{0}, +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* 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 ++; + // printf("Error #%d, system_level: %d, system_context: %d, error_code: 0x%x\n", __LINE__, system_level, system_context, error_code); + + if (!error_callback_ignore) + { + { + /* Failed test. */ + 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 VOID slave_audio_activate(VOID *audio_instance) +{ + slave_audio = (UX_DEVICE_CLASS_AUDIO *)audio_instance; + ux_device_class_audio_stream_get(slave_audio, 0, &slave_audio_tx_stream); + ux_device_class_audio_stream_get(slave_audio, 1, &slave_audio_rx_stream); + // printf("sAUD:%p;%p,%p\n", audio_instance, slave_audio_tx_stream, slave_audio_rx_stream); +} +static VOID slave_audio_deactivate(VOID *audio_instance) +{ + if ((VOID *)slave_audio == audio_instance) + { + slave_audio = UX_NULL; + slave_audio_tx_stream = UX_NULL; + slave_audio_rx_stream = UX_NULL; + } +} +static VOID slave_audio_tx_stream_change(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG alt) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_tx_stream_change, audio, (ALIGN_TYPE)alt, 0); +} +static VOID slave_audio_rx_stream_change(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG alt) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_rx_stream_change, audio, (ALIGN_TYPE)alt, 0); + + slave_audio_rx_transfer = UX_NULL; +} +static UINT slave_audio_control_process(UX_DEVICE_CLASS_AUDIO *audio, UX_SLAVE_TRANSFER *transfer) +{ + + +UINT status; +UX_DEVICE_CLASS_AUDIO20_CONTROL_GROUP group = + {2, g_slave_audio20_control}; + + + SAVE_CALLBACK_INVOKE_LOG(slave_audio_control_process, audio, transfer, 0); + + /* For sampling frequency support. */ + { + UCHAR *setup = transfer -> ux_slave_transfer_request_setup; + UCHAR *buffer = transfer -> ux_slave_transfer_request_data_pointer; + UCHAR bmRequestType = setup[UX_SETUP_REQUEST_TYPE]; + UCHAR bRequest = setup[UX_SETUP_REQUEST]; + UCHAR wValue_CN = setup[UX_SETUP_VALUE]; + UCHAR wValue_CS = setup[UX_SETUP_VALUE + 1]; + UCHAR wIndex_iface = setup[UX_SETUP_INDEX]; + UCHAR wIndex_ID = setup[UX_SETUP_INDEX + 1]; + ULONG wLength = _ux_utility_long_get(setup + UX_SETUP_LENGTH); + /* AC Interface request. */ + if (audio->ux_device_class_audio_interface->ux_slave_interface_descriptor.bInterfaceNumber == wIndex_iface) + { + /* AC Get request. */ + if (bmRequestType == (UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE)) + { + + /* Clock Selector CUR. */ + if (wIndex_ID == 0x12 && + wValue_CS == UX_DEVICE_CLASS_AUDIO20_CX_CLOCK_SELECTOR_CONTROL && + bRequest == UX_DEVICE_CLASS_AUDIO20_CUR) + { + if (wLength < 1) + return(UX_ERROR); + *buffer = 1; + ux_device_stack_transfer_request(transfer, 1, wLength); + return(UX_SUCCESS); + } + /* Clock Multiplier Numerator, Denominator CUR. */ + if (wIndex_ID == 0x10) + { + if (wLength < 2) + return(UX_ERROR); + if (wValue_CS == UX_DEVICE_CLASS_AUDIO20_CM_NUMERATOR_CONTROL) + { + ux_utility_short_put(buffer, 12); + ux_device_stack_transfer_request(transfer, 2, wLength); + return(UX_SUCCESS); + } + if (wValue_CS == UX_DEVICE_CLASS_AUDIO20_CM_DENOMINATOR_CONTROL) + { + ux_utility_short_put(buffer, 2); + ux_device_stack_transfer_request(transfer, 2, wLength); + return(UX_SUCCESS); + } + } + /* Clock Source, sampling control. */ + if (wIndex_ID == 0x11 && wValue_CS == UX_DEVICE_CLASS_AUDIO20_CS_SAM_FREQ_CONTROL) + { + if (bRequest == UX_DEVICE_CLASS_AUDIO20_CUR) + { + if (wLength < 4) + return(UX_ERROR); + ux_utility_long_put(buffer, 8000); + ux_device_stack_transfer_request(transfer, 4, wLength); + return(UX_SUCCESS); + } + if (bRequest == UX_DEVICE_CLASS_AUDIO20_RANGE) + { + if (wLength < 2) + return(UX_ERROR); + ux_utility_long_put(buffer + 0, 1); /* wNumSubRanges */ + ux_utility_long_put(buffer + 2, 8000); /* dMIN */ + ux_utility_long_put(buffer + 6, 8000); /* dMAX */ + ux_utility_long_put(buffer + 10, 0); /* dRES */ + ux_device_stack_transfer_request(transfer, UX_MIN(2+4*3, wLength), wLength); + return(UX_SUCCESS); + } + } + } + } + } + + status = ux_device_class_audio20_control_process(audio, transfer, &group); + if (status == UX_SUCCESS) + { + if (g_slave_audio20_control[0].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_MUTE_CHANGED) + { + /* Mute change! */ + } + if (g_slave_audio20_control[0].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_VOLUME_CHANGED) + { + /* Volume change! */ + } + if (g_slave_audio20_control[1].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_MUTE_CHANGED) + { + /* Mute change! */ + } + if (g_slave_audio20_control[1].ux_device_class_audio20_control_changed == UX_DEVICE_CLASS_AUDIO20_CONTROL_VOLUME_CHANGED) + { + /* Volume change! */ + } + } + return(status); +} +static VOID slave_audio_tx_done(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG length) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_tx_done, audio, (ALIGN_TYPE)length, 0); +} +static VOID slave_audio_rx_done(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG length) +{ + SAVE_CALLBACK_INVOKE_LOG(slave_audio_rx_done, audio, (ALIGN_TYPE)length, 0); +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_AUDIO *audio = (UX_HOST_CLASS_AUDIO *) inst; + + + switch(event) + { + + case UX_DEVICE_INSERTION: + + // printf("hINS:%p,%p:%ld\n", cls, inst, ux_host_class_audio_type_get(audio)); + if (ux_host_class_audio_type_get(audio) == UX_HOST_CLASS_AUDIO_INPUT) + host_audio_rx = audio; + else + host_audio_tx = audio; + break; + + case UX_DEVICE_REMOVAL: + + // printf("hRMV:%p,%p:%ld\n", cls, inst, ux_host_class_audio_type_get(audio)); + if (audio == host_audio_rx) + host_audio_rx = UX_NULL; + if (audio == host_audio_tx) + host_audio_tx = UX_NULL; + break; + + default: + break; + } + return 0; +} + + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_mem_free_on_set_cfg = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_audio20_device_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running Audio 2.0 Host Basic Functionality Test..................... "); + +#if !UX_TEST_MULTI_IFC_ON || !UX_TEST_MULTI_ALT_ON || !UX_TEST_MULTI_CLS_ON || \ + !defined(UX_HOST_CLASS_AUDIO_2_SUPPORT) || \ + !defined(UX_DEVICE_BIDIRECTIONAL_ENDPOINT_SUPPORT) || \ + (UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH < 260) + printf("SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + + stepinfo("\n"); + + /* 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(); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* 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_host_change_function); + UX_TEST_CHECK_SUCCESS(status); + + /* Register Audio class. */ + status = ux_host_stack_class_register(_ux_system_host_class_audio_name, ux_host_class_audio_entry); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Set the parameters for callback when insertion/extraction of a Audio 2.0 device, no IAD. */ + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_thread_entry = ux_device_class_audio_write_thread_entry; + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_change = slave_audio_tx_stream_change; + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_frame_done = slave_audio_tx_done; + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_max_frame_buffer_size = 256; + slave_audio_stream_parameter[0].ux_device_class_audio_stream_parameter_max_frame_buffer_nb = 8; +#if defined(UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT) + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_feedback_thread_entry = ux_device_class_audio_feedback_thread_entry; +#endif + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_thread_entry = ux_device_class_audio_read_thread_entry; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_change = slave_audio_rx_stream_change; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_frame_done = slave_audio_rx_done; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_max_frame_buffer_size = 256; + slave_audio_stream_parameter[1].ux_device_class_audio_stream_parameter_max_frame_buffer_nb = 8; + slave_audio_parameter.ux_device_class_audio_parameter_streams = slave_audio_stream_parameter; + slave_audio_parameter.ux_device_class_audio_parameter_streams_nb = 2; + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_slave_class_audio_instance_activate = slave_audio_activate; + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_slave_class_audio_instance_deactivate = slave_audio_deactivate; + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_device_class_audio_control_process = slave_audio_control_process; + slave_audio_parameter.ux_device_class_audio_parameter_callbacks.ux_device_class_audio_arg = UX_NULL; + +#if defined(UX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT) + slave_audio_parameter.ux_device_class_audio_parameter_status_queue_size = 2; + slave_audio_parameter.ux_device_class_audio_parameter_status_size = 6; +#endif + + g_slave_audio20_control[0].ux_device_class_audio20_control_cs_id = 0x10; + g_slave_audio20_control[0].ux_device_class_audio20_control_sampling_frequency = 48000; + g_slave_audio20_control[0].ux_device_class_audio20_control_fu_id = 2; + g_slave_audio20_control[0].ux_device_class_audio20_control_mute[0] = 0; + g_slave_audio20_control[0].ux_device_class_audio20_control_volume[0] = 0; + g_slave_audio20_control[1].ux_device_class_audio20_control_cs_id = 0x10; + g_slave_audio20_control[1].ux_device_class_audio20_control_sampling_frequency = 48000; + g_slave_audio20_control[1].ux_device_class_audio20_control_fu_id = 5; + g_slave_audio20_control[1].ux_device_class_audio20_control_mute[0] = 0; + g_slave_audio20_control[1].ux_device_class_audio20_control_volume[0] = 0; + +#if 0 + printf("Memory requirement UX_HOST_CLASS_:\n"); + printf(" per _AUDIO: %d bytes\n", sizeof(UX_HOST_CLASS_AUDIO)); + printf(" per _AUDIO_TRANSFER_REQUEST: %d bytes\n", sizeof(UX_HOST_CLASS_AUDIO_TRANSFER_REQUEST)); + printf(" per _AUDIO_CONTROL: %d bytes\n", sizeof(UX_HOST_CLASS_AUDIO_CONTROL)); + printf(" per _AUDIO_SAMPLING: %d bytes\n", sizeof(UX_HOST_CLASS_AUDIO_SAMPLING)); + printf(" per _AUDIO_SAMPLING_ATTR: %d bytes\n", sizeof(UX_HOST_CLASS_AUDIO_SAMPLING_CHARACTERISTICS)); +#endif + + /* Initialize the device Audio class. This class owns interfaces starting with 0, 1, 2. */ + status = ux_device_stack_class_register(_ux_system_slave_class_audio_name, ux_device_class_audio_entry, + 1, 0, &slave_audio_parameter); + UX_TEST_CHECK_SUCCESS(status); + + /* Hook ISO transfers. */ + ux_test_link_hooks_from_array(ux_host_class_audio_transfer_hook); + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main event group. */ + status = tx_event_flags_create(&tx_test_events, "tx_test_events"); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx demo host simulation", tx_test_thread_host_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx demo slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_CHECK_SUCCESS(status); +} + +static UINT test_wait_until_expected(VOID **ptr, ULONG loop, VOID *expected) +{ + while(loop) + { + _ux_utility_delay_ms(10); + if (*ptr == expected) + return UX_SUCCESS; + } + return UX_ERROR; +} +static UINT test_wait_until_not_expected(VOID **ptr, ULONG loop, VOID *expected) +{ + while(loop) + { + _ux_utility_delay_ms(10); + if (*ptr != expected) + return UX_SUCCESS; + } + return UX_ERROR; +} +#define test_wait_until_not_null(ptr, loop) test_wait_until_not_expected(ptr, loop, UX_NULL) +#define test_wait_until_null(ptr, loop) test_wait_until_expected(ptr, loop, UX_NULL) + +static void _memory_tests(void) +{ +ULONG test_n; +ULONG mem_free; + + /* Test disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Reset testing counts. */ + ux_test_utility_sim_mutex_create_count_reset(); + ux_test_utility_sim_sem_create_count_reset(); + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + /* Save free memory usage. */ + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + tx_thread_sleep(100); + /* Log create counts for further tests. */ + rsc_enum_mutex_usage = rsc_mutex_on_set_cfg; + rsc_enum_sem_usage = rsc_sem_on_set_cfg; + rsc_enum_mem_usage = mem_free - rsc_mem_free_on_set_cfg; + rsc_enum_mem_alloc_count = rsc_mem_alloc_cnt_on_set_cfg; + /* Log create counts when instances active for further tests. */ + rsc_audio_mutex_usage = ux_test_utility_sim_mutex_create_count() - rsc_enum_mutex_usage; + rsc_audio_sem_usage = ux_test_utility_sim_sem_create_count() - rsc_enum_sem_usage; + rsc_audio_mem_usage = rsc_mem_free_on_set_cfg - _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + rsc_audio_mem_alloc_count = ux_test_utility_sim_mem_alloc_count() - rsc_enum_mem_alloc_count; + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + + /* Lock log base for tests. */ + ux_test_utility_sim_mem_alloc_log_lock(); + + stepinfo("enum mem: %ld\n", rsc_enum_mem_alloc_count); + stepinfo("cdc mem : %ld\n", rsc_audio_mem_alloc_count); + stepinfo("mem free: %ld, %ld\n", _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); + + /* Simulate detach and attach for FS enumeration, + and check if there is memory error in normal enumeration. + */ + stepinfo(">>>>>>>>>>>> Enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < 3; test_n++) + { + stepinfo("%4ld / 2\n", test_n); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #11.%ld: Memory level different after re-enumerations %ld <> %ld\n", test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on error. */ + ux_test_breakable_sleep(100, sleep_break_on_error); + + /* Check */ + if (!host_audio_tx || !host_audio_rx) + { + + printf("ERROR #12.%ld: Enumeration fail\n", test_n); + test_control_return(1); + } + } + + /* Simulate detach and attach for FS enumeration, + and test possible memory allocation error handlings. + */ + if (rsc_audio_mem_alloc_count) stepinfo(">>>>>>>>>>>> Memory errors enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_audio_mem_alloc_count; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_audio_mem_alloc_count - 1); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #11.%ld: Memory level different after re-enumerations %ld <> %ld\n", test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Set memory error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n + rsc_enum_mem_alloc_count); + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on errors. */ + ux_test_breakable_sleep(100, sleep_break_on_error); + + /* Check error */ + if (host_audio_tx && host_audio_rx) + { + + printf("ERROR #12.%ld: device detected when there is memory error\n", test_n); + test_control_return(1); + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + } + ux_test_utility_sim_mem_alloc_error_generation_stop(); + if (rsc_audio_mem_alloc_count) stepinfo("\n"); +} + +static void _feature_control_tests(void) +{ +UX_HOST_CLASS_AUDIO_CONTROL audio_control; +UINT status; +UCHAR buffer[32]; +ULONG actual_length; + +#if !defined(UX_HOST_CLASS_AUDIO_DISABLE_CONTROLS) + RESET_CALLBACK_INVOKE_LOG(); + + audio_control.ux_host_class_audio_control_channel = 1; + audio_control.ux_host_class_audio_control = UX_HOST_CLASS_AUDIO_VOLUME_CONTROL; + status = ux_host_class_audio_control_get(host_audio_tx, &audio_control); + // UX_TEST_ASSERT(status == UX_TRANSFER_STALLED); + UX_TEST_ASSERT(callback_invoke_count == 1); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_control_process); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream->ux_device_class_audio_stream_audio); + + audio_control.ux_host_class_audio_control_channel = 1; + audio_control.ux_host_class_audio_control = UX_HOST_CLASS_AUDIO_VOLUME_CONTROL; + audio_control.ux_host_class_audio_control_cur = 0xfff0; + status = ux_host_class_audio_control_value_set(host_audio_tx, &audio_control); + // UX_TEST_ASSERT(status == UX_TRANSFER_STALLED); + UX_TEST_ASSERT(callback_invoke_count == 2); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_control_process); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_rx_stream->ux_device_class_audio_stream_audio); + + audio_control.ux_host_class_audio_control_channel = 2; + audio_control.ux_host_class_audio_control = UX_HOST_CLASS_AUDIO_VOLUME_CONTROL; + status = ux_host_class_audio_control_get(host_audio_tx, &audio_control); + // UX_TEST_ASSERT(status == UX_TRANSFER_STALLED); + UX_TEST_ASSERT(callback_invoke_count == 3); + UX_TEST_ASSERT(callback_invoke_log[2].func == slave_audio_control_process); + UX_TEST_ASSERT(callback_invoke_log[2].param1 == slave_audio_rx_stream->ux_device_class_audio_stream_audio); + + audio_control.ux_host_class_audio_control_channel = 2; + audio_control.ux_host_class_audio_control = UX_HOST_CLASS_AUDIO_VOLUME_CONTROL; + audio_control.ux_host_class_audio_control_cur = 0xfff0; + status = ux_host_class_audio_control_value_set(host_audio_tx, &audio_control); + // UX_TEST_ASSERT(status == UX_TRANSFER_STALLED); + UX_TEST_ASSERT(callback_invoke_count == 4); + UX_TEST_ASSERT(callback_invoke_log[3].func == slave_audio_control_process); + UX_TEST_ASSERT(callback_invoke_log[3].param1 == slave_audio_rx_stream->ux_device_class_audio_stream_audio); +#endif + + RESET_CALLBACK_INVOKE_LOG(); + + audio_control.ux_host_class_audio_control_entity = 0x05; + audio_control.ux_host_class_audio_control_size = 2; + audio_control.ux_host_class_audio_control = UX_HOST_CLASS_AUDIO_VOLUME_CONTROL; + + audio_control.ux_host_class_audio_control_channel = 1; + status = ux_host_class_audio_entity_control_get(host_audio_tx, &audio_control); + UX_TEST_ASSERT(callback_invoke_count == 1); + UX_TEST_ASSERT(callback_invoke_log[0].func == slave_audio_control_process); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == slave_audio_rx_stream->ux_device_class_audio_stream_audio); + + audio_control.ux_host_class_audio_control_cur = 0xfff0; + status = ux_host_class_audio_entity_control_value_set(host_audio_tx, &audio_control); + UX_TEST_ASSERT(callback_invoke_count == 2); + UX_TEST_ASSERT(callback_invoke_log[1].func == slave_audio_control_process); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == slave_audio_rx_stream->ux_device_class_audio_stream_audio); + + audio_control.ux_host_class_audio_control_channel = 2; + status = ux_host_class_audio_entity_control_get(host_audio_tx, &audio_control); + UX_TEST_ASSERT(callback_invoke_count == 3); + UX_TEST_ASSERT(callback_invoke_log[2].func == slave_audio_control_process); + UX_TEST_ASSERT(callback_invoke_log[2].param1 == slave_audio_rx_stream->ux_device_class_audio_stream_audio); + + audio_control.ux_host_class_audio_control_cur = 0xfff0; + status = ux_host_class_audio_entity_control_value_set(host_audio_tx, &audio_control); + UX_TEST_ASSERT(callback_invoke_count == 4); + UX_TEST_ASSERT(callback_invoke_log[3].func == slave_audio_control_process); + UX_TEST_ASSERT(callback_invoke_log[3].param1 == slave_audio_rx_stream->ux_device_class_audio_stream_audio); + +#if defined(UX_HOST_CLASS_AUDIO_2_SUPPORT) /* Class consts included. */ + + buffer[0] = 0x5a; + status = ux_host_class_audio_control_request(host_audio_tx, 0, + 0x21, UX_CLASS_AUDIO20_CUR, + 0 | (UX_CLASS_AUDIO20_FU_MUTE_CONTROL << 8), + 0x05, + buffer, 1, &actual_length); + UX_TEST_CHECK_SUCCESS(status); + + buffer[0] = 0; + status = ux_host_class_audio_control_request(host_audio_tx, 0, + 0xa1, UX_CLASS_AUDIO20_CUR, + 0 | (UX_CLASS_AUDIO20_FU_MUTE_CONTROL << 8), + 0x05, + buffer, 1, &actual_length); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(buffer[0] == 0x5a); + + status = ux_host_class_audio_control_request(host_audio_tx, 0, + 0xa1, UX_CLASS_AUDIO20_CUR, + 0 | (UX_CLASS_AUDIO20_CM_DENOMINATOR_CONTROL << 8), + 0x10, + buffer, 2, &actual_length); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(buffer[0] == 2 && buffer[1] == 0); + + status = ux_host_class_audio_control_request(host_audio_tx, 0, + 0xa1, UX_CLASS_AUDIO20_CUR, + 0 | (UX_CLASS_AUDIO20_CM_NUMERATOR_CONTROL << 8), + 0x10, + buffer, 2, &actual_length); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(buffer[0] == 12 && buffer[1] == 0); + + status = ux_host_class_audio_control_request(host_audio_tx, 0, + 0xa1, UX_CLASS_AUDIO20_CUR, + 0 | (UX_CLASS_AUDIO20_CS_SAM_FREQ_CONTROL << 8), + 0x11, + buffer, 4, &actual_length); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(*(ULONG*)buffer == 8000); +#endif +} + +static void _sampling_control_tests(void) +{ +UINT status; +UX_HOST_CLASS_AUDIO_SAMPLING sampling; + + RESET_CALLBACK_INVOKE_LOG(); + + sampling.ux_host_class_audio_sampling_channels = 2; + sampling.ux_host_class_audio_sampling_frequency = 44100; + sampling.ux_host_class_audio_sampling_resolution = 16; + status = ux_host_class_audio_streaming_sampling_set(host_audio_tx, &sampling); + UX_TEST_CHECK_NOT_SUCCESS(status); + + sampling.ux_host_class_audio_sampling_channels = 4; + sampling.ux_host_class_audio_sampling_frequency = 48000; + sampling.ux_host_class_audio_sampling_resolution = 16; + status = ux_host_class_audio_streaming_sampling_set(host_audio_tx, &sampling); + UX_TEST_CHECK_NOT_SUCCESS(status); + + sampling.ux_host_class_audio_sampling_channels = 2; + sampling.ux_host_class_audio_sampling_frequency = 48000; + sampling.ux_host_class_audio_sampling_resolution = 32; + status = ux_host_class_audio_streaming_sampling_set(host_audio_tx, &sampling); + UX_TEST_CHECK_NOT_SUCCESS(status); + + sampling.ux_host_class_audio_sampling_channels = 2; + sampling.ux_host_class_audio_sampling_frequency = 48000; + sampling.ux_host_class_audio_sampling_resolution = 16; + status = ux_host_class_audio_streaming_sampling_set(host_audio_tx, &sampling); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(callback_invoke_count > 1); /* There could be multiple requests. */ + UX_TEST_ASSERT(callback_invoke_log[callback_invoke_count-1].func == slave_audio_rx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[callback_invoke_count-1].param1 == slave_audio_rx_stream); + UX_TEST_ASSERT(ux_host_class_audio_max_packet_size_get(host_audio_tx) == 256); + UX_TEST_ASSERT(host_audio_tx->ux_host_class_audio_packet_fraction == 0); + UX_TEST_ASSERT(host_audio_tx->ux_host_class_audio_packet_freq == 1000); + UX_TEST_ASSERT(host_audio_tx->ux_host_class_audio_packet_size == 192); + + sampling.ux_host_class_audio_sampling_channels = 2; + sampling.ux_host_class_audio_sampling_frequency = 48000; + sampling.ux_host_class_audio_sampling_resolution = 16; + status = ux_host_class_audio_streaming_sampling_set(host_audio_rx, &sampling); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(callback_invoke_log[callback_invoke_count-1].func == slave_audio_tx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[callback_invoke_count-1].param1 == slave_audio_tx_stream); + UX_TEST_ASSERT(ux_host_class_audio_max_packet_size_get(host_audio_rx) == 256); + UX_TEST_ASSERT(host_audio_rx->ux_host_class_audio_packet_fraction == 0); + UX_TEST_ASSERT(host_audio_rx->ux_host_class_audio_packet_freq == 1000); + UX_TEST_ASSERT(host_audio_rx->ux_host_class_audio_packet_size == 192); +} + +static void _audio_request_completion(UX_HOST_CLASS_AUDIO_TRANSFER_REQUEST *transfer) +{ + UX_PARAMETER_NOT_USED(transfer); + SAVE_CALLBACK_INVOKE_LOG(_audio_request_completion, transfer, 0, 0); +} +static void _audio_requests_tests(void) +{ +UINT status; + + RESET_CALLBACK_INVOKE_LOG(); + + /* Prepare the 2 audio transfer_requests */ + audio_transfer1.ux_host_class_audio_transfer_request_completion_function = _audio_request_completion; + audio_transfer2.ux_host_class_audio_transfer_request_completion_function = _audio_request_completion; + audio_transfer1.ux_host_class_audio_transfer_request_class_instance = host_audio_tx; + audio_transfer2.ux_host_class_audio_transfer_request_class_instance = host_audio_tx; + audio_transfer1.ux_host_class_audio_transfer_request_next_audio_transfer_request = &audio_transfer1; + audio_transfer2.ux_host_class_audio_transfer_request_next_audio_transfer_request = UX_NULL; + + audio_transfer1.ux_host_class_audio_transfer_request_data_pointer = host_audio_buffer[0]; + audio_transfer1.ux_host_class_audio_transfer_request_requested_length = sizeof(host_audio_buffer[0]); + audio_transfer1.ux_host_class_audio_transfer_request.ux_transfer_request_packet_length = 192; + + audio_transfer2.ux_host_class_audio_transfer_request_data_pointer = host_audio_buffer[1]; + audio_transfer2.ux_host_class_audio_transfer_request_requested_length = sizeof(host_audio_buffer[1]); + audio_transfer2.ux_host_class_audio_transfer_request.ux_transfer_request_packet_length = 192; + + // ux_test_set_main_action_list_from_array(ux_host_class_audio_tx_action); + + status = ux_host_class_audio_write(host_audio_tx, &audio_transfer1); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(callback_invoke_count == 2); + UX_TEST_ASSERT(callback_invoke_log[0].func == ux_host_class_audio_tx_hook); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == (void*)0x02); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (void*)sizeof(host_audio_buffer[0])); + UX_TEST_ASSERT(callback_invoke_log[1].func == _audio_request_completion); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == &audio_transfer1); + + status = ux_host_class_audio_write(host_audio_tx, &audio_transfer2); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(callback_invoke_count == 4); + UX_TEST_ASSERT(callback_invoke_log[2].func == ux_host_class_audio_tx_hook); + UX_TEST_ASSERT(callback_invoke_log[2].param1 == (void*)0x02); + UX_TEST_ASSERT(callback_invoke_log[2].param2 == (void*)sizeof(host_audio_buffer[1])); + UX_TEST_ASSERT(callback_invoke_log[3].func == _audio_request_completion); + UX_TEST_ASSERT(callback_invoke_log[3].param1 == &audio_transfer2); + + // ux_test_set_main_action_list_from_array(ux_host_class_audio_rx_action); + + status = ux_host_class_audio_read(host_audio_rx, &audio_transfer1); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(callback_invoke_count == 6); + UX_TEST_ASSERT(callback_invoke_log[4].func == ux_host_class_audio_rx_hook); + UX_TEST_ASSERT(callback_invoke_log[4].param1 == (void*)0x81); + UX_TEST_ASSERT(callback_invoke_log[4].param2 == (void*)256); + UX_TEST_ASSERT(callback_invoke_log[5].func == _audio_request_completion); + UX_TEST_ASSERT(callback_invoke_log[5].param1 == &audio_transfer1); + + status = ux_host_class_audio_read(host_audio_rx, &audio_transfer2); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(callback_invoke_count == 8); + UX_TEST_ASSERT(callback_invoke_log[6].func == ux_host_class_audio_rx_hook); + UX_TEST_ASSERT(callback_invoke_log[6].param1 == (void*)0x81); + UX_TEST_ASSERT(callback_invoke_log[6].param2 == (void*)256); + UX_TEST_ASSERT(callback_invoke_log[7].func == _audio_request_completion); + UX_TEST_ASSERT(callback_invoke_log[7].param1 == &audio_transfer2); +} +#if UX_DEMO_FEEDBACK +static void _audio_feedback_tests(void) +{ +ULONG host_feedback; +UINT status; + + tx_thread_suspend(&tx_test_thread_slave_simulation); + + host_feedback = 0; + status = ux_host_class_audio_feedback_set(host_audio_tx, (UCHAR *)&host_feedback); + UX_TEST_CHECK_SUCCESS(status); + + host_feedback = 0xFF; + status = ux_host_class_audio_feedback_get(host_audio_tx, (UCHAR *)&host_feedback); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(0 == host_feedback); + + tx_thread_resume(&tx_test_thread_slave_simulation); + + + feedback_data = 0x123456; + ux_utility_delay_ms(20); + status = ux_host_class_audio_feedback_get(host_audio_tx, (UCHAR *)&host_feedback); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(feedback_data == host_feedback); + + feedback_data = 0x654321; + ux_utility_delay_ms(20); + status = ux_host_class_audio_feedback_get(host_audio_tx, (UCHAR *)&host_feedback); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(feedback_data == host_feedback); +} +#endif + +static void _audio_stop_test(void) +{ +UINT status; + RESET_CALLBACK_INVOKE_LOG(); + status = ux_host_class_audio_stop(host_audio_tx); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(callback_invoke_count == 1); + UX_TEST_ASSERT(callback_invoke_log[callback_invoke_count-1].func == slave_audio_rx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[callback_invoke_count-1].param1 == slave_audio_rx_stream); + + status = ux_host_class_audio_stop(host_audio_rx); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(callback_invoke_count == 2); + UX_TEST_ASSERT(callback_invoke_log[callback_invoke_count-1].func == slave_audio_tx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[callback_invoke_count-1].param1 == slave_audio_tx_stream); +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +UCHAR test_tmp[32]; +ULONG temp; + + /* Test connect. */ + status = test_wait_until_not_null((void**)&host_audio_rx, 100); + status |= test_wait_until_not_null((void**)&host_audio_tx, 100); + status |= test_wait_until_not_null((void**)&slave_audio_tx_stream, 100); + status |= test_wait_until_not_null((void**)&slave_audio_rx_stream, 100); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(ux_host_class_audio_protocol_get(host_audio_rx) == UX_HOST_CLASS_AUDIO_PROTOCOL_IP_VERSION_02_00); + UX_TEST_ASSERT(ux_host_class_audio_type_get(host_audio_rx) == UX_HOST_CLASS_AUDIO_INPUT); + UX_TEST_ASSERT(ux_host_class_audio_speed_get(host_audio_rx) == UX_FULL_SPEED_DEVICE); + + /* Check enumeration information. */ + UX_TEST_ASSERT(host_audio_rx->ux_host_class_audio_control_interface_number == 0); + UX_TEST_ASSERT(host_audio_rx->ux_host_class_audio_streaming_interface->ux_interface_descriptor.bInterfaceNumber == 1); + UX_TEST_ASSERT(host_audio_tx->ux_host_class_audio_control_interface_number == 0); + UX_TEST_ASSERT(host_audio_tx->ux_host_class_audio_streaming_interface->ux_interface_descriptor.bInterfaceNumber == 2); + + _memory_tests(); + _feature_control_tests(); + _sampling_control_tests(); + _audio_requests_tests(); +#if UX_DEMO_FEEDBACK + _audio_feedback_tests(); +#endif + _audio_stop_test(); + + /* Wait pending threads. */ + _ux_utility_thread_sleep(1); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + ux_device_stack_class_unregister(_ux_system_slave_class_audio_name, ux_device_class_audio_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + while(1) + { + +#if UX_DEMO_FEEDBACK + UINT status; + ULONG events; + status = tx_event_flags_get(&tx_test_events, 0x1u, TX_OR_CLEAR, &events, 10); + if (status == UX_SUCCESS) + { + /* Simulate ISO transfer done event. */ + feedback_transfer -> ux_transfer_request_completion_code = UX_SUCCESS; + if (feedback_transfer -> ux_transfer_request_completion_function) + feedback_transfer -> ux_transfer_request_completion_function(feedback_transfer); + _ux_host_semaphore_put(&feedback_transfer -> ux_transfer_request_semaphore); + ux_utility_delay_ms(1); + } +#else + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); +#endif + } +} diff --git a/test/regression/usbx_bus_powered_hub_conn_to_self_and_bus_powered_hub_test.c b/test/regression/usbx_bus_powered_hub_conn_to_self_and_bus_powered_hub_test.c new file mode 100644 index 00000000..740c578d --- /dev/null +++ b/test/regression/usbx_bus_powered_hub_conn_to_self_and_bus_powered_hub_test.c @@ -0,0 +1,110 @@ +/* This tests the case where a bus-powered hub is connected to a self-powered hub. */ + +#include "usbx_ux_test_hub.h" + +static unsigned char device_framework_bus_powered[] = { + + /* Device Descriptor */ + 0x12, /* bLength */ + 0x01, /* bDescriptorType */ + 0x00, 0x02, /* bcdUSB */ + 0x09, /* bDeviceClass - Hub */ + 0x00, /* bDeviceSubClass */ + 0x01, /* bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 */ + 0x24, 0x04, /* idVendor */ + 0x12, 0x24, /* idProduct */ + 0xb2, 0x0b, /* bcdDevice */ + 0x00, /* iManufacturer */ + 0x00, /* iProduct */ + 0x00, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ + + /* Configuration Descriptor */ + 0x09, /* bLength */ + 0x02, /* bDescriptorType */ + 0x19, 0x00, /* wTotalLength */ + 0x01, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xa0, /* bmAttributes - Bus-powered */ + 0x01, /* bMaxPower */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x09, /* bInterfaceClass - Hub */ + 0x00, /* bInterfaceSubClass */ + 0x00, /* bInterfaceProtocol */ + 0x00, /* iInterface */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x81, /* bEndpointAddress */ + 0x03, /* bmAttributes - Interrupt */ + 0x02, 0x00, /* wMaxPacketSize */ + 0x0c, /* bInterval */ + +}; + +static DEVICE_INIT_DATA device_init_data = { + .framework = device_framework_bus_powered, + .framework_length = sizeof(device_framework_bus_powered), +}; + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_bus_powered_hub_connected_to_self_and_bus_powered_hub_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ +#if UX_MAX_DEVICES > 1 + printf("Running Hub Bus Powered Hub Connected....Test....................... "); +#else + printf("Running Hub Bus Powered Hub Connected....Skip max 1 device.......... SUCCESS!\n"); + test_control_return(0); + return; +#endif + + stepinfo("\n"); + + initialize_hub_with_device_init_data(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ +#if UX_MAX_DEVICES > 1 +UX_DEVICE parent; + + stepinfo("test this hub connected to a self-powered hub\n"); + + parent.ux_device_power_source = UX_DEVICE_SELF_POWERED; + + g_hub_host->ux_host_class_hub_device->ux_device_parent = &parent; + UX_TEST_CHECK_SUCCESS(_ux_host_class_hub_configure(g_hub_host)); + + /* Should've been null originally. */ + g_hub_host->ux_host_class_hub_device->ux_device_parent = UX_NULL; + + stepinfo("test this hub connected to a bus-powered hub\n"); + + parent.ux_device_power_source = UX_DEVICE_BUS_POWERED; + + g_hub_host->ux_host_class_hub_device->ux_device_parent = &parent; + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HUB, UX_CONNECTION_INCOMPATIBLE)); + UX_TEST_CHECK_NOT_SUCCESS(_ux_host_class_hub_configure(g_hub_host)); + + /* Should've been null originally. */ + g_hub_host->ux_host_class_hub_device->ux_device_parent = UX_NULL; +#endif +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_acm_basic_memory_test.c b/test/regression/usbx_cdc_acm_basic_memory_test.c new file mode 100644 index 00000000..bbcf48b9 --- /dev/null +++ b/test/regression/usbx_cdc_acm_basic_memory_test.c @@ -0,0 +1,854 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" +#include "ux_host_class_cdc_acm.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static TX_THREAD ux_test_thread_host_simulation; +static TX_THREAD ux_test_thread_slave_simulation; +static void ux_test_thread_host_simulation_entry(ULONG); +static void ux_test_thread_slave_simulation_entry(ULONG); + +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +static UCHAR cdc_acm_slave_change; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_cdc_sem_usage; +static ULONG rsc_cdc_sem_get_count; +static ULONG rsc_cdc_mutex_usage; +static ULONG rsc_cdc_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +/* Define device framework. */ + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 93 +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 103 +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Configuration 1 descriptor 9 bytes */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Endpoint 0x83 descriptor 7 bytes */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, /* @ 93 - 14 + 2 = 81 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, /* @ 93 - 7 + 2 = 88 */ + 0x02, + 0x40, 0x00, + 0x00, + +}; + +#define DEVICE_FRAMEWORK_EPA_POS_1_FS (DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 14 + 2) +#define DEVICE_FRAMEWORK_EPA_POS_2_FS (DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 7 + 2) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor */ + 0x05, 0x24, 0x06, + 0x00, + 0x01, + + /* Call Management Functional Descriptor */ + 0x05, 0x24, 0x01, + 0x00, + 0x01, + + /* Endpoint 0x83 descriptor */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor */ + 0x07, 0x05, 0x02, /* @ 103 - 14 + 2 = 91 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor */ + 0x07, 0x05, 0x81, /* @ 103 - 7 + 2 = 98 */ + 0x02, + 0x40, 0x00, + 0x00, + +}; + +#define DEVICE_FRAMEWORK_EPA_POS_1_HS (DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 14 + 2) +#define DEVICE_FRAMEWORK_EPA_POS_2_HS (DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 7 + 2) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 + }; + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +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; +} + +static UINT demo_class_cdc_acm_get(void) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_CDC_ACM *cdc_acm_host; + + + /* Find the main cdc_acm container */ + status = ux_host_stack_class_get(_ux_system_host_class_cdc_acm_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* We get the first instance of the cdc_acm device */ + do + { + + status = ux_host_stack_class_instance_get(class, 0, (void **) &cdc_acm_host); + tx_thread_sleep(10); + } while (status != UX_SUCCESS); + + /* We still need to wait for the cdc_acm status to be live */ + while (cdc_acm_host -> ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + tx_thread_sleep(10); + + /* Isolate both the control and data interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_DATA_CLASS) + { + /* This is the data interface. */ + cdc_acm_host_data = cdc_acm_host; + + /* In that case, the second one should be the control interface. */ + status = ux_host_stack_class_instance_get(class, 1, (void **) &cdc_acm_host); + + /* Check error. */ + if (status != UX_SUCCESS) + return(status); + + /* Check for the control interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + + /* This is the control interface. */ + cdc_acm_host_control = cdc_acm_host; + + return(UX_SUCCESS); + + } + } + else + { + /* Check for the control interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + + /* This is the control interface. */ + cdc_acm_host_control = cdc_acm_host; + + /* In that case, the second one should be the data interface. */ + status = ux_host_stack_class_instance_get(class, 1, (void **) &cdc_acm_host); + + /* Check error. */ + if (status != UX_SUCCESS) + return(status); + + /* Check for the data interface. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_DATA_CLASS) + { + + /* This is the data interface. */ + cdc_acm_host_data = cdc_acm_host; + + return(UX_SUCCESS); + + } + } + } + + /* Return ERROR. */ + return(UX_ERROR); +} + +static UINT demo_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; +} + +static VOID test_swap_framework_bulk_ep_descriptors(VOID) +{ +UCHAR tmp; + + tmp = device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_1_FS]; + device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_1_FS] = device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_2_FS]; + device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_2_FS] = tmp; + + tmp = device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_1_HS]; + device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_1_HS] = device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_2_HS]; + device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_2_HS] = tmp; +} + +static VOID test_slave_cdc_acm_transfer_disconnect(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, ULONG ep_dir) +{ + +UX_SLAVE_ENDPOINT *endpoint; +UX_SLAVE_DEVICE *device; +UX_SLAVE_INTERFACE *interface; +UX_SLAVE_TRANSFER *transfer_request; + + /* Get the pointer to the device. */ + device = &_ux_system_slave -> ux_system_slave_device; + + /* This is the first time we are activated. We need the interface to the class. */ + interface = cdc_acm -> ux_slave_class_cdc_acm_interface; + + /* Locate the endpoints. */ + endpoint = interface -> ux_slave_interface_first_endpoint; + + /* Check the endpoint direction, if OUT we have the correct endpoint. */ + if ((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) != ep_dir) + { + + /* So the next endpoint has to be the OUT endpoint. */ + endpoint = endpoint -> ux_slave_endpoint_next_endpoint; + } + + /* All CDC reading are on the endpoint OUT, from the host. */ + transfer_request = &endpoint -> ux_slave_endpoint_transfer_request; + + /* Continue transfer. */ + transfer_request -> ux_slave_transfer_request_actual_length = endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize; + + /* Change device state. */ + device -> ux_slave_device_state = UX_DEVICE_ATTACHED; + + /* Inform hcd. */ + _ux_utility_semaphore_put(&transfer_request -> ux_slave_transfer_request_semaphore); + + /* Wait a while for transfer request handling. */ + tx_thread_sleep(50); + + /* Change device state. */ + device -> ux_slave_device_state = UX_DEVICE_CONFIGURED; +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *_params) +{ + + set_cfg_counter ++; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_sem_get_on_set_cfg = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_acm_basic_memory_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + /* Inform user. */ + printf("Running CDC ACM Basic Memory Test................................... "); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* 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 #1\n"); + 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(demo_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #2\n"); + test_control_return(1); + } + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_entry); + if (status != UX_SUCCESS) + { + + printf("ERROR #3\n"); + 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 #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + + if(status!=UX_SUCCESS) + { + + printf("ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #7\n"); + 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 #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_host_simulation, "tx demo host simulation", ux_test_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 #8\n"); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&ux_test_thread_slave_simulation, "tx demo slave simulation", ux_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #9\n"); + test_control_return(1); + } +} + +void ux_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_SLAVE_CLASS_CDC_ACM * cdc_acm_slave_bak; +UX_HOST_CLASS_CDC_ACM * cdc_acm_host_ctrl_bak; +UX_HOST_CLASS_CDC_ACM * cdc_acm_host_data_bak; +ULONG test_n; +ULONG mem_free; +ULONG retry; + + stepinfo("\n"); + + /* Find the cdc_acm class and wait for the link to be up. */ + status = demo_class_cdc_acm_get(); + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #10\n"); + test_control_return(1); + } + + /* Save slave instance for later tests. */ + cdc_acm_slave_bak = cdc_acm_slave; + /* Save host instances for later tests. */ + cdc_acm_host_ctrl_bak = cdc_acm_host_control; + cdc_acm_host_data_bak = cdc_acm_host_data; + + /* Test disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_count_reset(); + ux_test_utility_sim_mutex_create_count_reset(); + ux_test_utility_sim_sem_create_count_reset(); + ux_test_utility_sim_sem_get_count_reset(); + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + + /* Save free memory usage. */ + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + for (retry = 0; (retry < 10) && (cdc_acm_host_control == UX_NULL || cdc_acm_host_data == UX_NULL); retry ++) + tx_thread_sleep(10); + + /* Log create counts for further tests. */ + rsc_enum_mutex_usage = rsc_mutex_on_set_cfg; + rsc_enum_sem_usage = rsc_sem_on_set_cfg; + rsc_enum_mem_alloc_count = rsc_mem_alloc_cnt_on_set_cfg; + /* Log create counts when instances active for further tests. */ + rsc_cdc_mutex_usage = ux_test_utility_sim_mutex_create_count() - rsc_enum_mutex_usage; + rsc_cdc_sem_usage = ux_test_utility_sim_sem_create_count() - rsc_enum_sem_usage; + rsc_cdc_mem_alloc_count = ux_test_utility_sim_mem_alloc_count() - rsc_enum_mem_alloc_count; + + /* Lock log base for tests. */ + ux_test_utility_sim_mem_alloc_log_lock(); + + stepinfo("enum mem: %ld\n", rsc_enum_mem_alloc_count); + stepinfo("cdc mem : %ld\n", rsc_cdc_mem_alloc_count); + stepinfo("mem free: %ld, %ld\n", _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); + + /* Simulate detach and attach for FS enumeration, + and check if there is memory error in normal enumeration. + */ + stepinfo(">>>>>>>>>>>> Enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < 3; test_n++) + { + stepinfo("%4ld / 2\n", test_n); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #11.%ld: Memory level different after re-enumerations %ld <> %ld\n", test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on error. */ + ux_test_breakable_sleep(100, sleep_break_on_error); + + /* Check */ + if (!cdc_acm_host_control || !cdc_acm_host_data) + { + + printf("ERROR #12.%ld: Enumeration fail\n", test_n); + test_control_return(1); + } + } + + /* Simulate detach and attach for FS enumeration, + and test possible memory allocation error handlings. + */ + if (rsc_cdc_mem_alloc_count) stepinfo(">>>>>>>>>>>> Memory errors enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_cdc_mem_alloc_count; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_cdc_mem_alloc_count - 1); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #11.%ld: Memory level different after re-enumerations %ld <> %ld\n", test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Set memory error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n + rsc_enum_mem_alloc_count); + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on errors. */ + ux_test_breakable_sleep(100, sleep_break_on_error); + + /* Check error */ + if (cdc_acm_host_control && cdc_acm_host_data) + { + + printf("ERROR #12.%ld: device detected when there is memory error\n", test_n); + test_control_return(1); + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + } + ux_test_utility_sim_mem_alloc_error_generation_stop(); + if (rsc_cdc_mem_alloc_count) stepinfo("\n"); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_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 ux_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); + } +} diff --git a/test/regression/usbx_cdc_acm_basic_test.c b/test/regression/usbx_cdc_acm_basic_test.c new file mode 100644 index 00000000..9997c4ce --- /dev/null +++ b/test/regression/usbx_cdc_acm_basic_test.c @@ -0,0 +1,3086 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#define UX_DEMO_REQUEST_MAX_LENGTH \ + ((UX_HCD_SIM_HOST_MAX_PAYLOAD) > (UX_SLAVE_REQUEST_DATA_MAX_LENGTH) ? \ + (UX_HCD_SIM_HOST_MAX_PAYLOAD) : (UX_SLAVE_REQUEST_DATA_MAX_LENGTH)) + +/* Define constants. */ +#define UX_CDC_ACM_CONNECTION_DELAY ((UX_RH_ENUMERATION_RETRY + 1)*UX_HOST_CLASS_CDC_ACM_DEVICE_INIT_DELAY) +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_DEMO_REQUEST_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (128*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static void test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static void tx_test_thread_host_simulation_entry(ULONG); +static void tx_test_thread_slave_simulation_entry(ULONG); +static void test_thread_host_reception_callback(UX_HOST_CLASS_CDC_ACM *cdc_acm, UINT status, UCHAR *reception_buffer, ULONG reception_size); +static VOID demo_cdc_instance_activate(VOID *cdc_instance); +static VOID demo_cdc_instance_deactivate(VOID *cdc_instance); +static VOID demo_cdc_instance_parameter_change(VOID *cdc_instance); +static UINT test_usbx_simulator_cdc_acm_host_send_command(UCHAR *string, ULONG length, ULONG no_ack); +static UINT tx_test_thread_slave_simulation_response(UCHAR *string, ULONG length); + +static UINT ux_test_host_class_cdc_acm_command(UX_HOST_CLASS_CDC_ACM *cdc_acm, ULONG command, ULONG value, UCHAR *data_buffer, ULONG data_length, ULONG *actual_length); + +static VOID ux_test_host_class_cdc_acm_device_status_change_callback(struct UX_HOST_CLASS_CDC_ACM_STRUCT *cdc_acm, + ULONG notification_type, ULONG notification_value); + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_interaction_request_sem_put(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_interaction_invoked(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_interaction_wait_transfer_disconnection(UX_TEST_ACTION *action, VOID *params); + +#define test_usbx_simulator_cdc_acm_host_send_at_command(s,l) test_usbx_simulator_cdc_acm_host_send_command(s,l,UX_FALSE) +#define test_usbx_simulator_cdc_acm_host_send_string(s,l) test_usbx_simulator_cdc_acm_host_send_command(s,l,UX_TRUE) + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; +static ULONG notification_count; +static ULONG command_received_count; +static UCHAR cdc_acm_reception_buffer[UX_DEMO_RECEPTION_BUFFER_SIZE]; +static UCHAR cdc_acm_xmit_buffer[UX_DEMO_XMIT_BUFFER_SIZE]; +static UX_HOST_CLASS_CDC_ACM_RECEPTION cdc_acm_reception; +static UCHAR *global_reception_buffer; +static ULONG global_reception_size; +static UCHAR cdc_acm_reception_overflow = UX_FALSE; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +static UCHAR cdc_acm_slave_change; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE * 4]; /* Large enough to avoid memory access exception. */ +static UCHAR cdc_acm_slave_bulk_read_write = UX_TRUE; + +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; + +static UCHAR _rsp_ok[UX_DEMO_BUFFER_SIZE] = {'O', 'K', '\r', '\n', '\0'}; + +/* Define device framework. */ + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED (93 + 7) +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED (103 + 7) +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Configuration 1 descriptor 9 bytes */ + 0x09, 0x02, 0x52, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x00, + 0x02, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Endpoint 0x04 descriptor 7 bytes */ + 0x07, 0x05, 0x04, + 0x03, + 0x08, 0x00, + 15, + + /* Endpoint 0x83 descriptor 7 bytes */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, /* @ 93 - 14 + 2 = 81 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, /* @ 93 - 7 + 2 = 88 */ + 0x02, + 0x40, 0x00, + 0x00, + +}; + +#define DEVICE_FRAMEWORK_EPA_POS_1_FS (DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 14 + 2) +#define DEVICE_FRAMEWORK_EPA_POS_2_FS (DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 7 + 2) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor */ + 0x09, 0x02, 0x52, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x00, + 0x00, + 0x02, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor */ + 0x05, 0x24, 0x06, + 0x00, + 0x01, + + /* Call Management Functional Descriptor */ + 0x05, 0x24, 0x01, + 0x00, + 0x01, + + /* Endpoint 0x04 descriptor */ + 0x07, 0x05, 0x04, + 0x03, + 0x08, 0x00, + 10, + + /* Endpoint 0x83 descriptor */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 10, + + /* Data Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor */ + 0x07, 0x05, 0x02, /* @ 103 - 14 + 2 = 91 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor */ + 0x07, 0x05, 0x81, /* @ 103 - 7 + 2 = 98 */ + 0x02, + 0x40, 0x00, + 0x00, + +}; + +#define DEVICE_FRAMEWORK_EPA_POS_1_HS (DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 14 + 2) +#define DEVICE_FRAMEWORK_EPA_POS_2_HS (DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 7 + 2) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 + }; + +#define DEVICE_FRAMEWORK1_LENGTH (18 +9 +8 +9+5+4+5+5+ 9+7+7) /* =86 */ +#define DEVICE_FRAMEWORK1_CFG_TOTAL_LEN_POS (18+2) +#define DEVICE_FRAMEWORK1_IFC1_N_EPS_POS (86-7-7-9+4) +#define DEVICE_FRAMEWORK1_IFC1_EPA1_POS (86-7-7+2) +#define DEVICE_FRAMEWORK1_IFC1_EPA2_POS (86-7+2) + +static unsigned char device_framework_no_interrupt_ep[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 0x03, + 0x01, + + /* Configuration 1 descriptor 9 bytes */ + 0x09, 0x02, 0x44, 0x00, /* wTotalLength @ 21 */ + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x00, + 0x00, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, /* bNumEndpoints @ 86 - 14 - 9 + 4 = 67 */ + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, /* @ 86 - 14 + 2 = 73 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, /* @ 86 - 7 + 2 = 81 */ + 0x02, + 0x40, 0x00, + 0x00, + +}; + +static unsigned char replaced_cfg_descriptor[] = +{ + /* Configuration 1 descriptor 9 bytes */ + 0x09, 0x02, 0x52, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x00, + 0x02, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Endpoint 0x04 descriptor 7 bytes */ + 0x07, 0x05, 0x04, + 0x03, + 0x08, 0x00, + 10, + + /* Endpoint 0x83 descriptor 7 bytes */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 10, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, /* @ 93 - 14 + 2 = 81 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, /* @ 93 - 7 + 2 = 88 */ + 0x02, + 0x40, 0x00, + 0x00, +}; + +static unsigned char replaced_cfg_descriptor_no_bulk[] = +{ + /* Configuration 1 descriptor */ + 0x09, 0x02, 0x52 - 7, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x00, + 0x00, + 0x02, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor */ + 0x05, 0x24, 0x06, + 0x00, + 0x01, + + /* Call Management Functional Descriptor */ + 0x05, 0x24, 0x01, + 0x00, + 0x01, + + /* Endpoint 0x04 descriptor */ + 0x07, 0x05, 0x04, + 0x03, + 0x08, 0x00, + 10, + + /* Endpoint 0x83 descriptor */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 10, + + /* Data Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x01, + 0x00, + 0x01, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor */ + 0x07, 0x05, 0x02, /* @ - 7 + 2 */ + 0x02, + 0x40, 0x00, + 0x00, + +}; + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; +static UX_TEST_SETUP _GetCfgDescr = UX_TEST_SETUP_GetCfgDescr; +static UX_TEST_SETUP _SetAddress = UX_TEST_SETUP_SetAddress; +static UX_TEST_SETUP _GetDeviceDescriptor = UX_TEST_SETUP_GetDevDescr; +static UX_TEST_SETUP _GetConfigDescriptor = UX_TEST_SETUP_GetCfgDescr; + +/* Interaction define */ + +static UX_TEST_HCD_SIM_ACTION check_ignore_next_transfer_request[] = { +/* 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, + 0, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_interaction_invoked}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION wait_disconn_on_transfer_0[] = { +/* 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, + 0, 0, UX_NULL, 0, 0, + UX_ERROR, ux_test_hcd_entry_interaction_wait_transfer_disconnection}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION error_on_transfer_0[] = { +/* 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_SIM_REQ_ANSWER, 0, UX_NULL, 0, UX_ERROR, + UX_ERROR}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION error_on_transfer_1[] = { +/* 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_SIM_REQ_ANSWER, 0, UX_NULL, ~0, 0, + UX_SUCCESS, ux_test_hcd_entry_interaction_invoked}, /* All requested */ +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER, 0, UX_NULL, 0, UX_ERROR, + UX_ERROR, ux_test_hcd_entry_interaction_invoked}, /* Error */ +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION good_on_transfer_1[] = { +/* 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_SIM_REQ_ANSWER, 0, UX_NULL, ~0, 0, /* Return all required */ + UX_SUCCESS, ux_test_hcd_entry_interaction_invoked}, /* All requested */ +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER, 0, UX_NULL, 0, 0, /* Return ZLP */ + UX_SUCCESS, ux_test_hcd_entry_interaction_invoked}, /* No Error */ +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION good_on_transfer_0_ZLP[] = { +/* 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_SIM_REQ_ANSWER, 0, UX_NULL, 0, 0, /* Return ZLP */ + UX_SUCCESS, ux_test_hcd_entry_interaction_request_sem_put}, /* No Error */ +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION error_on_transfer_interruptEP[] = { +/* 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, 0x83, UX_NULL, 0, 0, + UX_ERROR, ux_test_hcd_entry_interaction_invoked}, /* Error */ +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION replaced_GetCfgDescr[] = { +/* 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, &_GetCfgDescr, + UX_FALSE, 0, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, replaced_cfg_descriptor, 9, 0, + UX_SUCCESS, ux_test_hcd_entry_interaction_invoked}, /* Invoke callback & answer */ +{ UX_HCD_TRANSFER_REQUEST, &_GetCfgDescr, + UX_FALSE, 0, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, replaced_cfg_descriptor, sizeof(replaced_cfg_descriptor), 0, + UX_SUCCESS, ux_test_hcd_entry_interaction_invoked}, /* Invoke callback & answer */ +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION enum_replace_no_bulk[] = { +/* 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, &_GetDeviceDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 0, 8, 0, + UX_SUCCESS, ux_test_hcd_entry_interaction_invoked}, +{ UX_HCD_TRANSFER_REQUEST, &_GetDeviceDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 0, 18, 0, + UX_SUCCESS, ux_test_hcd_entry_interaction_invoked}, + + /* Note: Each enumeration does two GetConfigurations (the second one is in _ux_host_class_cdc_acm_capabilities_get.c) */ + + /* 1st. */ +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, replaced_cfg_descriptor_no_bulk, UX_CONFIGURATION_DESCRIPTOR_LENGTH, 0, + UX_SUCCESS, ux_test_hcd_entry_interaction_invoked}, +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, replaced_cfg_descriptor_no_bulk, sizeof(replaced_cfg_descriptor_no_bulk), 0, + UX_SUCCESS, ux_test_hcd_entry_interaction_invoked}, +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, replaced_cfg_descriptor_no_bulk, UX_CONFIGURATION_DESCRIPTOR_LENGTH, 0, + UX_SUCCESS, ux_test_hcd_entry_interaction_invoked}, +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, replaced_cfg_descriptor_no_bulk, sizeof(replaced_cfg_descriptor_no_bulk), 0, + UX_SUCCESS, ux_test_hcd_entry_interaction_invoked}, + + /* 2nd. */ +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, replaced_cfg_descriptor_no_bulk, UX_CONFIGURATION_DESCRIPTOR_LENGTH, 0, + UX_SUCCESS, ux_test_hcd_entry_interaction_invoked}, +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, replaced_cfg_descriptor_no_bulk, sizeof(replaced_cfg_descriptor_no_bulk), 0, + UX_SUCCESS, ux_test_hcd_entry_interaction_invoked}, +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, replaced_cfg_descriptor_no_bulk, UX_CONFIGURATION_DESCRIPTOR_LENGTH, 0, + UX_SUCCESS, ux_test_hcd_entry_interaction_invoked}, +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, replaced_cfg_descriptor_no_bulk, sizeof(replaced_cfg_descriptor_no_bulk), 0, + UX_SUCCESS, ux_test_hcd_entry_interaction_invoked}, + + /* 3rd. */ +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, replaced_cfg_descriptor_no_bulk, UX_CONFIGURATION_DESCRIPTOR_LENGTH, 0, + UX_SUCCESS, ux_test_hcd_entry_interaction_invoked}, +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, replaced_cfg_descriptor_no_bulk, sizeof(replaced_cfg_descriptor_no_bulk), 0, + UX_SUCCESS, ux_test_hcd_entry_interaction_invoked}, +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, replaced_cfg_descriptor_no_bulk, UX_CONFIGURATION_DESCRIPTOR_LENGTH, 0, + UX_SUCCESS, ux_test_hcd_entry_interaction_invoked}, +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, replaced_cfg_descriptor_no_bulk, sizeof(replaced_cfg_descriptor_no_bulk), 0, + UX_SUCCESS, ux_test_hcd_entry_interaction_invoked}, +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* 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 demo_class_cdc_acm_get(void) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_CDC_ACM *cdc_acm_host; + + + /* Find the main cdc_acm container */ + status = ux_host_stack_class_get(_ux_system_host_class_cdc_acm_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* We get the first instance of the cdc_acm device */ + do + { + + status = ux_host_stack_class_instance_get(class, 0, (void **) &cdc_acm_host); + tx_thread_sleep(10); + } while (status != UX_SUCCESS); + + /* We still need to wait for the cdc_acm status to be live */ + while (cdc_acm_host -> ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + tx_thread_sleep(10); + + /* Isolate both the control and data interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_DATA_CLASS) + { + /* This is the data interface. */ + cdc_acm_host_data = cdc_acm_host; + + /* In that case, the second one should be the control interface. */ + status = ux_host_stack_class_instance_get(class, 1, (void **) &cdc_acm_host); + + /* Check error. */ + if (status != UX_SUCCESS) + return(status); + + /* Check for the control interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + + /* This is the control interface. */ + cdc_acm_host_control = cdc_acm_host; + + return(UX_SUCCESS); + + } + } + else + { + /* Check for the control interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + + /* This is the control interface. */ + cdc_acm_host_control = cdc_acm_host; + + /* In that case, the second one should be the data interface. */ + status = ux_host_stack_class_instance_get(class, 1, (void **) &cdc_acm_host); + + /* Check error. */ + if (status != UX_SUCCESS) + return(status); + + /* Check for the data interface. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_DATA_CLASS) + { + + /* This is the data interface. */ + cdc_acm_host_data = cdc_acm_host; + + return(UX_SUCCESS); + + } + } + } + + /* Return ERROR. */ + return(UX_ERROR); +} + +static UINT demo_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID demo_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID demo_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static VOID demo_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; +} + +static VOID test_swap_framework_bulk_ep_descriptors(VOID) +{ +UCHAR tmp; + + tmp = device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_1_FS]; + device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_1_FS] = device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_2_FS]; + device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_2_FS] = tmp; + + tmp = device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_1_HS]; + device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_1_HS] = device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_2_HS]; + device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_2_HS] = tmp; +} + +static VOID test_slave_cdc_acm_transfer_disconnect(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, ULONG ep_dir) +{ + +UX_SLAVE_ENDPOINT *endpoint; +UX_SLAVE_DEVICE *device; +UX_SLAVE_INTERFACE *interface; +UX_SLAVE_TRANSFER *transfer_request; + + /* Get the pointer to the device. */ + device = &_ux_system_slave -> ux_system_slave_device; + + /* This is the first time we are activated. We need the interface to the class. */ + interface = cdc_acm -> ux_slave_class_cdc_acm_interface; + + /* Locate the endpoints. */ + endpoint = interface -> ux_slave_interface_first_endpoint; + + /* Check the endpoint direction, if OUT we have the correct endpoint. */ + if ((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) != ep_dir) + { + + /* So the next endpoint has to be the OUT endpoint. */ + endpoint = endpoint -> ux_slave_endpoint_next_endpoint; + } + + /* All CDC reading are on the endpoint OUT, from the host. */ + transfer_request = &endpoint -> ux_slave_endpoint_transfer_request; + + /* Continue transfer. */ + transfer_request -> ux_slave_transfer_request_actual_length = endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize; + + /* Change device state. */ + device -> ux_slave_device_state = UX_DEVICE_ATTACHED; + + /* Inform hcd. */ + _ux_utility_semaphore_put(&transfer_request -> ux_slave_transfer_request_semaphore); + + /* Wait a while for transfer request handling. */ + tx_thread_sleep(50); + + /* Change device state. */ + device -> ux_slave_device_state = UX_DEVICE_CONFIGURED; +} + +static VOID ux_test_hcd_entry_interaction_wait_transfer_disconnection(UX_TEST_ACTION *action, VOID *_params) +{ +UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *params = _params; +UX_TRANSFER *transfer_request = (UX_TRANSFER *)params->parameter; +UX_ENDPOINT *endpoint; +UX_DEVICE *device; + + endpoint = transfer_request -> ux_transfer_request_endpoint; + device = endpoint -> ux_endpoint_device; + + while(device -> ux_device_state > UX_DEVICE_RESET) + tx_thread_sleep(10); +} + +static VOID ux_test_hcd_entry_interaction_invoked(UX_TEST_ACTION *action, VOID *params) +{ + + interaction_count ++; +} + +static VOID ux_test_hcd_entry_interaction_request_sem_put(UX_TEST_ACTION *action, VOID *params) +{ + + interaction_count ++; + +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_acm_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +ULONG test_n; + + /* Inform user. */ + printf("Running CDC ACM Basic Functionality 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(); + + /* 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 #1\n"); + 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(demo_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #2\n"); + test_control_return(1); + } + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_entry); + if (status != UX_SUCCESS) + { + + printf("ERROR #3\n"); + 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 #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = demo_cdc_instance_activate; + parameter.ux_slave_class_cdc_acm_instance_deactivate = demo_cdc_instance_deactivate; + parameter.ux_slave_class_cdc_acm_parameter_change = demo_cdc_instance_parameter_change; + + /* Mutex will be created on initialize to protect CDC Bulk IN/OUT */ + for (test_n = 0; test_n < 2; test_n ++) + { + ux_test_utility_sim_mutex_error_generation_start(test_n); + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + /* Mutex error should be reported */ + if(status != UX_MUTEX_ERROR) + { + + printf("ERROR #46.%ld\n", test_n); + test_control_return(1); + } + } + ux_test_utility_sim_mutex_error_generation_stop(); + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + + if(status!=UX_SUCCESS) + { + + printf("ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #7\n"); + 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 #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx demo host simulation", tx_test_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 #8\n"); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx demo slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #9\n"); + test_control_return(1); + } +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_CDC_ACM_LINE_CODING line_coding_host; +UX_HOST_CLASS_CDC_ACM_LINE_STATE line_state_host; +ULONG actual_length; +UCHAR at_cmd[16]; +UX_SLAVE_CLASS_CDC_ACM * cdc_acm_slave_bak; +UX_HOST_CLASS_CDC_ACM * cdc_acm_host_ctrl_bak; +UX_HOST_CLASS_CDC_ACM * cdc_acm_host_data_bak; +ULONG test_n; +UX_HOST_CLASS_COMMAND command; +UX_HOST_CLASS_COMMAND command1; +ULONG mem_free; + + stepinfo("\n"); + + /* Find the cdc_acm class and wait for the link to be up. */ + status = demo_class_cdc_acm_get(); + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #10\n"); + test_control_return(1); + } + + /* Reception parameter */ + cdc_acm_reception.ux_host_class_cdc_acm_reception_block_size = UX_DEMO_RECEPTION_BLOCK_SIZE; + cdc_acm_reception.ux_host_class_cdc_acm_reception_data_buffer = cdc_acm_reception_buffer; + cdc_acm_reception.ux_host_class_cdc_acm_reception_data_buffer_size = UX_DEMO_RECEPTION_BUFFER_SIZE; + cdc_acm_reception.ux_host_class_cdc_acm_reception_callback = test_thread_host_reception_callback; + + /* Save slave instance for later tests. */ + cdc_acm_slave_bak = cdc_acm_slave; + /* Save host instances for later tests. */ + cdc_acm_host_ctrl_bak = cdc_acm_host_control; + cdc_acm_host_data_bak = cdc_acm_host_data; + + /* Test disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Test reception on instance inactive */ + stepinfo(">>>>>>>>>>>> Start reception when interface is inactive\n"); + status = ux_host_class_cdc_acm_reception_start(cdc_acm_host_data_bak, &cdc_acm_reception); + if (status == UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #86: error must be reported when invoking reception while interface is not ready\n"); + test_control_return(1); + } + + /* Test stop reception on inactive interface */ + stepinfo(">>>>>>>>>>>> Stop reception when interface is inactive\n"); + status = ux_host_class_cdc_acm_reception_stop(cdc_acm_host_data_bak, &cdc_acm_reception); + if (status == UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #91: error not reported when stop reception on inactive interface\n"); + test_control_return(1); + } + + /* Reset testing counts. */ + ux_test_utility_sim_mutex_create_count_reset(); + ux_test_utility_sim_sem_create_count_reset(); + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + /* Save free memory usage. */ + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + tx_thread_sleep(100); + /* Log create counts for further tests. */ + rsc_enum_mutex_usage = rsc_mutex_on_set_cfg; + rsc_enum_sem_usage = rsc_sem_on_set_cfg; + rsc_enum_mem_usage = mem_free - rsc_mem_free_on_set_cfg; + /* Log create counts when instances active for further tests. */ + rsc_cdc_mutex_usage = ux_test_utility_sim_mutex_create_count() - rsc_enum_mutex_usage; + rsc_cdc_sem_usage = ux_test_utility_sim_sem_create_count() - rsc_enum_sem_usage; + rsc_cdc_mem_usage = rsc_mem_free_on_set_cfg - _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + + /* Start the reception on control interface. */ + stepinfo(">>>>>>>>>>>> Start reception on control interface\n"); + status = ux_host_class_cdc_acm_reception_start(cdc_acm_host_control, &cdc_acm_reception); + if (status == UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #87: error must be reported when invoking reception on control interface\n"); + test_control_return(1); + } + + /* Start and stop immediately. */ + stepinfo(">>>>>>>>>>>> Start reception and stop it immediately\n"); + status = ux_host_class_cdc_acm_reception_start(cdc_acm_host_data, &cdc_acm_reception); + status |= ux_host_class_cdc_acm_reception_stop(cdc_acm_host_data, &cdc_acm_reception); + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Transfer error. */ + stepinfo(">>>>>>>>>>>> Start reception request error\n"); + ux_test_hcd_sim_host_set_actions(error_on_transfer_0); + status = ux_host_class_cdc_acm_reception_start(cdc_acm_host_data, &cdc_acm_reception); + if (status == UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #88: error must be reported when transfer request error\n"); + test_control_return(1); + } + + /* Start the reception for test. */ + status = ux_host_class_cdc_acm_reception_start(cdc_acm_host_data, &cdc_acm_reception); + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #89: Start reception fail\n"); + test_control_return(1); + } + + /* Test stop reception on wrong interface */ + status = ux_host_class_cdc_acm_reception_stop(cdc_acm_host_control, &cdc_acm_reception); + if (status == UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #90: error not reported when stop reception on wrong interface\n"); + test_control_return(1); + } + + /* Stop reception for test */ + status = ux_host_class_cdc_acm_reception_stop(cdc_acm_host_data, &cdc_acm_reception); + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #92: stop reception failed\n"); + test_control_return(1); + } + + /* Start the reception for cdc_acm. */ + status = ux_host_class_cdc_acm_reception_start(cdc_acm_host_data, &cdc_acm_reception); + + /* Get the current data rate. */ + stepinfo(">>>>>>>>>>>> ATB: get baud\n"); + status = test_usbx_simulator_cdc_acm_host_send_at_command("ATB",3); + + /* The device may be extracted after we start sending\receiving. */ + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #11\n"); + test_control_return(1); + } + + /* Get the current stop bit rate. */ + stepinfo(">>>>>>>>>>>> ATS: get stop bits\n"); + status = test_usbx_simulator_cdc_acm_host_send_at_command("ATS",3); + + /* The device may be extracted after we start sending\receiving. */ + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #12\n"); + test_control_return(1); + } + + /* Get the current parity rate. */ + stepinfo(">>>>>>>>>>>> ATP: get parity\n"); + status = test_usbx_simulator_cdc_acm_host_send_at_command("ATP",3); + + /* The device may be extracted after we start sending\receiving. */ + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #13\n"); + test_control_return(1); + } + + /* Get the current data bit rate. */ + stepinfo(">>>>>>>>>>>> ATD: data bits\n"); + status = test_usbx_simulator_cdc_acm_host_send_at_command("ATD",3); + + /* The device may be extracted after we start sending\receiving. */ + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + + /* Get the current RTS state. */ + stepinfo(">>>>>>>>>>>> ATR: RTS\n"); + status = test_usbx_simulator_cdc_acm_host_send_at_command("ATR",3); + + /* The device may be extracted after we start sending\receiving. */ + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #15\n"); + test_control_return(1); + } + + /* Get the current DTR rate. */ + stepinfo(">>>>>>>>>>>> ATT: DTR\n"); + status = test_usbx_simulator_cdc_acm_host_send_at_command("ATT",3); + + /* The device may be extracted after we start sending\receiving. */ + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #16\n"); + test_control_return(1); + } + + /* Stop after receive. */ + stepinfo(">>>>>>>>>>>> Start reception and stop it immediately\n"); + status |= ux_host_class_cdc_acm_reception_stop(cdc_acm_host_data, &cdc_acm_reception); + status = ux_host_class_cdc_acm_reception_start(cdc_acm_host_data, &cdc_acm_reception); + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Read 64 bytes and next device side expect 64 byte */ + stepinfo(">>>>>>>>>>>> ATOP: 64/64\n"); + status = test_usbx_simulator_cdc_acm_host_send_at_command("ATOP", 4); + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Set the line coding. */ + stepinfo(">>>>>>>>>>>> ATL: Set LineCoding\n"); + at_cmd[0] = 'A'; + at_cmd[1] = 'T'; + at_cmd[2] = 'L'; + at_cmd[3] = 0x00; + at_cmd[4] = 0xC2; + at_cmd[5] = 0x01; + at_cmd[6] = 0x00; /* 115200: 0x0001C200 */ + at_cmd[7] = UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_STOP_BIT; + at_cmd[8] = UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_PARITY; + at_cmd[9] = 7; + status = test_usbx_simulator_cdc_acm_host_send_at_command(at_cmd,62); + + /* The device may be extracted after we start sending\receiving. */ + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #33\n"); + test_control_return(1); + } + + /* Change the line coding values. */ + stepinfo(">>>>>>>>>>>> IOCTRL: SetLineCoding\n"); + line_coding_host.ux_host_class_cdc_acm_line_coding_dter = 9600; + line_coding_host.ux_host_class_cdc_acm_line_coding_stop_bit = UX_HOST_CLASS_CDC_ACM_LINE_CODING_STOP_BIT_15; + line_coding_host.ux_host_class_cdc_acm_line_coding_parity = UX_HOST_CLASS_CDC_ACM_LINE_CODING_PARITY_EVEN; + line_coding_host.ux_host_class_cdc_acm_line_coding_data_bits = 5; + + status = _ux_host_class_cdc_acm_ioctl(cdc_acm_host_control, UX_HOST_CLASS_CDC_ACM_IOCTL_SET_LINE_CODING, + &line_coding_host); + + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #17\n"); + test_control_return(1); + } + + /* Slave should invoke parameter change callback */ + if (cdc_acm_slave_change != UX_TRUE) + { + + /* CDC ACM basic test error. */ + printf("ERROR #25\n"); + test_control_return(1); + } + /* Reset slave change flag */ + cdc_acm_slave_change = UX_FALSE; + + /* Change the line state values. */ + stepinfo(">>>>>>>>>>>> IOCTRL: SetLineState\n"); + line_state_host.ux_host_class_cdc_acm_line_state_rts = 0; + line_state_host.ux_host_class_cdc_acm_line_state_dtr = 0; + + status = _ux_host_class_cdc_acm_ioctl(cdc_acm_host_control, UX_HOST_CLASS_CDC_ACM_IOCTL_SET_LINE_STATE, + &line_state_host); + + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #18\n"); + test_control_return(1); + } + + /* Slave should invoke parameter change callback */ + if (cdc_acm_slave_change != UX_TRUE) + { + + /* CDC ACM basic test error. */ + printf("ERROR #26\n"); + test_control_return(1); + } + /* Reset slave change flag */ + cdc_acm_slave_change = UX_FALSE; + + /* Reobtain the cdc acm line values. */ + /* Get the current data rate. */ + stepinfo(">>>>>>>>>>>> ATB: baud rate\n"); + status = test_usbx_simulator_cdc_acm_host_send_at_command("ATB",3); + + /* The device may be extracted after we start sending\receiving. */ + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #19\n"); + test_control_return(1); + } + + /* Get the current stop bit rate. */ + stepinfo(">>>>>>>>>>>> ATS: stop bits\n"); + status = test_usbx_simulator_cdc_acm_host_send_at_command("ATS",3); + + /* The device may be extracted after we start sending\receiving. */ + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #20\n"); + test_control_return(1); + } + + /* Get the current parity rate. */ + stepinfo(">>>>>>>>>>>> ATP: parity\n"); + status = test_usbx_simulator_cdc_acm_host_send_at_command("ATP",3); + + /* The device may be extracted after we start sending\receiving. */ + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #21\n"); + test_control_return(1); + } + + /* Get the current data bit rate. */ + stepinfo(">>>>>>>>>>>> ATD: data bits\n"); + status = test_usbx_simulator_cdc_acm_host_send_at_command("ATD",3); + + /* The device may be extracted after we start sending\receiving. */ + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #22\n"); + test_control_return(1); + } + + /* Get the current RTS state. */ + stepinfo(">>>>>>>>>>>> ATR: RTS\n"); + status = test_usbx_simulator_cdc_acm_host_send_at_command("ATR",3); + + /* The device may be extracted after we start sending\receiving. */ + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #23\n"); + test_control_return(1); + } + + /* Test enumeration different descriptors */ + + /* Initialize to disconnect */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Test enumeration no interrupt EP */ + stepinfo(">>>>>>>>>>>> Enumerate device wihtout interrupt EP\n"); + _ux_system_slave->ux_system_slave_device_framework_full_speed = device_framework_no_interrupt_ep; + _ux_system_slave->ux_system_slave_device_framework_length_full_speed = sizeof(device_framework_no_interrupt_ep); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + ux_utility_delay_ms(UX_CDC_ACM_CONNECTION_DELAY); + /* Instances should be ready */ + if (!cdc_acm_slave || !cdc_acm_host_control || !cdc_acm_host_data) + { + + printf("ERROR #57: instance should ready after reconnect without interrupt EP\n"); + test_control_return(1); + } + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + /* Instances should be removed */ + if (cdc_acm_slave || cdc_acm_host_control || cdc_acm_host_data) + { + + printf("ERROR #60: instance should removed after disconnect without interrupt EP\n"); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Enumerate device wihtout one of bulk EP\n"); + /* Pause bulk read/write since there is no bulk EP. */ + cdc_acm_slave_bulk_read_write = UX_FALSE; + + /* Test enumeration no bulk EP */ + + ux_test_hcd_sim_host_set_actions(enum_replace_no_bulk); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + ux_utility_delay_ms(UX_CDC_ACM_CONNECTION_DELAY); + /* Data instances should not be ready */ + if (cdc_acm_host_data) + { + + printf("ERROR #58: instance should NOT ready after reconnect without one of bulk EP\n"); + test_control_return(1); + } + UX_TEST_ASSERT(ux_test_check_actions_empty()); + + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + if (cdc_acm_slave || cdc_acm_host_control) + { + + printf("ERROR #61: instance should be removed after disconnect without one of bulk EP\n"); + test_control_return(1); + } + + replaced_cfg_descriptor_no_bulk[sizeof(replaced_cfg_descriptor_no_bulk) - 7 + 2] ^= 0x80; + ux_test_hcd_sim_host_set_actions(enum_replace_no_bulk); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + ux_utility_delay_ms(UX_CDC_ACM_CONNECTION_DELAY); + /* Data instances should not be ready */ + if (cdc_acm_host_data) + { + + printf("ERROR #59: instance should NOT ready after reconnect without one of bulk EP\n"); + test_control_return(1); + } + + /* Restore frameworks */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + _ux_system_slave->ux_system_slave_device_framework_full_speed = device_framework_full_speed; + _ux_system_slave->ux_system_slave_device_framework_length_full_speed = DEVICE_FRAMEWORK_LENGTH_FULL_SPEED; + ux_test_hcd_sim_host_set_actions(UX_NULL); + cdc_acm_slave_bulk_read_write = UX_TRUE; + + /* Swap EP address for different EP sequence. */ + stepinfo(">>>>>>>>>>>> Enumerate device swap bulk EP addresses\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + test_swap_framework_bulk_ep_descriptors(); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + ux_utility_delay_ms(UX_CDC_ACM_CONNECTION_DELAY); + /* Instances should be ready */ + if (!cdc_acm_slave || !cdc_acm_host_control || !cdc_acm_host_data) + { + + printf("ERROR #53: instance not ready after reconnect (%p,%p,%p)\n", cdc_acm_slave, cdc_acm_host_control, cdc_acm_host_data); + test_control_return(1); + } + + if (cdc_acm_host_control->ux_host_class_cdc_acm_interrupt_endpoint) + { + + stepinfo(">>>>>>>>>>>> Notification reception test\n"); + + /* Set notification callback */ + status = _ux_host_class_cdc_acm_ioctl(cdc_acm_host_control, UX_HOST_CLASS_CDC_ACM_IOCTL_NOTIFICATION_CALLBACK, + (VOID*)ux_test_host_class_cdc_acm_device_status_change_callback); + if (status != UX_SUCCESS) + { + + printf("ERROR #55: notification callback set fail\n"); + test_control_return(1); + } + interaction_count = 0; + ux_test_hcd_sim_host_set_actions(check_ignore_next_transfer_request); + /* Simulate notification! */ + cdc_acm_host_control->ux_host_class_cdc_acm_interrupt_endpoint->ux_endpoint_transfer_request.ux_transfer_request_completion_code = UX_SUCCESS; + _ux_host_class_cdc_acm_transfer_request_completed(&cdc_acm_host_control->ux_host_class_cdc_acm_interrupt_endpoint->ux_endpoint_transfer_request); + /* There should be call of transfer to re-start notification monitoring */ + if (interaction_count == 0) + { + + printf("ERROR #56: notification monitoring not reactivated\n"); + test_control_return(1); + } + + } + + /* Start the reception for cdc_acm. */ + status = ux_host_class_cdc_acm_reception_start(cdc_acm_host_data, &cdc_acm_reception); + if (status != UX_SUCCESS) + { + + printf("ERROR #54: reception start error\n"); + test_control_return(1); + } + + /* Get the current DTR rate. */ + stepinfo(">>>>>>>>>>>> ATT: get DTR\n"); + status = test_usbx_simulator_cdc_acm_host_send_at_command("ATT",3); + + /* The device may be extracted after we start sending\receiving. */ + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #24\n"); + test_control_return(1); + } + + /* Try invalid command on IOCTL. */ + stepinfo(">>>>>>>>>>>> ATF: invalid device IOCTRL command\n"); + status = test_usbx_simulator_cdc_acm_host_send_at_command("ATF",3); + + /* The device may be extracted after we start sending\receiving. */ + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #36\n"); + test_control_return(1); + } + + /* Try slave ABORT command on IOCTL. */ + stepinfo(">>>>>>>>>>>> ATA: slave IOCTRL ABORT test\n"); + status = test_usbx_simulator_cdc_acm_host_send_at_command("ATA",3); + + /* The device may be extracted after we start sending\receiving. */ + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #37\n"); + test_control_return(1); + } + + /* Start reception again if it's aborted */ + ux_host_class_cdc_acm_reception_start(cdc_acm_host_data, &cdc_acm_reception); + /* Read until there is no data from slave */ + do + { + status = command_received_count; + tx_thread_sleep(20); + } while(status != command_received_count); + + /* Try overflow */ + stepinfo(">>>>>>>>>>>> Reception overflow test\n"); + cdc_acm_reception_overflow = UX_TRUE; + /* Start writing long buffer in device side */ + test_usbx_simulator_cdc_acm_host_send_string("ATO\0", 4); + /* Waiting overflow detection */ + status = 50; + while(cdc_acm_reception_overflow && status --) + { + tx_thread_sleep(20); + } + if (cdc_acm_reception_overflow) + { + + printf("ERROR #93: Reception overflow not detected\n"); + cdc_acm_reception_overflow = UX_FALSE; + test_control_return(1); + } + /* Continue reception */ + ux_host_class_cdc_acm_reception_start(cdc_acm_host_data, &cdc_acm_reception); + + /* GetLineCoding with larger buffer size + response should be OK with correct bytes */ + stepinfo(">>>>>>>>>>>> GetLineCoding with larger buffer than line coding data\n"); + status = ux_test_host_class_cdc_acm_command(cdc_acm_host_control, UX_HOST_CLASS_CDC_ACM_REQ_GET_LINE_CODING, + 0, cdc_acm_reception_buffer, UX_HOST_CLASS_CDC_ACM_LINE_CODING_LENGTH + 1, + &actual_length); + + /* The device may be extracted after we start sending\receiving. */ + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #27\n"); + test_control_return(1); + } + /* Returned number of bytes should be correct */ + if (actual_length != UX_HOST_CLASS_CDC_ACM_LINE_CODING_LENGTH) + { + + /* CDC ACM basic test error. */ + printf("ERROR #28\n"); + test_control_return(1); + } + + /* Host command test */ + + /* Undefined command */ + stepinfo(">>>>>>>>>>>> Invalid command\n"); + status = _ux_host_class_cdc_acm_command(cdc_acm_host_control, UX_HOST_CLASS_CDC_ACM_REQ_GET_LINE_CODING + 7, + 0, cdc_acm_reception_buffer, UX_HOST_CLASS_CDC_ACM_LINE_CODING_LENGTH + 1); + + /* The device may be extracted after we start sending\receiving. */ + if (status == UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #29\n"); + test_control_return(1); + } + + /* Semaphore protection error test */ + stepinfo(">>>>>>>>>>>> Semaphore get error on command\n"); + ux_test_utility_sim_sem_get_error_generation_start(0); + status = _ux_host_class_cdc_acm_command(cdc_acm_host_control, UX_HOST_CLASS_CDC_ACM_REQ_GET_LINE_CODING, + 0, cdc_acm_reception_buffer, UX_HOST_CLASS_CDC_ACM_LINE_CODING_LENGTH); + if (status == UX_SUCCESS) + { + + printf("ERROR #64: no error reported on control semaphore error\n"); + test_control_return(1); + } + ux_test_utility_sim_sem_get_error_generation_stop(); + + /* Host entry test */ + + /* Invalid command */ + stepinfo(">>>>>>>>>>>> Host Entry - Invalid command\n"); + command.ux_host_class_command_request = 0xFF; + status = ux_host_class_cdc_acm_entry(&command); + if (status == UX_SUCCESS) + { + + printf("ERROR #62: no error report on invalid command entry\n"); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Host Entry - Query\n"); + + /* Query test - wrong class */ + command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_QUERY; + command.ux_host_class_command_usage = UX_HOST_CLASS_COMMAND_USAGE_CSP; + command.ux_host_class_command_class = 0xFF; + status = ux_host_class_cdc_acm_entry(&command); + if (status == UX_SUCCESS) + { + + printf("ERROR #63: no error report when Query class wrong\n"); + test_control_return(1); + } + + /* Query test - CTRL & DLC */ + command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_QUERY; + command.ux_host_class_command_usage = UX_HOST_CLASS_COMMAND_USAGE_CSP; + command.ux_host_class_command_class = UX_HOST_CLASS_CDC_CONTROL_CLASS; + command.ux_host_class_command_subclass = UX_HOST_CLASS_CDC_DLC_SUBCLASS; + command.ux_host_class_command_iad_class = 0; + command.ux_host_class_command_iad_subclass = 0; + status = ux_host_class_cdc_acm_entry(&command); + if (status != UX_SUCCESS) + { + + printf("ERROR #64: error report when Query class OK\n"); + test_control_return(1); + } + + /* Query test - wrong IAD */ + command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_QUERY; + command.ux_host_class_command_usage = UX_HOST_CLASS_COMMAND_USAGE_CSP; + command.ux_host_class_command_class = UX_HOST_CLASS_CDC_CONTROL_CLASS; + command.ux_host_class_command_subclass = UX_HOST_CLASS_CDC_DLC_SUBCLASS; + command.ux_host_class_command_iad_class = 0xFE; + status = ux_host_class_cdc_acm_entry(&command); + if (status == UX_SUCCESS) + { + + printf("ERROR #65: no error report when Query class IAD wrong"); + test_control_return(1); + } + + /* Host class deactivate & activate */ + stepinfo(">>>>>>>>>>>> Host CDC deactivate & activate\n"); + command.ux_host_class_command_container = cdc_acm_host_control->ux_host_class_cdc_acm_interface; + command.ux_host_class_command_class_ptr = cdc_acm_host_control->ux_host_class_cdc_acm_class; + command.ux_host_class_command_instance = cdc_acm_host_control; + command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_DEACTIVATE; + + command1.ux_host_class_command_container = cdc_acm_host_data->ux_host_class_cdc_acm_interface; + command1.ux_host_class_command_class_ptr = cdc_acm_host_data->ux_host_class_cdc_acm_class; + command1.ux_host_class_command_instance = cdc_acm_host_data; + command1.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_DEACTIVATE; + + ux_host_class_cdc_acm_entry(&command); + /* Instance should be removed */ + if (cdc_acm_host_control) + { + + printf("ERROR #67: control instance not deactivate\n"); + test_control_return(1); + } + + ux_host_class_cdc_acm_entry(&command1); + /* Instance should be removed */ + if (cdc_acm_host_data) + { + + printf("ERROR #67: control instance not deactivate\n"); + test_control_return(1); + } + + command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_ACTIVATE; + ux_host_class_cdc_acm_entry(&command); + /* Instance should be back */ + if (!cdc_acm_host_control) + { + + printf("ERROR #68: control instance not activate\n"); + test_control_return(1); + } + + command1.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_ACTIVATE; + ux_host_class_cdc_acm_entry(&command1); + /* Instance should be back */ + if (!cdc_acm_host_data) + { + + printf("ERROR #68: control instance not activate\n"); + test_control_return(1); + } + + /* Start the reception for cdc_acm. */ + status = ux_host_class_cdc_acm_reception_start(cdc_acm_host_data, &cdc_acm_reception); + if (status != UX_SUCCESS) + { + + printf("ERROR #70: reception start error\n"); + test_control_return(1); + } + + /* Get the current stop bit rate. */ + stepinfo(">>>>>>>>>>>> ATS: stop bits\n"); + status = test_usbx_simulator_cdc_acm_host_send_at_command("ATS",3); + + /* The device may be extracted after we start sending\receiving. */ + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #69\n"); + test_control_return(1); + } + + /* Sim: slave lost configure while reading pending. */ + stepinfo(">>>>>>>>>>>> Slave lost connection while reading\n"); + ux_utility_memory_set(cdc_acm_xmit_buffer, 0x00, 3); + status = ux_host_class_cdc_acm_write(cdc_acm_host_data, cdc_acm_xmit_buffer, 128, &actual_length); + /* Simulate disconnect after first packet sent */ + test_slave_cdc_acm_transfer_disconnect(cdc_acm_slave_bak, UX_ENDPOINT_OUT); + status = ux_host_class_cdc_acm_write(cdc_acm_host_data, cdc_acm_xmit_buffer, 64, &actual_length); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + tx_thread_sleep(50); + + /* Sim: slave lost configure while writing pending. */ + stepinfo(">>>>>>>>>>>> Slave lost connection while writing\n"); + status = test_usbx_simulator_cdc_acm_host_send_string("\0",1); + status = test_usbx_simulator_cdc_acm_host_send_string("ATW",3); + /* The device may be extracted after we start sending\receiving. */ + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #42\n"); + test_control_return(1); + } + tx_thread_sleep(20); + test_slave_cdc_acm_transfer_disconnect(cdc_acm_slave_bak, UX_ENDPOINT_IN); + + /* Now disconnect the device. */ + ux_test_dcd_sim_slave_disconnect(); + + /* Read/write through disconnected slave should return error */ + stepinfo(">>>>>>>>>>>> R/W on deactivated slave interface instance\n"); + /* Try read, error must be returned */ + status = ux_device_class_cdc_acm_read(cdc_acm_slave_bak, buffer, UX_DEMO_BUFFER_SIZE, &actual_length); + if (status == UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #40\n"); + test_control_return(1); + + } + + /* Try write, error must be returned */ + status = ux_device_class_cdc_acm_write(cdc_acm_slave_bak, buffer, UX_DEMO_BUFFER_SIZE, &actual_length); + if (status == UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #41\n"); + test_control_return(1); + + } + + stepinfo(">>>>>>>>>>>> R/W on invalid interface instance\n"); + + /* Try host read on control interface, error must be returned. */ + status = ux_host_class_cdc_acm_read(cdc_acm_host_control, buffer, 64, &actual_length); + if (status != UX_HOST_CLASS_INSTANCE_UNKNOWN) + { + + /* CDC ACM basic test error. */ + printf("ERROR #47\n"); + test_control_return(1); + } + + /* Try host write, error must be returned. */ + status = ux_host_class_cdc_acm_write(cdc_acm_host_control, buffer, 64, &actual_length); + if (status != UX_HOST_CLASS_INSTANCE_UNKNOWN) + { + + /* CDC ACM basic test error. */ + printf("ERROR #48\n"); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> R/W on deactivated host interface instance\n"); + + ux_test_hcd_sim_host_disconnect(); + tx_thread_sleep(50); + + /* Try host read on disconnected interface, error must be returned. */ + status = ux_host_class_cdc_acm_read(cdc_acm_host_data_bak, buffer, 64, &actual_length); + if (status != UX_HOST_CLASS_INSTANCE_UNKNOWN) + { + + /* CDC ACM basic test error. */ + printf("ERROR #49\n"); + test_control_return(1); + } + + /* Try host write, error must be returned. */ + status = ux_host_class_cdc_acm_write(cdc_acm_host_data_bak, buffer, 64, &actual_length); + if (status != UX_HOST_CLASS_INSTANCE_UNKNOWN) + { + + /* CDC ACM basic test error. */ + printf("ERROR #43\n"); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> IOCTRL on deactivated host interface instance\n"); + status = ux_host_class_cdc_acm_ioctl(cdc_acm_host_data_bak, 0, UX_NULL); + if (status == UX_SUCCESS) + { + + printf("ERROR #73: IOCTRL on deactivated interface should report error\n"); + test_control_return(1); + } + + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + while(!cdc_acm_host_control || !cdc_acm_host_data) + tx_thread_sleep(10); + + /* Host IOCTRL tests */ + + /* Try invalid IOCTRL command */ + stepinfo(">>>>>>>>>>>> IOCTRL invalid command\n"); + status = ux_host_class_cdc_acm_ioctl(cdc_acm_host_control, 0xFF, UX_NULL); + if (status != UX_FUNCTION_NOT_SUPPORTED) + { + + printf("ERROR #74: IOCTRL with invalid command should report UX_FUNCTION_NOT_SUPPORTED\n"); + test_control_return(1); + } + + /* Try IOCTRL UX_HOST_CLASS_CDC_ACM_IOCTL_GET_DEVICE_STATUS */ + stepinfo(">>>>>>>>>>>> IOCTRL UX_HOST_CLASS_CDC_ACM_IOCTL_GET_DEVICE_STATUS\n"); + status = ux_host_class_cdc_acm_ioctl(cdc_acm_host_control, UX_HOST_CLASS_CDC_ACM_IOCTL_GET_DEVICE_STATUS, &test_n); + if (status != UX_SUCCESS) + { + + printf("ERROR #75: IOCTRL UX_HOST_CLASS_CDC_ACM_IOCTL_GET_DEVICE_STATUS should be OK\n"); + test_control_return(1); + } + + /* Try IOCTRL UX_HOST_CLASS_CDC_ACM_IOCTL_ABORT_OUT_PIPE */ + stepinfo(">>>>>>>>>>>> IOCTRL UX_HOST_CLASS_CDC_ACM_IOCTL_ABORT_OUT_PIPE\n"); + status = ux_host_class_cdc_acm_ioctl(cdc_acm_host_data, UX_HOST_CLASS_CDC_ACM_IOCTL_ABORT_OUT_PIPE, UX_NULL); + if (status != UX_SUCCESS) + { + + printf("ERROR #76: IOCTRL UX_HOST_CLASS_CDC_ACM_IOCTL_ABORT_OUT_PIPE should be OK\n"); + test_control_return(1); + } + + /* Try IOCTRL UX_HOST_CLASS_CDC_ACM_IOCTL_ABORT_IN_PIPE */ + stepinfo(">>>>>>>>>>>> IOCTRL UX_HOST_CLASS_CDC_ACM_IOCTL_ABORT_IN_PIPE\n"); + status = ux_host_class_cdc_acm_ioctl(cdc_acm_host_data, UX_HOST_CLASS_CDC_ACM_IOCTL_ABORT_IN_PIPE, UX_NULL); + if (status != UX_SUCCESS) + { + + printf("ERROR #77: IOCTRL UX_HOST_CLASS_CDC_ACM_IOCTL_ABORT_IN_PIPE should be OK\n"); + test_control_return(1); + } + + /* Try IOCTRL UX_HOST_CLASS_CDC_ACM_IOCTL_SEND_BREAK */ + stepinfo(">>>>>>>>>>>> IOCTRL UX_HOST_CLASS_CDC_ACM_IOCTL_SEND_BREAK\n"); + status = ux_host_class_cdc_acm_ioctl(cdc_acm_host_control, UX_HOST_CLASS_CDC_ACM_IOCTL_SEND_BREAK, &test_n); + /* Not supported by simulator */ + if (status == UX_SUCCESS) + { + + printf("ERROR #78: IOCTRL UX_HOST_CLASS_CDC_ACM_IOCTL_SEND_BREAK should fail\n"); + test_control_return(1); + } + + /* Try IOCTRL UX_HOST_CLASS_CDC_ACM_IOCTL_GET/SET_LINE_CODING */ + stepinfo(">>>>>>>>>>>> IOCTRL UX_HOST_CLASS_CDC_ACM_IOCTL_GET/SET_LINE_CODING without enough memory\n"); + + /* Use out memories */ + ux_test_utility_sim_mem_allocate_until(UX_HOST_CLASS_CDC_ACM_LINE_CODING_LENGTH); + + /* UX_HOST_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING */ + status = ux_host_class_cdc_acm_ioctl(cdc_acm_host_data, UX_HOST_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING, &test_n); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("ERROR #80: IOCTRL UX_HOST_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING should be fail if no memory\n"); + test_control_return(1); + } + + /* UX_HOST_CLASS_CDC_ACM_IOCTL_SET_LINE_CODING */ + status = ux_host_class_cdc_acm_ioctl(cdc_acm_host_data, UX_HOST_CLASS_CDC_ACM_IOCTL_SET_LINE_CODING, &line_coding_host); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("ERROR #81: IOCTRL UX_HOST_CLASS_CDC_ACM_IOCTL_SET_LINE_CODING should be fail if no memory\n"); + test_control_return(1); + } + + /* Free memory */ + ux_test_utility_sim_mem_free_all(); + + /* Try host read/write with semaphore error. */ + stepinfo(">>>>>>>>>>>> R/W semaphore error\n"); + + /* Try host write, error must be returned. */ + ux_test_utility_sim_sem_get_error_exception_add(UX_NULL, UX_WAIT_FOREVER); + ux_test_utility_sim_sem_get_error_generation_start(0); + + /* Write small size */ + status = ux_host_class_cdc_acm_write(cdc_acm_host_data, buffer, 64, &actual_length); + if (status == UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #52: write semaphore error not reported\n"); + test_control_return(1); + } + + /* Read large size */ + status = ux_host_class_cdc_acm_read(cdc_acm_host_data, buffer, UX_DEMO_BUFFER_SIZE, &actual_length); + if (status == UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #51: read semaphore error not reported\n"); + test_control_return(1); + } + ux_test_utility_sim_sem_get_error_generation_stop(); + ux_test_utility_sim_sem_get_error_exception_reset(); + + /* Try host read/write with transfer error. */ + stepinfo(">>>>>>>>>>>> R/W transfer error\n"); + + ux_test_hcd_sim_host_set_actions(error_on_transfer_0); + status = ux_host_class_cdc_acm_write(cdc_acm_host_data, buffer, 64, &actual_length); + if (status == UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #82: write transfer request error not reported\n"); + test_control_return(1); + } + + /* Stop reception for test */ + status = ux_host_class_cdc_acm_reception_stop(cdc_acm_host_data, &cdc_acm_reception); + + ux_test_hcd_sim_host_set_actions(error_on_transfer_0); + /* Read large size */ + status = ux_host_class_cdc_acm_read(cdc_acm_host_data, buffer, UX_DEMO_BUFFER_SIZE, &actual_length); + if (status == UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #83: read transfer request error not reported\n"); + test_control_return(1); + } + + /* Error on second transfer request */ + ux_test_hcd_sim_host_set_actions(error_on_transfer_1); + + /* Put a semaphore for first transfer request. */ + _ux_utility_semaphore_put(&cdc_acm_host_data->ux_host_class_cdc_acm_bulk_in_endpoint->ux_endpoint_transfer_request.ux_transfer_request_semaphore); + + /* Read large size */ + status = ux_host_class_cdc_acm_read(cdc_acm_host_data, buffer, UX_DEMO_BUFFER_SIZE, &actual_length); + if (status == UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #84: read transfer request error not reported\n"); + test_control_return(1); + } + if (actual_length == 0) + { + + /* CDC ACM basic test error. */ + printf("ERROR #85: actual length should not be 0\n"); + test_control_return(1); + } + + /* Flush device. */ + status = ux_host_class_cdc_acm_reception_start(cdc_acm_host_data, &cdc_acm_reception); + status = test_usbx_simulator_cdc_acm_host_send_string("ATO0",4); + status = test_usbx_simulator_cdc_acm_host_send_string("ATO0",4); + _tx_thread_sleep(10); + + /* Stop reception for read test. */ + status = ux_host_class_cdc_acm_reception_stop(cdc_acm_host_data, &cdc_acm_reception); + + stepinfo(">>>>>>>>>>>> Read transfer good\n"); + + /* ATO1: expect return OK */ + status = test_usbx_simulator_cdc_acm_host_send_string("ATO1",4); + + /* Read, expect short package. */ + status = ux_host_class_cdc_acm_read(cdc_acm_host_data, cdc_acm_reception_buffer, 64, &actual_length); + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #86: read transfer request error should not be reported\n"); + test_control_return(1); + } + if (actual_length != 2) + { + + /* CDC ACM basic test error. */ + printf("ERROR #87: actual length should be 2\n"); + test_control_return(1); + } + + /* ATO1: expect return OK */ + status = test_usbx_simulator_cdc_acm_host_send_string("ATO1",4); + + /* Read, expect exact size. */ + status = ux_host_class_cdc_acm_read(cdc_acm_host_data, cdc_acm_reception_buffer, 2, &actual_length); + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #86: read transfer request error should not be reported\n"); + test_control_return(1); + } + if (actual_length != 2) + { + + /* CDC ACM basic test error. */ + printf("ERROR #87: actual length should be 2\n"); + test_control_return(1); + } + + /* ATO0: expect ZLP */ + test_usbx_simulator_cdc_acm_host_send_string("ATO0",4); + status = ux_host_class_cdc_acm_read(cdc_acm_host_data, cdc_acm_reception_buffer, 64, &actual_length); + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #94: read transfer request error should not be reported\n"); + test_control_return(1); + } + if (actual_length != 0) + { + + /* CDC ACM basic test error. */ + printf("ERROR #95: actual length should be 0 but not %ld\n", actual_length); + test_control_return(1); + } + +#if defined(UX_DEVICE_CLASS_CDC_ACM_WRITE_AUTO_ZLP) + test_usbx_simulator_cdc_acm_host_send_string("ATO2",4); + status = ux_host_class_cdc_acm_read(cdc_acm_host_data, cdc_acm_reception_buffer, UX_DEMO_RECEPTION_BUFFER_SIZE, &actual_length); + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #%d: read transfer request error should not be reported\n", __LINE__); + test_control_return(1); + } + if (actual_length != 64) + { + + /* CDC ACM basic test error. */ + printf("ERROR #%d: actual length should be 64 but not %ld\n", __LINE__, actual_length); + test_control_return(1); + } +#endif + + /* Start the reception for cdc_acm. */ + status = ux_host_class_cdc_acm_reception_start(cdc_acm_host_data, &cdc_acm_reception); + + /* Swap bulk IN/OUT endpoint position. + Simulate detach and attach for HS enumeration, + and test possible mutex creation error handlings. + */ + if (rsc_cdc_mutex_usage) stepinfo(">>>>>>>>>>>> Enumerate mutex error\n"); + for (test_n = 0; test_n < rsc_cdc_mutex_usage; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_cdc_mutex_usage - 1); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Swap EP address. */ + test_swap_framework_bulk_ep_descriptors(); + + /* Generate error while the test_n and after mutex are requested */ + ux_test_utility_sim_mutex_error_generation_start(test_n + rsc_enum_mutex_usage); + + /* Connect. */ + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + tx_thread_sleep(100); + + if (cdc_acm_host_control && cdc_acm_host_data) + { + + printf("ERROR #97: at least one interface should fail\n"); + test_control_return(1); + } + } + ux_test_utility_sim_mutex_error_generation_stop(); + + /* Simulate detach and attach for FS enumeration, + and test possible semaphore creation error handlings. + */ + ux_test_utility_sim_sem_get_error_exception_add(&_ux_system_host -> ux_system_host_hcd_semaphore, UX_WAIT_FOREVER); + if (rsc_cdc_sem_usage) stepinfo(">>>>>>>>>>>> Enumerate semaphore error\n"); + for (test_n = 0; test_n < rsc_cdc_sem_usage; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_cdc_sem_usage - 1); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Generate error while the test_n and after semaphore are requested */ + ux_test_utility_sim_sem_error_generation_start(test_n + rsc_enum_sem_usage); + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + #if 0 + tx_thread_sleep(100); + #else + /* Wait until error detected. */ + ux_test_breakable_sleep(100, sleep_break_on_error); + #endif + + if (cdc_acm_host_control && cdc_acm_host_data) + { + + printf("ERROR #97: at least one interface should fail\n"); + test_control_return(1); + } + } + ux_test_utility_sim_sem_error_generation_stop(); + ux_test_utility_sim_sem_get_error_exception_reset(); + + stepinfo(">>>>>>>>>>>> Enumerate interrupt EP transfer request error\n"); + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + /* Transfer error on interrupt IN 0x83 */ + ux_test_hcd_sim_host_set_actions(error_on_transfer_interruptEP); + /* Connect. */ + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + tx_thread_sleep(100); + if (cdc_acm_host_control) + { + + printf("ERROR #96: control interface should fail\n"); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Capabilities get\n"); + + /* Confirm connection */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + ux_test_hcd_sim_host_set_actions(UX_NULL); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + test_n = 10; + while(cdc_acm_host_control == UX_NULL && test_n --) + tx_thread_sleep(10); + if (cdc_acm_host_control == UX_NULL) + { + + printf("ERROR #99: CDC ACM control interface is not ready\n"); + test_control_return(1); + } + + /* Some of descriptor length is too small */ + replaced_cfg_descriptor[9+8+9+5] = 0; + ux_test_hcd_sim_host_set_actions(replaced_GetCfgDescr); + status = _ux_host_class_cdc_acm_capabilities_get(cdc_acm_host_control); + if (status != UX_DESCRIPTOR_CORRUPTED) + { + + printf("ERROR #100: descriptor error should be reported\n"); + test_control_return(1); + } + + /* Some of descriptor length is too large */ + replaced_cfg_descriptor[9+8+9+5] = sizeof(replaced_cfg_descriptor); + ux_test_hcd_sim_host_set_actions(replaced_GetCfgDescr); + status = _ux_host_class_cdc_acm_capabilities_get(cdc_acm_host_control); + if (status != UX_DESCRIPTOR_CORRUPTED) + { + + printf("ERROR #101: no descriptor error reported\n"); + test_control_return(1); + } + + /* Restore descriptor size */ + replaced_cfg_descriptor[9+8+9+5] = device_framework_full_speed[18 + 9+8+9+5]; + /* Set descriptor sub class to DLC */ + replaced_cfg_descriptor[9+8 + 6] = UX_HOST_CLASS_CDC_DLC_SUBCLASS; + ux_test_hcd_sim_host_set_actions(replaced_GetCfgDescr); + status = _ux_host_class_cdc_acm_capabilities_get(cdc_acm_host_control); + if (status != UX_SUCCESS) + { + + printf("ERROR #102: no error expected\n"); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Deactivate while writing\n"); + test_usbx_simulator_cdc_acm_host_send_string("ATK",3); /* Disconnect after 10 tick */ + ux_test_hcd_sim_host_set_actions(wait_disconn_on_transfer_0); + status = ux_host_class_cdc_acm_write(cdc_acm_host_data, cdc_acm_xmit_buffer, 16384, &actual_length); + + 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_cdc_acm_name, ux_device_class_cdc_acm_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); + +} + + +UINT test_usbx_simulator_cdc_acm_host_send_command(UCHAR *string, ULONG length, ULONG no_ack) +{ + +UINT status; +ULONG actual_length; + + /* Perform a write to the modem to echo values. And wait for the answer. */ + ux_utility_memory_copy(cdc_acm_xmit_buffer, string,length); + cdc_acm_xmit_buffer[length] = 0x0d; + cdc_acm_xmit_buffer[length+1] = 0x0a; + + /* Update the length. */ + length += 2; + + /* Send the AT command. */ + status = ux_host_class_cdc_acm_write(cdc_acm_host_data, cdc_acm_xmit_buffer, length, &actual_length); + + /* The device may be extracted after we start sending\receiving. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait for the answer. */ + if (!no_ack) + while(command_received_count == 0) + tx_thread_sleep(10); + + /* Reset receive count. */ + command_received_count = 0; + + /* Return status. */ + return(status); +} + +void test_thread_host_reception_callback(UX_HOST_CLASS_CDC_ACM *cdc_acm, UINT status, UCHAR *reception_buffer, ULONG reception_size) +{ + + /* Incase target to test overflow case, buffers are not moved. */ + if (!cdc_acm_reception_overflow) + { + /* And move to the next reception buffer. Check if we are at the end of the application buffer. */ + if (cdc_acm_reception.ux_host_class_cdc_acm_reception_data_tail + cdc_acm_reception.ux_host_class_cdc_acm_reception_block_size >= + cdc_acm_reception.ux_host_class_cdc_acm_reception_data_buffer + cdc_acm_reception.ux_host_class_cdc_acm_reception_data_buffer_size) + + /* We are at the end of the buffer. Move back to the beginning. */ + cdc_acm_reception.ux_host_class_cdc_acm_reception_data_tail = cdc_acm_reception.ux_host_class_cdc_acm_reception_data_buffer; + + else + + /* Program the tail to be after the current buffer. */ + cdc_acm_reception.ux_host_class_cdc_acm_reception_data_tail += cdc_acm_reception.ux_host_class_cdc_acm_reception_block_size; + } + if (status == UX_BUFFER_OVERFLOW) + cdc_acm_reception_overflow = UX_FALSE; + + /* Keep the buffer pointer and length received. */ + global_reception_buffer = reception_buffer; + global_reception_size = reception_size; + + /* We have received a response. */ + command_received_count++; + + return; +} + +static VOID ux_test_host_class_cdc_acm_device_status_change_callback( + struct UX_HOST_CLASS_CDC_ACM_STRUCT *cdc_acm, + ULONG notification_type, + ULONG notification_value) +{ + + /* We received a notification */ + notification_count ++; +} + + +void tx_test_thread_slave_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG requested_length; +ULONG actual_length; +UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_PARAMETER line_coding; +UX_SLAVE_CLASS_CDC_ACM_LINE_STATE_PARAMETER line_state; +UX_SLAVE_CLASS_COMMAND class_command; + +UCHAR data_bit[16]; + +ULONG read_size = 64; +ULONG write_size; + + /* The stack/class code always invoke ux_device_class_cdc_acm_entry correct. + Do a command request error test here. */ + class_command.ux_slave_class_command_request = 0xFF; + status = ux_device_class_cdc_acm_entry(&class_command); + /* Error should be reported */ + if (status == UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #30\n"); + test_control_return(1); + } + + /* On CDC ACM driver initialize, there is memory allocation for: + - instance of the device cdc_acm class + - mute for each of endpoint (EP IN and EP OUT) + mute creation never fails so there is no tests. + */ + /* Use out memories */ + ux_test_utility_sim_mem_allocate_until(sizeof(UX_SLAVE_CLASS_CDC_ACM)); + + /* Try initialize CDC ACM instance */ + class_command.ux_slave_class_command_request = UX_SLAVE_CLASS_COMMAND_INITIALIZE; + status = ux_device_class_cdc_acm_entry(&class_command); + /* Error should be reported */ + if (status == UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #32\n"); + test_control_return(1); + } + + /* Free memory after test */ + ux_test_utility_sim_mem_free_all(); + + while(1) + { + + /* Ensure the CDC class is mounted. */ + while(cdc_acm_slave != UX_NULL && cdc_acm_slave_bulk_read_write == UX_TRUE) + { + + /* Read from the CDC class. */ + status = ux_device_class_cdc_acm_read(cdc_acm_slave, buffer, read_size, &actual_length); + + if (status != UX_SUCCESS) + { + + break; + } + + /* Change read size for different read cases */ + if (read_size <= 64) + read_size = UX_SLAVE_REQUEST_DATA_MAX_LENGTH; + + /* The actual length becomes the requested length. */ + requested_length = actual_length; + + /* Check for AT command. */ + if (*buffer == 'A' && *(buffer + 1) == 'T') + { + + /* This is a AT command. Decode next byte. */ + switch (*(buffer + 2)) + { + case 'K' : /* Break! */ + + tx_thread_sleep(10); + ux_test_hcd_sim_host_disconnect(); + break; + + case 'O' : + + /* Start writing. */ + switch(*(buffer + 3)) + { + case '0': /* ZLP */ + write_size = 0; + break; + case '1': /* Short packet of 2 */ + write_size = 2; + break; + case '2': /* Full packet of 64 */ + write_size = 64; + break; + case '3': /* Full packet of 512 */ + write_size = 512; + break; + case '4': /* Full packet of 4096 */ + write_size = 4096; + break; + case '5': /* Full packet of 8128 */ + write_size = 8128; + break; + case 'P': /* Full packet of 64 */ + write_size = 64; + read_size = 64; /* Next read is 64 */ + break; + default: + write_size = UX_DEMO_BUFFER_SIZE * 4; + break; + } + + status = ux_device_class_cdc_acm_write(cdc_acm_slave, buffer, write_size, &actual_length); + if (status == UX_TRANSFER_BUS_RESET) + status = ux_device_class_cdc_acm_write(cdc_acm_slave, buffer, write_size, &actual_length); + + break; + + case 'W' : + + /* Start writing. */ + status = ux_device_class_cdc_acm_write(cdc_acm_slave, buffer, UX_DEMO_BUFFER_SIZE, &actual_length); + if (status == UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #50\n"); + test_control_return(1); + } + + break; + + case 'A' : + + /* This is to try abort XMIT. Pending or next XMIT aborted. */ + status = _ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_ABORT_PIPE, (VOID*)UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_XMIT); + /* Error should not be reported */ + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #35\n"); + test_control_return(1); + } + + /* This is to try abort RCV. */ + status = _ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_ABORT_PIPE, (VOID*)UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_RCV); + /* Error should not be reported */ + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #39\n"); + test_control_return(1); + } + + /* This is to try abort unknown. */ + status = _ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_ABORT_PIPE, (VOID*)0xFF); + /* Error should be reported */ + if (status == UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #47\n"); + test_control_return(1); + } + + status = tx_test_thread_slave_simulation_response(_rsp_ok, UX_DEMO_BUFFER_SIZE - 2); + if (status != UX_SUCCESS) + { + /* Try again if it's aborted */ + status = tx_test_thread_slave_simulation_response(_rsp_ok, UX_DEMO_BUFFER_SIZE - 2); + } + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #44: response sent error %x\n", status); + test_control_return(1); + } + + break; + + case 'F' : + + /* This is to try invalid IOCTRL code */ + status = _ux_device_class_cdc_acm_ioctl(cdc_acm_slave, 0xFF, 0); + + /* Error should be reported */ + if (status == UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #34\n"); + test_control_return(1); + } + /* Send response any case */ + status = tx_test_thread_slave_simulation_response("OK", 2); + if (status == UX_TRANSFER_BUS_RESET) + status = tx_test_thread_slave_simulation_response("OK", 2); + /* Send ZLP */ + ux_device_class_cdc_acm_write(cdc_acm_slave, buffer, 0, &actual_length); + break; + + case 'L' : + + /* This is to set line coding. */ + line_coding.ux_slave_class_cdc_acm_parameter_baudrate = buffer[3] + (buffer[4] << 8) + (buffer[5] << 16) + (buffer[6] << 24); + line_coding.ux_slave_class_cdc_acm_parameter_stop_bit = *(buffer + 7); + line_coding.ux_slave_class_cdc_acm_parameter_parity = *(buffer + 8); + line_coding.ux_slave_class_cdc_acm_parameter_data_bit = *(buffer + 9); + status = _ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_CODING, &line_coding); + + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #38\n"); + test_control_return(1); + } + /* Send response any case */ + status = tx_test_thread_slave_simulation_response("OK", 2); + break; + + case 'B' : + + /* This is to retrieve BAUD rate. */ + status = _ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING, &line_coding); + + /* Any error ? */ + if (status == UX_SUCCESS) + { + /* Decode BAUD rate. */ + switch (line_coding.ux_slave_class_cdc_acm_parameter_baudrate) + { + + case 300 : + status = tx_test_thread_slave_simulation_response("300", 3); + break; + + case 1200 : + status = tx_test_thread_slave_simulation_response("1200", 4); + break; + + case 2400 : + status = tx_test_thread_slave_simulation_response("2400", 4); + break; + + case 4800 : + status = tx_test_thread_slave_simulation_response("4800", 4); + break; + + case 9600 : + status = tx_test_thread_slave_simulation_response("9600", 4); + break; + + case 14400 : + status = tx_test_thread_slave_simulation_response("14400", 5); + break; + + case 19200 : + status = tx_test_thread_slave_simulation_response("19200", 5); + break; + + case 28800 : + status = tx_test_thread_slave_simulation_response("28800", 5); + break; + + case 38400 : + status = tx_test_thread_slave_simulation_response("38400", 5); + break; + + case 57600 : + status = tx_test_thread_slave_simulation_response("57600", 5); + break; + + case 115200 : + status = tx_test_thread_slave_simulation_response("115200", 6); + break; + + case 230400 : + status = tx_test_thread_slave_simulation_response("230400", 6); + break; + } + + } + break; + + + case 'S' : + + /* This is to retrieve stop bit rate. */ + status = _ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING, &line_coding); + + /* Any error ? */ + if (status == UX_SUCCESS) + { + + /* Decode stop bit. */ + switch (line_coding.ux_slave_class_cdc_acm_parameter_stop_bit) + { + + case 0 : + status = tx_test_thread_slave_simulation_response("0 Stop bit", 10); + break; + + case 1 : + status = tx_test_thread_slave_simulation_response("1.5 Stop bit", 12); + break; + + case 2 : + status = tx_test_thread_slave_simulation_response("2 Stop bit", 10); + break; + } + } + break; + + + case 'P' : + + /* This is to retrieve parity rate. */ + status = _ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING, &line_coding); + + /* Any error ? */ + if (status == UX_SUCCESS) + { + + /* Decode Parity bit. */ + switch (line_coding.ux_slave_class_cdc_acm_parameter_parity) + { + + case 0 : + status = tx_test_thread_slave_simulation_response("Parity none", 11); + break; + + case 1 : + status = tx_test_thread_slave_simulation_response("Parity odd", 10); + break; + + case 2 : + status = tx_test_thread_slave_simulation_response("Parity even", 11); + break; + + case 3 : + status = tx_test_thread_slave_simulation_response("Parity mark", 11); + break; + + case 4 : + status = tx_test_thread_slave_simulation_response("Parity space", 12); + break; + + + } + } + break; + + case 'D' : + + /* This is to retrieve Data Bit. */ + status = _ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING, &line_coding); + + /* Any error ? */ + if (status == UX_SUCCESS) + { + /* Copy generic string. */ + ux_utility_memory_copy(data_bit, "Data Bit x",10); + + /* Put data bit value. */ + data_bit[9] = line_coding.ux_slave_class_cdc_acm_parameter_data_bit + '0'; + + /* Send data. */ + status = tx_test_thread_slave_simulation_response(data_bit, 10); + } + break; + + case 'R' : + + /* This is to retrieve RTS state. */ + status = _ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_STATE, &line_state); + + /* Any error ? */ + if (status == UX_SUCCESS) + { + /* Check state. */ + if (line_state.ux_slave_class_cdc_acm_parameter_rts == UX_TRUE) + + /* State is ON. */ + status = tx_test_thread_slave_simulation_response("RTS ON", 6); + + else + + /* State is OFF. */ + status = tx_test_thread_slave_simulation_response("RTS OFF", 7); + + } + break; + + case 'T' : + + /* This is to retrieve DTR state. */ + status = _ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_STATE, &line_state); + + /* Any error ? */ + if (status == UX_SUCCESS) + { + /* Check state. */ + if (line_state.ux_slave_class_cdc_acm_parameter_dtr == UX_TRUE) + + /* State is ON. */ + status = tx_test_thread_slave_simulation_response("DTR ON", 6); + + else + + /* State is OFF. */ + status = tx_test_thread_slave_simulation_response("DTR OFF", 7); + + } + break; + } + } + else + { + + /* Not an AT command, just echo back. */ + /* Check the status. If OK, we will write to the CDC instance. */ + status = ux_device_class_cdc_acm_write(cdc_acm_slave, buffer, requested_length, &actual_length); + + /* Check for CR/LF. */ + if (buffer[requested_length - 1] == '\r') + { + + /* Copy LF value into user buffer. */ + ux_utility_memory_copy(buffer, "\n", 1); + + /* And send it again. */ + status = ux_device_class_cdc_acm_write(cdc_acm_slave, buffer, 1, &actual_length); + + } + } + } + + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); + } +} + +UINT tx_test_thread_slave_simulation_response(UCHAR *string, ULONG length) +{ + +UINT status; +ULONG actual_length; + + /* Perform a write to the modem to echo values. And wait for the answer. */ + ux_utility_memory_copy(buffer, string,length); + buffer[length] = 0x0d; + buffer[length+1] = 0x0a; + + /* Update the length. */ + length += 2; + + /* Check the status. If OK, we will write to the CDC instance. */ + status = ux_device_class_cdc_acm_write(cdc_acm_slave, buffer, length, &actual_length); + + /* Return status. */ + return(status); +} + +static UINT ux_test_host_class_cdc_acm_command(UX_HOST_CLASS_CDC_ACM *cdc_acm, ULONG command, + ULONG value, UCHAR *data_buffer, ULONG data_length, + ULONG *actual_length) +{ + +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UINT status; +ULONG request_direction; + + /* We need to get the default control endpoint transfer request pointer. */ + control_endpoint = &cdc_acm -> ux_host_class_cdc_acm_device -> ux_device_control_endpoint; + transfer_request = &control_endpoint -> ux_endpoint_transfer_request; + switch(command) + { + case UX_HOST_CLASS_CDC_ACM_REQ_GET_ENCAPSULATED_COMMAND: + case UX_HOST_CLASS_CDC_ACM_REQ_GET_COMM_FEATURE: + case UX_HOST_CLASS_CDC_ACM_REQ_GET_LINE_CODING: + case UX_HOST_CLASS_CDC_ACM_REQ_GET_RINGER_PARMS: + case UX_HOST_CLASS_CDC_ACM_REQ_GET_OPERATION_PARMS: + case UX_HOST_CLASS_CDC_ACM_REQ_GET_LINE_PARMS: + + request_direction = UX_REQUEST_IN; + break; + + default: + + request_direction = UX_REQUEST_OUT; + } + + /* Protect the control endpoint semaphore here. It will be unprotected in the + transfer request function. */ + status = _ux_utility_semaphore_get(&cdc_acm -> ux_host_class_cdc_acm_device -> ux_device_protection_semaphore, UX_WAIT_FOREVER); + + /* Check for status. */ + if (status != UX_SUCCESS) + + /* Something went wrong. */ + return(status); + + /* Create a transfer_request for the request. */ + transfer_request -> ux_transfer_request_data_pointer = data_buffer; + transfer_request -> ux_transfer_request_requested_length = data_length; + transfer_request -> ux_transfer_request_function = command; + transfer_request -> ux_transfer_request_type = request_direction | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_value = value; + transfer_request -> ux_transfer_request_index = cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceNumber; + + /* Send request to HCD layer. */ + status = ux_host_stack_transfer_request(transfer_request); + + /* Fill actual length */ + if (actual_length) { + *actual_length = transfer_request -> ux_transfer_request_actual_length; + } + + /* Return completion status. */ + return(status); +} + diff --git a/test/regression/usbx_cdc_acm_configure_test.c b/test/regression/usbx_cdc_acm_configure_test.c new file mode 100644 index 00000000..d4c164d0 --- /dev/null +++ b/test/regression/usbx_cdc_acm_configure_test.c @@ -0,0 +1,860 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" + +#include "ux_host_class_cdc_acm.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#include "ux_host_stack.h" + +/* Define constants. */ +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +/* Define global data structures. */ +UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +UX_HOST_CLASS *class_driver; +UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; + +UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +UCHAR cdc_acm_slave_change; +UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; + +ULONG error_counter; + +ULONG set_cfg_counter; + +ULONG rsc_mem_free_on_set_cfg; +ULONG rsc_sem_on_set_cfg; +ULONG rsc_sem_get_on_set_cfg; +ULONG rsc_mutex_on_set_cfg; + +ULONG rsc_enum_sem_usage; +ULONG rsc_enum_sem_get_count; +ULONG rsc_enum_mutex_usage; +ULONG rsc_enum_mem_usage; + +/* Define device framework. */ + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 161 +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 171 +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x02, /* bNumConfigurations */ + + /* Configuration 1 descriptor 9 bytes, total 68 bytes */ + 0x09, 0x02, 0x44, 0x00, /* ,,wTotalLength */ + 0x02, 0x01, 0x00, /* ,bConfigurationValue, */ + 0x40, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, /* ,,bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + 0x02, 0x02, 0x01, /* bInterfaceClass,SubClass,Protocol */ + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, + 0x02, + 0x40, 0x00, + 0x00, + + /* Configuration 2 descriptor 9 bytes, total 75 bytes */ + 0x09, 0x02, 0x4b, 0x00, /* ,,wTotalLength */ + 0x02, 0x02, 0x00, /* ,bConfigurationValue, */ + 0x40, 0xFA, /* bmAttributes,bMaxPower () */ + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, /* ,,bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x02, 0x02, 0x01, /* bInterfaceClass,SubClass,Protocol */ + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Endpoint 0x83 descriptor 7 bytes */ + 0x07, 0x05, 0x83, /* ,,bEndpointAddress */ + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, + 0x02, + 0x40, 0x00, + 0x00, +}; + +#define DEVICE_FRAMEWORK_EPA_POS_1_FS (DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 14 + 2) +#define DEVICE_FRAMEWORK_EPA_POS_2_FS (DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 7 + 2) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x02, /* bNumConfigurations */ + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor 9 bytes, total 68 bytes */ + 0x09, 0x02, 0x44, 0x00, /* ,,wTotalLength */ + 0x02, 0x01, 0x00, /* ,bConfigurationValue, */ + 0x40, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, /* ,,bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + 0x02, 0x02, 0x01, /* bInterfaceClass,SubClass,Protocol */ + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, + 0x02, + 0x40, 0x00, + 0x00, + + /* Configuration 2 descriptor 9 bytes, total 75 bytes */ + 0x09, 0x02, 0x4b, 0x00, /* ,,wTotalLength */ + 0x02, 0x02, 0x00, /* ,bConfigurationValue, */ + 0x40, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, /* ,,bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x02, 0x02, 0x01, /* bInterfaceClass,SubClass,Protocol */ + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Endpoint 0x83 descriptor 7 bytes */ + 0x07, 0x05, 0x83, /* ,,bEndpointAddress */ + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, + 0x02, + 0x40, 0x00, + 0x00, +}; + +#define DEVICE_FRAMEWORK_EPA_POS_1_HS (DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 14 + 2) +#define DEVICE_FRAMEWORK_EPA_POS_2_HS (DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 7 + 2) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +static UX_TEST_HCD_SIM_ACTION error_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_ERROR, UX_NULL}, /* Error */ +{ 0 } +}; + +static UX_CONFIGURATION *cfg_2_modify; +static VOID ux_test_hcd_entry_interaction_set_cfg(UX_TEST_ACTION *action, VOID *_params) +{ + + if (cfg_2_modify) + cfg_2_modify -> ux_configuration_handle = 0; +} + +static UX_TEST_HCD_SIM_ACTION corrupt_configuration_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_interaction_set_cfg, + UX_TRUE}, /* Go on */ +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_acm_configure_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + printf("Running CDC ACM Configure 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(); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register CDC ACM class */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_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); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register HCD for test */ + 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(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +ULONG mem_free; +UX_HOST_CLASS_COMMAND class_command; +UX_CONFIGURATION *configuration; +UX_HOST_CLASS_CDC_ACM *cdc_control; +UX_HOST_CLASS_CDC_ACM *cdc_data; +UX_DEVICE *device; +UX_DEVICE *parent_device; +UX_INTERFACE *interface; + + stepinfo("\n"); + + /* Test connect. */ + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + tx_thread_sleep(100); + if (cdc_acm_host_control == UX_NULL || cdc_acm_host_data == UX_NULL || cdc_acm_slave == UX_NULL) + { + + printf("ERROR #%d: connection not detected\n", __LINE__); + test_control_return(1); + } + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + cdc_control = cdc_acm_host_control; + cdc_data = cdc_acm_host_data; + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + test_n = 10; + while((cdc_acm_host_control || cdc_acm_host_data || cdc_acm_slave) && test_n --) + tx_thread_sleep(10); + + if (cdc_acm_host_control || cdc_acm_host_data || cdc_acm_slave) + { + + printf("ERROR #%d: instance not removed when disconnect, %p %p %p\n", __LINE__, cdc_acm_host_control, cdc_acm_host_data, cdc_acm_slave); + test_control_return(1); + } + if (_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available <= mem_free) + { + + printf("ERROR #%d: memory not freed when disconnect\n", __LINE__); + test_control_return(1); + } + + /* Test configure function */ + stepinfo(">>>>>>>>>>>>>>>> Test Configure\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + /* Now connect, configuration stopped because power issue */ + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + tx_thread_sleep(100); + /* Find device */ + status = _ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + /* Reset configuration */ + status = ux_host_stack_device_configuration_reset(device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + /* Find configuration */ + status = _ux_host_stack_device_configuration_get(device, 0, &configuration); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + /* Force power source */ + device -> ux_device_power_source = UX_DEVICE_BUS_POWERED; + /* Activate interfaces */ + class_command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_ACTIVATE; + /* Control interface */ + interface = configuration -> ux_configuration_first_interface; + class_command.ux_host_class_command_container = (VOID *)interface; + class_command.ux_host_class_command_class_ptr = interface->ux_interface_class; + status = interface->ux_interface_class->ux_host_class_entry_function(&class_command); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + /* Data interface */ + interface = configuration -> ux_configuration_first_interface->ux_interface_next_interface; + class_command.ux_host_class_command_container = (VOID *)interface; + class_command.ux_host_class_command_class_ptr = interface->ux_interface_class; + status = interface->ux_interface_class->ux_host_class_entry_function(&class_command); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test Configure ERROR\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + /* Now connect, configuration stopped because power issue */ + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + tx_thread_sleep(100); + /* Find device */ + status = _ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + /* Reset configuration */ + status = ux_host_stack_device_configuration_reset(device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + /* Find configuration */ + status = _ux_host_stack_device_configuration_get(device, 0, &configuration); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#if UX_MAX_DEVICES > 1 + stepinfo(">>>>>>>>>>>>>>>> Test Configure ERROR - Parent power fail\n"); + /* Get a device */ + parent_device = _ux_host_stack_new_device_get(); + /* Use this device as parent */ + parent_device -> ux_device_power_source = UX_DEVICE_BUS_POWERED; + device -> ux_device_parent = parent_device; + /* Force power source */ + device -> ux_device_power_source = UX_DEVICE_BUS_POWERED; + /* Activate interfaces */ + class_command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_ACTIVATE; + /* Control interface */ + interface = configuration -> ux_configuration_first_interface; + class_command.ux_host_class_command_container = (VOID *)interface; + class_command.ux_host_class_command_class_ptr = interface->ux_interface_class; + status = interface->ux_interface_class->ux_host_class_entry_function(&class_command); + if (status != UX_CONNECTION_INCOMPATIBLE) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test Configure ERROR - Configuration handler\n"); + device -> ux_device_handle = 0; + status = interface->ux_interface_class->ux_host_class_entry_function(&class_command); + if (status != UX_CONFIGURATION_HANDLE_UNKNOWN) + { + + printf("ERROR %d: expect UX_CONFIGURATION_HANDLE_UNKNOWN but got 0x%x\n", __LINE__, status); + test_control_return(1); + } + device -> ux_device_handle = (ULONG) (ALIGN_TYPE) device; + + stepinfo(">>>>>>>>>>>>>>>> Test Configure ERROR - Parent power OK but SetConfigure error\n"); + parent_device -> ux_device_power_source = UX_DEVICE_SELF_POWERED; + ux_test_hcd_sim_host_set_actions(error_on_SetCfg); + status = interface->ux_interface_class->ux_host_class_entry_function(&class_command); + if (status == UX_SUCCESS) + { + + printf("ERROR %d: expect fail\n", __LINE__); + test_control_return(1); + } +#endif + stepinfo(">>>>>>>>>>>>>>>> Test Configure ERROR - Device power OK but SetConfigure error\n"); + device -> ux_device_power_source = UX_DEVICE_SELF_POWERED; + ux_test_hcd_sim_host_set_actions(error_on_SetCfg); + status = interface->ux_interface_class->ux_host_class_entry_function(&class_command); + if (status == UX_SUCCESS) + { + + printf("ERROR %d: expect fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test Configure ERROR - SetConfigure\n"); + UX_DEVICE_PARENT_SET(device, UX_NULL); + ux_test_hcd_sim_host_set_actions(error_on_SetCfg); + status = interface->ux_interface_class->ux_host_class_entry_function(&class_command); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + stepinfo(">>>>>>>>>>>>>>>> Test Configure ERROR - Interface get\n"); + /* Break the configuration */ + cfg_2_modify = configuration; + ux_test_hcd_sim_host_set_actions(corrupt_configuration_on_SetCfg); + status = interface->ux_interface_class->ux_host_class_entry_function(&class_command); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: %x\n", __LINE__, status); + test_control_return(1); + } + /* Restore */ + cfg_2_modify = UX_NULL; + configuration->ux_configuration_handle = (ULONG)(ALIGN_TYPE)configuration; + + /* Deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); + } +} diff --git a/test/regression/usbx_cdc_acm_device_dtr_rts_reset_on_disconnect_test.c b/test/regression/usbx_cdc_acm_device_dtr_rts_reset_on_disconnect_test.c new file mode 100644 index 00000000..20ebbbe4 --- /dev/null +++ b/test/regression/usbx_cdc_acm_device_dtr_rts_reset_on_disconnect_test.c @@ -0,0 +1,526 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" +#include "ux_host_class_cdc_acm.h" +#include "ux_test_dcd_sim_slave.h" +#include "ux_test.h" + +/* Define constants. */ +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE 2048 +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); +static void tx_demo_thread_slave_simulation_entry(ULONG); +static void demo_thread_host_reception_callback(UX_HOST_CLASS_CDC_ACM *cdc_acm, UINT status, UCHAR *reception_buffer, ULONG reception_size); +static VOID demo_cdc_instance_activate(VOID *cdc_instance); +static VOID demo_cdc_instance_deactivate(VOID *cdc_instance); +static UINT demo_usbx_simulator_cdc_acm_host_send_at_command(UCHAR *string, ULONG length); +static UINT tx_demo_thread_slave_simulation_response(UCHAR *string, ULONG length); + + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; +static ULONG command_received_count; +static UCHAR cdc_acm_reception_buffer[UX_DEMO_RECEPTION_BUFFER_SIZE]; +static UCHAR cdc_acm_xmit_buffer[UX_DEMO_XMIT_BUFFER_SIZE]; +static UX_HOST_CLASS_CDC_ACM_RECEPTION cdc_acm_reception; +static UCHAR *global_reception_buffer; +static ULONG global_reception_size; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; +static ULONG echo_mode; + +static ULONG error_counter; + + +/* Define device framework. */ + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 93 +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 103 +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Configuration 1 descriptor 9 bytes */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Endpoint 1 descriptor 7 bytes */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* First alternate setting Endpoint 1 descriptor 7 bytes*/ + 0x07, 0x05, 0x02, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 2 descriptor 7 bytes */ + 0x07, 0x05, 0x81, + 0x02, + 0x40, 0x00, + 0x00, + +}; + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x01, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor */ + 0x05, 0x24, 0x06, + 0x00, + 0x01, + + /* Call Management Functional Descriptor */ + 0x05, 0x24, 0x01, + 0x00, + 0x01, + + /* Endpoint 1 descriptor */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* First alternate setting Endpoint 1 descriptor */ + 0x07, 0x05, 0x02, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 2 descriptor */ + 0x07, 0x05, 0x81, + 0x02, + 0x40, 0x00, + 0x00, + +}; + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 + }; + + + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static UINT demo_class_cdc_acm_get(void) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_CDC_ACM *cdc_acm_host; + + + /* Find the main cdc_acm container */ + status = ux_host_stack_class_get(_ux_system_host_class_cdc_acm_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* We get the first instance of the cdc_acm device */ + do + { + + status = ux_host_stack_class_instance_get(class, 0, (void **) &cdc_acm_host); + tx_thread_sleep(10); + } while (status != UX_SUCCESS); + + /* We still need to wait for the cdc_acm status to be live */ + while (cdc_acm_host -> ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + tx_thread_sleep(10); + + /* Isolate both the control and data interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_DATA_CLASS) + { + /* This is the data interface. */ + cdc_acm_host_data = cdc_acm_host; + + /* In that case, the second one should be the control interface. */ + status = ux_host_stack_class_instance_get(class, 1, (void **) &cdc_acm_host); + + /* Check error. */ + if (status != UX_SUCCESS) + return(status); + + /* Check for the control interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + + /* This is the control interface. */ + cdc_acm_host_control = cdc_acm_host; + + return(UX_SUCCESS); + + } + } + else + { + /* Check for the control interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + + /* This is the control interface. */ + cdc_acm_host_control = cdc_acm_host; + + /* In that case, the second one should be the data interface. */ + status = ux_host_stack_class_instance_get(class, 1, (void **) &cdc_acm_host); + + /* Check error. */ + if (status != UX_SUCCESS) + return(status); + + /* Check for the data interface. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_DATA_CLASS) + { + + /* This is the data interface. */ + cdc_acm_host_data = cdc_acm_host; + + return(UX_SUCCESS); + + } + } + } + + /* Return ERROR. */ + return(UX_ERROR); +} + +static VOID demo_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID demo_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Don't Reset the CDC instance. We need to use it after disconnection to + check for the line state values. */ + //cdc_acm_slave = UX_NULL; +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_acm_device_dtr_rts_reset_on_disconnect_test_application_define(void *first_unused_memory) +#endif +{ +CHAR * stack_pointer; +CHAR * memory_pointer; +UINT status; + + /* 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("Running CDC ACM Basic Functionality Test............................ ERROR #1\n"); + test_control_return(1); + } + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(UX_NULL); + if (status != UX_SUCCESS) + { + + printf("Running CDC ACM Basic Functionality Test............................ ERROR #2\n"); + test_control_return(1); + } + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_entry); + if (status != UX_SUCCESS) + { + + printf("Running CDC ACM Basic Functionality Test............................ ERROR #3\n"); + 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); + if (status != UX_SUCCESS) + { + + printf("Running CDC ACM Basic Functionality Test............................ ERROR #4\n"); + 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("Running CDC ACM Basic Functionality Test............................ ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = demo_cdc_instance_activate; + parameter.ux_slave_class_cdc_acm_instance_deactivate = demo_cdc_instance_deactivate; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + + if(status!=UX_SUCCESS) + { + + printf("Running CDC ACM Basic Functionality Test............................ ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running CDC ACM Basic Functionality Test............................ ERROR #7\n"); + 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("Running CDC ACM Basic Functionality Test............................ ERROR #9\n"); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_SLAVE_CLASS_CDC_ACM_LINE_STATE_PARAMETER line_state_slave; + + + /* Inform user. */ + printf("Running Device CDC-ACM DTR/RTS Reset on Disconnect Test............. "); + + /* Find the cdc_acm class and wait for the link to be up. */ + status = demo_class_cdc_acm_get(); + if (status != UX_SUCCESS) + { + + /* DPUMP basic test error. */ + printf("ERROR #10\n"); + test_control_return(1); + } + + while (!cdc_acm_slave); + + /* Wait for RTS and DTR. */ + do + { + UX_TEST_CHECK_SUCCESS(ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_STATE, &line_state_slave)); + } + while (line_state_slave.ux_slave_class_cdc_acm_parameter_dtr == 0 || + line_state_slave.ux_slave_class_cdc_acm_parameter_rts == 0); + + /* Now disconnect. */ + ux_test_disconnect_slave(); + ux_test_disconnect_host_wait_for_enum_completion(); + + /* Now make sure DTR and RTS are reset. */ + UX_TEST_CHECK_SUCCESS(ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_STATE, &line_state_slave)); + UX_TEST_ASSERT(line_state_slave.ux_slave_class_cdc_acm_parameter_dtr == 0 && + line_state_slave.ux_slave_class_cdc_acm_parameter_rts == 0); + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_alternate_setting_change_to_zero_test.c b/test/regression/usbx_cdc_ecm_alternate_setting_change_to_zero_test.c new file mode 100644 index 00000000..ab34d569 --- /dev/null +++ b/test/regression/usbx_cdc_ecm_alternate_setting_change_to_zero_test.c @@ -0,0 +1,62 @@ +/* This tests the case where the host sets the device's alternate setting to + zero. */ + +#include "usbx_ux_test_cdc_ecm.h" +#include "ux_host_stack.h" + +static UCHAR host_ready_for_basic_test; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_alternate_setting_change_to_zero_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC ECM Alternate Setting Change To Zero Test............... "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static void post_init_host() +{ + + /* Change the data interface alternate setting to zero. */ + _ux_host_stack_interface_set(cdc_ecm_host->ux_host_class_cdc_ecm_interface_data); + + /* Wait for the host to change settings, which means the device has too. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_ulong(&cdc_ecm_host->ux_host_class_cdc_ecm_link_state, 0)); + + /* Change the data interface alternate setting back to one. */ + _ux_host_stack_interface_set(cdc_ecm_host->ux_host_class_cdc_ecm_interface_data->ux_interface_next_interface); + + /* Wait for the host to change settings, which means the device has too. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_ulong(&cdc_ecm_host->ux_host_class_cdc_ecm_link_state, 1)); + + /* Try a basic test. */ + host_ready_for_basic_test = 1; + cdc_ecm_basic_test(BASIC_TEST_HOST, BASIC_TEST_TCP); + + /* Huzzah! */ + + /* Change the data interface alternate setting to zero again - this time, with no deactivate callback. */ + cdc_ecm_device->ux_slave_class_cdc_ecm_parameter.ux_slave_class_cdc_ecm_instance_deactivate = UX_NULL; + _ux_host_stack_interface_set(cdc_ecm_host->ux_host_class_cdc_ecm_interface_data); + + /* Wait for the host to change settings, which means the device has too. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_ulong(&cdc_ecm_host->ux_host_class_cdc_ecm_link_state, 0)); + + /* Huzzah! Again! */ +} + +static void post_init_device() +{ + + /* Wait for basic test. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uchar(&host_ready_for_basic_test, 1)); + cdc_ecm_basic_test(BASIC_TEST_DEVICE, BASIC_TEST_TCP); +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_basic_ipv6_test.c b/test/regression/usbx_cdc_ecm_basic_ipv6_test.c new file mode 100644 index 00000000..3f920ddd --- /dev/null +++ b/test/regression/usbx_cdc_ecm_basic_ipv6_test.c @@ -0,0 +1,724 @@ +#ifndef USBX_UX_TEST_CDC_ECM_H +#define USBX_UX_TEST_CDC_ECM_H + +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_network_driver.h" +#include "ux_host_class_cdc_ecm.h" +#include "ux_device_class_cdc_ecm.h" +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" +#include "ux_test.h" +#include "ux_test_actions.h" + +//#define LOCAL_MACHINE + +typedef struct DEVICE_INIT_DATA +{ + UCHAR *framework; + ULONG framework_length; + UCHAR dont_register_hcd; + UCHAR *string_framework; + ULONG string_framework_length; +} DEVICE_INIT_DATA; + +#define DEMO_IP_THREAD_STACK_SIZE (8*1024) +#define HOST_IP_ADDRESS IP_ADDRESS(192,168,1,176) +#define HOST_SOCKET_PORT_UDP 45054 +#define HOST_SOCKET_PORT_TCP 45056 +#define DEVICE_IP_ADDRESS IP_ADDRESS(192,168,1,175) +#define DEVICE_SOCKET_PORT_UDP 45055 +#define DEVICE_SOCKET_PORT_TCP 45057 + +#define PACKET_PAYLOAD 1400 +#define PACKET_POOL_SIZE (PACKET_PAYLOAD*10000) +#define ARP_MEMORY_SIZE 1024 + +/* Define local constants. */ + +#define UX_DEMO_STACK_SIZE (4*1024) +#define UX_USBX_MEMORY_SIZE (128*1024) + +/* Define basic test constants. */ + +#define BASIC_TEST_NUM_ITERATIONS 10 +#define BASIC_TEST_NUM_PACKETS_PER_ITERATION 10 +#define BASIC_TEST_NUM_TOTAL_PACKETS (BASIC_TEST_NUM_ITERATIONS*BASIC_TEST_NUM_PACKETS_PER_ITERATION) +#define BASIC_TEST_HOST 0 +#define BASIC_TEST_DEVICE 1 +#define BASIC_TEST_TCP 0 +#define BASIC_TEST_UDP 1 + +/* Host */ + +static UX_HOST_CLASS *class_driver_host; +static UX_HOST_CLASS_CDC_ECM *cdc_ecm_host; +static UX_HOST_CLASS_CDC_ECM *cdc_ecm_host_from_system_change_function; +static TX_THREAD thread_host; +static UCHAR thread_stack_host[UX_DEMO_STACK_SIZE]; +static NX_IP nx_ip_host; +static NX_PACKET_POOL packet_pool_host; +static NX_PACKET_POOL *packet_pool_host_ptr = &packet_pool_host; +static NX_UDP_SOCKET udp_socket_host; +static NX_TCP_SOCKET tcp_socket_host; +static CHAR *packet_pool_memory_host; +static CHAR ip_thread_stack_host[DEMO_IP_THREAD_STACK_SIZE]; +static CHAR arp_memory_host[ARP_MEMORY_SIZE]; + +/* Device */ + +static TX_THREAD thread_device; +static UX_HOST_CLASS *class_driver_device; +static UX_SLAVE_CLASS_CDC_ECM *cdc_ecm_device; +static UX_SLAVE_CLASS_CDC_ECM_PARAMETER cdc_ecm_parameter; +static UCHAR thread_stack_device[UX_DEMO_STACK_SIZE]; +static NX_IP nx_ip_device; +static NX_PACKET_POOL packet_pool_device; +static NX_UDP_SOCKET udp_socket_device; +//static NX_TCP_SOCKET tcp_socket_device; +static CHAR *packet_pool_memory_device; +static CHAR ip_thread_stack_device[DEMO_IP_THREAD_STACK_SIZE]; +static CHAR arp_memory_device[ARP_MEMORY_SIZE]; + +static UCHAR global_is_device_initialized; +static UCHAR global_host_ready_for_application; + +static ULONG global_basic_test_num_writes_host; +static ULONG global_basic_test_num_reads_host; +static ULONG global_basic_test_num_writes_device; +static ULONG global_basic_test_num_reads_device; +static UCHAR device_is_finished; +NXD_ADDRESS ipv6_addr_host; +NXD_ADDRESS ipv6_addr_device; + +/* Define local prototypes and definitions. */ +static void thread_entry_host(ULONG arg); +static void thread_entry_device(ULONG arg); +static void post_init_host(); +static void post_init_device(); + +#define DEFAULT_FRAMEWORK_LENGTH sizeof(default_device_framework) +static unsigned char default_device_framework[] = { + + /* Device Descriptor */ + 0x12, /* bLength */ + 0x01, /* bDescriptorType */ + 0x10, 0x01, /* bcdUSB */ + 0xef, /* bDeviceClass - Depends on bDeviceSubClass */ + 0x02, /* bDeviceSubClass - Depends on bDeviceProtocol */ + 0x01, /* bDeviceProtocol - There's an IAD */ + 0x40, /* bMaxPacketSize0 */ + 0x70, 0x07, /* idVendor */ + 0x42, 0x10, /* idProduct */ + 0x00, 0x01, /* bcdDevice */ + 0x01, /* iManufacturer */ + 0x02, /* iProduct */ + 0x03, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ + + /* Configuration Descriptor */ + 0x09, /* bLength */ + 0x02, /* bDescriptorType */ + 0x58, 0x00, /* wTotalLength */ + 0x02, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xc0, /* bmAttributes - Self-powered */ + 0x00, /* bMaxPower */ + + /* Interface Association Descriptor */ + 0x08, /* bLength */ + 0x0b, /* bDescriptorType */ + 0x00, /* bFirstInterface */ + 0x02, /* bInterfaceCount */ + 0x02, /* bFunctionClass - CDC - Communication */ + 0x06, /* bFunctionSubClass - ECM */ + 0x00, /* bFunctionProtocol - No class specific protocol required */ + 0x00, /* iFunction */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x02, /* bInterfaceClass - CDC - Communication */ + 0x06, /* bInterfaceSubClass - ECM */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* CDC Header Functional Descriptor */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x00, /* bDescriptorSubType */ + 0x10, 0x01, /* bcdCDC */ + + /* CDC ECM Functional Descriptor */ + 0x0d, /* bLength */ + 0x24, /* bDescriptorType */ + 0x0f, /* bDescriptorSubType */ + 0x04, /* iMACAddress */ + 0x00, 0x00, 0x00, 0x00, /* bmEthernetStatistics */ + 0xea, 0x05, /* wMaxSegmentSize */ + 0x00, 0x00, /* wNumberMCFilters */ + 0x00, /* bNumberPowerFilters */ + + /* CDC Union Functional Descriptor */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x06, /* bDescriptorSubType */ + 0x00, /* bmMasterInterface */ + 0x01, /* bmSlaveInterface0 */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x83, /* bEndpointAddress */ + 0x03, /* bmAttributes - Interrupt */ + 0x08, 0x00, /* wMaxPacketSize */ + 0x08, /* bInterval */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x01, /* bAlternateSetting */ + 0x02, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x02, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x81, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + +}; + +static unsigned char default_string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL CDCECM Device" */ + 0x09, 0x04, 0x02, 0x10, + 0x45, 0x4c, 0x20, 0x43, 0x44, 0x43, 0x45, 0x43, + 0x4d, 0x20, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31, + + /* MAC Address string descriptor : Index 4 - "001E5841B879" */ + 0x09, 0x04, 0x04, 0x0C, + 0x30, 0x30, 0x31, 0x45, 0x35, 0x38, + 0x34, 0x31, 0x42, 0x38, 0x37, 0x39, + +}; + + /* 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 + }; + +static DEVICE_INIT_DATA default_device_init_data = { + .framework = default_device_framework, + .framework_length = sizeof(default_device_framework), + .dont_register_hcd = 0, + .string_framework = default_string_framework, + .string_framework_length = sizeof(default_string_framework) +}; + +static void ux_test_cdc_ecm_initialize_use_framework(void *first_unused_memory, DEVICE_INIT_DATA *device_init_data) +{ + +CHAR *memory_pointer = first_unused_memory; + + /* Initialize possible uninitialized device init values. */ + + if (device_init_data->framework == NULL) + { + device_init_data->framework = default_device_framework; + device_init_data->framework_length = sizeof(default_device_framework); + } + + if (device_init_data->string_framework == NULL) + { + device_init_data->string_framework = default_string_framework; + device_init_data->string_framework_length = sizeof(default_string_framework); + } + + /* Initialize USBX Memory. */ + ux_system_initialize(memory_pointer, UX_USBX_MEMORY_SIZE, UX_NULL, 0); + memory_pointer += UX_USBX_MEMORY_SIZE; + + /* It looks weird if this doesn't have a comment! */ + ux_utility_error_callback_register(ux_test_error_callback); + + /* Perform the initialization of the network driver. */ + UX_TEST_CHECK_SUCCESS(ux_network_driver_init()); + + /* Initialize the NetX system. */ + nx_system_initialize(); + + /* Now allocate memory for the packet pools. Note that using the memory passed + to us by ThreadX is mucho bettero than putting it in global memory because + we can reuse the memory for each test. So no more having to worry about + running out of memory! */ + packet_pool_memory_host = memory_pointer; + memory_pointer += PACKET_POOL_SIZE; + packet_pool_memory_device = memory_pointer; + memory_pointer += PACKET_POOL_SIZE; + + /* Create the host thread. */ + UX_TEST_CHECK_SUCCESS(tx_thread_create(&thread_host, "host thread", thread_entry_host, (ULONG)(ALIGN_TYPE)device_init_data, + thread_stack_host, UX_DEMO_STACK_SIZE, + 30, 30, 1, TX_DONT_START)); + UX_THREAD_EXTENSION_PTR_SET(&thread_host, device_init_data) + tx_thread_resume(&thread_host); + + /* Create the slave thread. */ + UX_TEST_CHECK_SUCCESS(tx_thread_create(&thread_device, "device thread", thread_entry_device, (ULONG)(ALIGN_TYPE)device_init_data, + thread_stack_device, UX_DEMO_STACK_SIZE, + 30, 30, 1, TX_DONT_START)); + UX_THREAD_EXTENSION_PTR_SET(&thread_device, device_init_data) + tx_thread_resume(&thread_device); +} + +static void ux_test_cdc_ecm_initialize(void *first_unused_memory) +{ + + ux_test_cdc_ecm_initialize_use_framework(first_unused_memory, &default_device_init_data); +} + +static UINT system_change_function(ULONG event, UX_HOST_CLASS *class, VOID *instance) +{ + if (event == UX_DEVICE_INSERTION) + { + cdc_ecm_host_from_system_change_function = instance; + } + else if (event == UX_DEVICE_REMOVAL) + { + cdc_ecm_host_from_system_change_function = UX_NULL; + } + return(UX_SUCCESS); +} + +static void class_cdc_ecm_get_host(void) +{ + +UX_HOST_CLASS *class; + + /* Find the main storage container */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_class_get(_ux_system_host_class_cdc_ecm_name, &class)); + + /* We get the first instance of the storage device */ + UX_TEST_CHECK_SUCCESS(ux_test_host_stack_class_instance_get(class, 0, (void **) &cdc_ecm_host)); + + /* We still need to wait for the cdc-ecm status to be live */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uint(&cdc_ecm_host -> ux_host_class_cdc_ecm_state, UX_HOST_CLASS_INSTANCE_LIVE)); + + /* Now wait for the link to be up. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_ulong(&cdc_ecm_host->ux_host_class_cdc_ecm_link_state, UX_HOST_CLASS_CDC_ECM_LINK_STATE_UP)); +} + +static VOID demo_cdc_ecm_instance_activate(VOID *cdc_ecm_instance) +{ + + /* Save the CDC instance. */ + cdc_ecm_device = (UX_SLAVE_CLASS_CDC_ECM *) cdc_ecm_instance; +} + +static VOID demo_cdc_ecm_instance_deactivate(VOID *cdc_ecm_instance) +{ + + /* Reset the CDC instance. */ + cdc_ecm_device = UX_NULL; +} + +/* Copied and pasted from ux_device_class_cdc_ecm_change.c. */ +static void ux_test_device_class_cdc_ecm_set_link_state(UX_SLAVE_CLASS_CDC_ECM *cdc_ecm, UCHAR new_link_state) +{ + + /* Declare the link to be down. */ + cdc_ecm_device -> ux_slave_class_cdc_ecm_link_state = new_link_state; + + /* We have a thread waiting for an event, we wake it up with a NETWORK NOTIFICATION CHANGE event. + In turn they will release the NetX resources used and suspend. */ + UX_TEST_CHECK_SUCCESS(_ux_utility_event_flags_set(&cdc_ecm_device -> ux_slave_class_cdc_ecm_event_flags_group, UX_DEVICE_CLASS_CDC_ECM_NETWORK_NOTIFICATION_EVENT, TX_OR)); +} + +static void read_packet_tcp(NX_TCP_SOCKET *tcp_socket, ULONG num_reads, CHAR *name) +{ + +NX_PACKET *rcv_packet; +ULONG num_writes_from_peer; + +#ifndef LOCAL_MACHINE + if (num_reads % 100 == 0) +#endif + stepinfo("%s reading tcp packet# %lu\n", name, num_reads); + + UX_TEST_CHECK_SUCCESS(nx_tcp_socket_receive(tcp_socket, &rcv_packet, NX_WAIT_FOREVER)); + + num_writes_from_peer = *(ULONG *)rcv_packet->nx_packet_prepend_ptr; + UX_TEST_ASSERT(num_writes_from_peer == num_reads); + + UX_TEST_CHECK_SUCCESS(nx_packet_release(rcv_packet)); +} + +static void write_packet_tcp(NX_TCP_SOCKET *tcp_socket, NX_PACKET_POOL *packet_pool, ULONG num_writes, CHAR *name) +{ + +NX_PACKET *out_packet; + + UX_TEST_CHECK_SUCCESS(nx_packet_allocate(packet_pool, &out_packet, NX_TCP_PACKET, NX_WAIT_FOREVER)); + + *(ULONG *)out_packet->nx_packet_prepend_ptr = num_writes; + out_packet->nx_packet_length = sizeof(ULONG); + out_packet->nx_packet_append_ptr = out_packet->nx_packet_prepend_ptr + out_packet->nx_packet_length; + +#ifndef LOCAL_MACHINE + if (num_writes % 100 == 0) +#endif + stepinfo("%s writing tcp packet# %lu\n", name, num_writes); + + UX_TEST_CHECK_SUCCESS(nx_tcp_socket_send(tcp_socket, out_packet, NX_WAIT_FOREVER)); +} + +static void read_packet_udp(NX_UDP_SOCKET *udp_socket, ULONG num_reads, CHAR *name) +{ + +NX_PACKET *rcv_packet; +ULONG num_writes_from_peer; + +#ifndef LOCAL_MACHINE + if (num_reads % 100 == 0) +#endif + stepinfo("%s reading udp packet# %lu\n", name, num_reads); + + UX_TEST_CHECK_SUCCESS(nx_udp_socket_receive(udp_socket, &rcv_packet, NX_WAIT_FOREVER)); + + num_writes_from_peer = *(ULONG *)rcv_packet->nx_packet_prepend_ptr; + UX_TEST_ASSERT(num_writes_from_peer == num_reads); + + UX_TEST_CHECK_SUCCESS(nx_packet_release(rcv_packet)); +} + +static void write_packet_udp(NX_UDP_SOCKET *udp_socket, NX_PACKET_POOL *packet_pool, ULONG ip_address, ULONG port, ULONG num_writes, CHAR *name) +{ + +NX_PACKET *out_packet; + + UX_TEST_CHECK_SUCCESS(nx_packet_allocate(packet_pool, &out_packet, NX_UDP_PACKET, NX_WAIT_FOREVER)); + + *(ULONG *)out_packet->nx_packet_prepend_ptr = num_writes; + out_packet->nx_packet_length = sizeof(ULONG); + out_packet->nx_packet_append_ptr = out_packet->nx_packet_prepend_ptr + out_packet->nx_packet_length; + +#ifndef LOCAL_MACHINE + if (num_writes % 100 == 0) +#endif + stepinfo("%s writing udp packet# %lu\n", name, num_writes); + + UX_TEST_CHECK_SUCCESS(nx_udp_socket_send(udp_socket, out_packet, ip_address, port)); +} + +static void thread_entry_host(ULONG device_init_data_ptr) +{ + +DEVICE_INIT_DATA *device_init_data; + + UX_THREAD_EXTENSION_PTR_GET(device_init_data, DEVICE_INIT_DATA, device_init_data_ptr); + + /* Wait for device to initialize. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uchar(&global_is_device_initialized, 1)); + + /* Create the IP instance. */ + + UX_TEST_CHECK_SUCCESS(nx_packet_pool_create(&packet_pool_host, "NetX Host Packet Pool", PACKET_PAYLOAD, packet_pool_memory_host, PACKET_POOL_SIZE)); + UX_TEST_CHECK_SUCCESS(nx_ip_create(&nx_ip_host, "NetX Host Thread", HOST_IP_ADDRESS, 0xFF000000UL, + &packet_pool_host, _ux_network_driver_entry, ip_thread_stack_host, DEMO_IP_THREAD_STACK_SIZE, 1)); + + + /* Setup ARP. */ + + UX_TEST_CHECK_SUCCESS(nx_arp_enable(&nx_ip_host, (void *)arp_memory_host, ARP_MEMORY_SIZE)); + UX_TEST_CHECK_SUCCESS(nx_arp_static_entry_create(&nx_ip_host, DEVICE_IP_ADDRESS, 0x0000001E, 0x80032CD8)); + + /* Setup UDP. */ + + UX_TEST_CHECK_SUCCESS(nx_udp_enable(&nx_ip_host)); + UX_TEST_CHECK_SUCCESS(nx_udp_socket_create(&nx_ip_host, &udp_socket_host, "USB HOST UDP SOCKET", NX_IP_NORMAL, NX_DONT_FRAGMENT, 20, 20)); + UX_TEST_CHECK_SUCCESS(nx_udp_socket_bind(&udp_socket_host, HOST_SOCKET_PORT_UDP, NX_NO_WAIT)); + + // /* Setup TCP. */ + + // UX_TEST_CHECK_SUCCESS(nx_tcp_enable(&nx_ip_host)); + // UX_TEST_CHECK_SUCCESS(nx_tcp_socket_create(&nx_ip_host, &tcp_socket_host, "USB HOST TCP SOCKET", NX_IP_NORMAL, NX_DONT_FRAGMENT, NX_IP_TIME_TO_LIVE, 100, NX_NULL, NX_NULL)); + // UX_TEST_CHECK_SUCCESS(nx_tcp_server_socket_listen(&nx_ip_host, HOST_SOCKET_PORT_TCP, &tcp_socket_host, 5, NX_NULL)); +#if 1 + UX_TEST_CHECK_SUCCESS(nxd_ipv6_enable(&nx_ip_host)); + + UX_TEST_CHECK_SUCCESS(nxd_icmp_enable(&nx_ip_host)); + + UX_TEST_CHECK_SUCCESS(nx_ip_raw_packet_enable(&nx_ip_host)); +#endif + + ipv6_addr_host.nxd_ip_version = NX_IP_VERSION_V6; + ipv6_addr_host.nxd_ip_address.v6[0] = 0x20010000; + ipv6_addr_host.nxd_ip_address.v6[1] = 0x00000000; + ipv6_addr_host.nxd_ip_address.v6[2] = 0x00000000; + ipv6_addr_host.nxd_ip_address.v6[3] = 0x00010001; + + UX_TEST_CHECK_SUCCESS(nxd_ipv6_address_set(&nx_ip_host, 0, &ipv6_addr_host, 64, NX_NULL)); + + /* The code below is required for installing the host portion of USBX. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_initialize(system_change_function)); + + /* Register cdc_ecm class. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_class_register(_ux_system_host_class_cdc_ecm_name, ux_host_class_cdc_ecm_entry)); + + if (!device_init_data->dont_register_hcd) + { + + /* Register all the USB host controllers available in this system. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + + /* Find the storage class. */ + class_cdc_ecm_get_host(); + + // /* Connect to device TCP socket. */ + // UX_TEST_CHECK_SUCCESS(nx_tcp_server_socket_accept(&tcp_socket_host, NX_WAIT_FOREVER)); + } + + global_host_ready_for_application = 1; + + /* Call test code. */ + post_init_host(); + + /* We need to disconnect the host and device. This is because the NetX cleaning + process (in usbxtestcontrol.c) includes disconnect the device, which tries + to send a RST packet to the peer (or something). By disconnecting here, + we ensure the deactivate routines notify the network driver so that the + packet tranmissiong is stopped there. */ + ux_test_disconnect_slave(); + ux_test_disconnect_host_wait_for_enum_completion(); + + /* And finally the usbx system resources. */ + _ux_system_uninitialize(); + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + +static void thread_entry_device(ULONG device_init_data_ptr) +{ + +DEVICE_INIT_DATA *device_init_data; + + UX_THREAD_EXTENSION_PTR_GET(device_init_data, DEVICE_INIT_DATA, device_init_data_ptr) + + /* Create the IP instance. */ + + UX_TEST_CHECK_SUCCESS(nx_packet_pool_create(&packet_pool_device, "NetX Device Packet Pool", PACKET_PAYLOAD, packet_pool_memory_device, PACKET_POOL_SIZE)); + + UX_TEST_CHECK_SUCCESS(nx_ip_create(&nx_ip_device, "NetX Device Thread", DEVICE_IP_ADDRESS, 0xFF000000L, &packet_pool_device, + _ux_network_driver_entry, ip_thread_stack_device, DEMO_IP_THREAD_STACK_SIZE, 1)); + + + /* Setup ARP. */ + + UX_TEST_CHECK_SUCCESS(nx_arp_enable(&nx_ip_device, (void *)arp_memory_device, ARP_MEMORY_SIZE)); + UX_TEST_CHECK_SUCCESS(nx_arp_static_entry_create(&nx_ip_device, HOST_IP_ADDRESS, 0x0000001E, 0x5841B878)); + + /* Setup UDP. */ + + UX_TEST_CHECK_SUCCESS(nx_udp_enable(&nx_ip_device)); + UX_TEST_CHECK_SUCCESS(nx_udp_socket_create(&nx_ip_device, &udp_socket_device, "USB DEVICE UDP SOCKET", NX_IP_NORMAL, NX_DONT_FRAGMENT, 20, 20)); + UX_TEST_CHECK_SUCCESS(nx_udp_socket_bind(&udp_socket_device, DEVICE_SOCKET_PORT_UDP, NX_NO_WAIT)); + + // /* Setup TCP. */ + + // UX_TEST_CHECK_SUCCESS(nx_tcp_enable(&nx_ip_device)); + // UX_TEST_CHECK_SUCCESS(nx_tcp_socket_create(&nx_ip_device, &tcp_socket_device, "USB DEVICE TCP SOCKET", NX_IP_NORMAL, NX_DONT_FRAGMENT, NX_IP_TIME_TO_LIVE, 100, NX_NULL, NX_NULL)); + // UX_TEST_CHECK_SUCCESS(nx_tcp_client_socket_bind(&tcp_socket_device, DEVICE_SOCKET_PORT_TCP, NX_WAIT_FOREVER)); + +#if 1 + UX_TEST_CHECK_SUCCESS(nxd_ipv6_enable(&nx_ip_device)); + + ipv6_addr_device.nxd_ip_version = NX_IP_VERSION_V6; + ipv6_addr_device.nxd_ip_address.v6[0] = 0x20010000; + ipv6_addr_device.nxd_ip_address.v6[1] = 0x00000000; + ipv6_addr_device.nxd_ip_address.v6[2] = 0x00000000; + ipv6_addr_device.nxd_ip_address.v6[3] = 0x00010002; + + UX_TEST_CHECK_SUCCESS(nxd_ipv6_address_set(&nx_ip_device, 0, &ipv6_addr_device, 64, NX_NULL)); + + UX_TEST_CHECK_SUCCESS(nxd_icmp_enable(&nx_ip_device)); + + UX_TEST_CHECK_SUCCESS(nx_ip_raw_packet_enable(&nx_ip_device)); + +#endif + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + UX_TEST_CHECK_SUCCESS(ux_device_stack_initialize(device_init_data->framework, device_init_data->framework_length, + device_init_data->framework, device_init_data->framework_length, + device_init_data->string_framework, device_init_data->string_framework_length, + language_id_framework, sizeof(language_id_framework), + UX_NULL)); + + /* Set the parameters for callback when insertion/extraction of a CDC device. Set to NULL.*/ + cdc_ecm_parameter.ux_slave_class_cdc_ecm_instance_activate = demo_cdc_ecm_instance_activate; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_instance_deactivate = demo_cdc_ecm_instance_deactivate; + + /* Define a NODE ID. */ + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_local_node_id[0] = 0x00; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_local_node_id[1] = 0x1e; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_local_node_id[2] = 0x58; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_local_node_id[3] = 0x41; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_local_node_id[4] = 0xb8; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_local_node_id[5] = 0x78; + + /* Define a remote NODE ID. */ + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_remote_node_id[0] = 0x00; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_remote_node_id[1] = 0x1e; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_remote_node_id[2] = 0x58; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_remote_node_id[3] = 0x41; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_remote_node_id[4] = 0xb8; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_remote_node_id[5] = 0x79; + + /* Initialize the device cdc_ecm class. */ + UX_TEST_CHECK_SUCCESS(ux_device_stack_class_register(_ux_system_slave_class_cdc_ecm_name, ux_device_class_cdc_ecm_entry, 1, 0, &cdc_ecm_parameter)); + + /* Initialize the simulated device controller. */ + UX_TEST_CHECK_SUCCESS(_ux_test_dcd_sim_slave_initialize()); + + global_is_device_initialized = UX_TRUE; + + if (!device_init_data->dont_register_hcd) + { + + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_non_null((VOID **)&cdc_ecm_device)); + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_ulong(&cdc_ecm_device->ux_slave_class_cdc_ecm_link_state, UX_DEVICE_CLASS_CDC_ECM_LINK_STATE_UP)); + + // /* Connect to host TCP socket. */ + // UX_TEST_CHECK_SUCCESS(nx_tcp_client_socket_connect(&tcp_socket_device, HOST_IP_ADDRESS, HOST_SOCKET_PORT_TCP, NX_WAIT_FOREVER)); + } + + /* Wait for host - believe this is so that we know host is always first... gives us some 'determinism'. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uchar(&global_host_ready_for_application, 1)); + + /* Call test code. */ + post_init_device(); +} + + + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_basic_ipv6_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC ECM Basic Functionality Test............................ "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static void post_init_host() +{ +UINT status; +NX_PACKET *my_packet; +ULONG value; + + /* Print out test information banner. */ + printf("\nNetX Test: IPv6 Raw Packet Test......................................"); + + tx_thread_sleep(5 * NX_IP_PERIODIC_RATE); + /* Now, pickup the three raw packets that should be queued on the other IP instance. */ + UX_TEST_CHECK_SUCCESS(nx_ip_raw_packet_receive(&nx_ip_host, &my_packet, 2 * NX_IP_PERIODIC_RATE)); + + if(memcmp(my_packet -> nx_packet_prepend_ptr, "ABCDEFGHIJKLMNOPQRSTUVWXYZ ", 28)) { + printf("ERROR #3\n"); + test_control_return(1); + } + + UX_TEST_CHECK_SUCCESS(nx_packet_release(my_packet)); + + /* Wait for device to finish. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uchar(&device_is_finished, UX_TRUE)); + + /* Disconnect. */ + ux_test_disconnect_slave_and_host_wait_for_enum_completion(); + + /* Connect with null system change function. */ + _ux_system_host->ux_system_host_change_function = UX_NULL; + + /* Connect. */ + ux_test_connect_slave_and_host_wait_for_enum_completion(); + + /* We're done. */ +} + +static void post_init_device() +{ +UINT status; +NX_PACKET *my_packet; +NXD_ADDRESS dest_addr; +ULONG value; + + tx_thread_sleep(1 * NX_IP_PERIODIC_RATE); + + /* Allocate a packet. */ + UX_TEST_CHECK_SUCCESS(nx_packet_allocate(&packet_pool_device, &my_packet, NX_UDP_PACKET, 2 * NX_IP_PERIODIC_RATE)); + + /* Write ABCs into the packet payload! */ + UX_TEST_CHECK_SUCCESS(nx_packet_data_append(my_packet, "ABCDEFGHIJKLMNOPQRSTUVWXYZ ", 28, &packet_pool_device, 2 * NX_IP_PERIODIC_RATE)); + + /* Send the raw IP packet. */ + UX_TEST_CHECK_SUCCESS(nxd_ip_raw_packet_send(&nx_ip_device, my_packet, &ipv6_addr_host, NX_IP_RAW >> 16, 0x80, NX_IP_NORMAL)); + + device_is_finished = UX_TRUE; +} + +#endif //USBX_UX_TEST_CDC_ECM_H \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_basic_memory_test.c b/test/regression/usbx_cdc_ecm_basic_memory_test.c new file mode 100644 index 00000000..82719bb0 --- /dev/null +++ b/test/regression/usbx_cdc_ecm_basic_memory_test.c @@ -0,0 +1,354 @@ +/* Include necessary system files. */ + +#include "usbx_ux_test_cdc_ecm.h" + +/* Resource usage */ + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_cdc_sem_usage; +static ULONG rsc_cdc_sem_get_count; +static ULONG rsc_cdc_mutex_usage; +static ULONG rsc_cdc_mem_alloc_count; +static ULONG rsc_cdc_mem_tx_rx_count; + +static ULONG error_callback_counter; + +/* Log resources usage on SetConfigure */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *_params) +{ + + set_cfg_counter ++; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_sem_get_on_set_cfg = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +{ .function = UX_HCD_TRANSFER_REQUEST, + .req_setup = &_SetConfigure, + .req_action = UX_TEST_SETUP_MATCH_REQ, + .action_func = ux_test_hcd_entry_set_cfg, + .no_return = UX_TRUE +}, /* Invoke callback & continue */ +{ 0 } +}; + +static void count_error_callback(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ +UX_TEST_ERROR_CALLBACK_PARAMS *error = (UX_TEST_ERROR_CALLBACK_PARAMS *)params; + + // printf("error trap: 0x%x, 0x%x, 0x%x\n", error->system_level, error->system_context, error->error_code); + error_callback_counter ++; +} + +static UX_TEST_HCD_SIM_ACTION count_on_error_trap[] = { +{ .usbx_function = UX_TEST_OVERRIDE_ERROR_CALLBACK, + .action_func = count_error_callback, +}, +{ 0 } +}; + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + +static UINT sleep_break_on_host_tx_or_rx_buffer_allocated(VOID) +{ +UINT buffer_count = 0; + if (cdc_ecm_host == UX_NULL) + return(UX_SUCCESS); + if (cdc_ecm_host -> ux_host_class_cdc_ecm_xmit_buffer) + buffer_count ++; + if (cdc_ecm_host -> ux_host_class_cdc_ecm_receive_buffer) + buffer_count ++; + return (buffer_count); +} + +static UINT sleep_break_on_host_tx_and_rx_buffer_allocated(VOID) +{ +UINT buffer_count = 0; + if (cdc_ecm_host == UX_NULL) + return(UX_SUCCESS); + if (cdc_ecm_host -> ux_host_class_cdc_ecm_xmit_buffer) + buffer_count ++; + if (cdc_ecm_host -> ux_host_class_cdc_ecm_receive_buffer) + buffer_count ++; + return ((buffer_count >=2) ? buffer_count : UX_SUCCESS); +} + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_basic_memory_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC ECM Basic Memory Test................................... "); + + stepinfo("\n"); + + /* Override error trap. */ + ux_test_link_hooks_from_array(count_on_error_trap); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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_test_cdc_ecm_initialize(first_unused_memory); +} + +static void post_init_host() +{ + +UINT status; +ULONG mem_free; +ULONG test_n; + + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_disconnect_slave(); + ux_test_disconnect_host_wait_for_enum_completion(); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_count_reset(); + ux_test_utility_sim_mutex_create_count_reset(); + ux_test_utility_sim_sem_create_count_reset(); + ux_test_utility_sim_sem_get_count_reset(); + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + + /* Save free memory usage. */ + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + stepinfo(">>>>>>>>>>>>>>>>>>> Test connect\n"); + /* Connect. */ + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + class_cdc_ecm_get_host(); + + /* Log create counts for further tests. */ + rsc_enum_mutex_usage = rsc_mutex_on_set_cfg; + rsc_enum_sem_usage = rsc_sem_on_set_cfg; + rsc_enum_mem_alloc_count = rsc_mem_alloc_cnt_on_set_cfg; + /* Log create counts when instances active for further tests. */ + rsc_cdc_mutex_usage = ux_test_utility_sim_mutex_create_count() - rsc_enum_mutex_usage; + rsc_cdc_sem_usage = ux_test_utility_sim_sem_create_count() - rsc_enum_sem_usage; + rsc_cdc_mem_alloc_count = ux_test_utility_sim_mem_alloc_count() - rsc_enum_mem_alloc_count; + /* Some allocation does not affect enum. */ + rsc_cdc_mem_tx_rx_count = 0; + if (cdc_ecm_host->ux_host_class_cdc_ecm_receive_buffer) + rsc_cdc_mem_tx_rx_count ++; + if (cdc_ecm_host->ux_host_class_cdc_ecm_xmit_buffer) + rsc_cdc_mem_tx_rx_count ++; + /* Lock log base for tests. */ + ux_test_utility_sim_mem_alloc_log_lock(); + + stepinfo("enum mem: %ld\n", rsc_enum_mem_alloc_count); + stepinfo("cdc mem : %ld\n", rsc_cdc_mem_alloc_count); + stepinfo("mem free: %ld, %ld\n", _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); + + /* Simulate detach and attach for FS enumeration, + and check if there is memory error in normal enumeration. + */ + stepinfo(">>>>>>>>>>>>>>>>>>> Enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < 3; test_n++) + { + stepinfo("%4ld / 2\n", test_n); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on error. */ + ux_test_breakable_sleep(200, sleep_break_on_error); + + /* Check */ + if (cdc_ecm_host_from_system_change_function == UX_NULL) + { + + printf("ERROR #%d.%ld: Enumeration fail\n", __LINE__, test_n); + test_control_return(1); + } + } + + /* Simulate detach and attach for FS enumeration, + and test possible memory allocation error handlings. + */ + if (rsc_cdc_mem_alloc_count) stepinfo(">>>>>>>>>>>>>>>>>>> Memory errors enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_cdc_mem_alloc_count; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_cdc_mem_alloc_count - 1); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Set memory error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n + rsc_enum_mem_alloc_count); + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + if (test_n >= rsc_cdc_mem_alloc_count - rsc_cdc_mem_tx_rx_count) + { + + /* Wait and break on errors. */ + ux_test_breakable_sleep(200, sleep_break_on_error); + } + else + { + + /* Wait and break on errors. */ + ux_test_breakable_sleep(200, sleep_break_on_error); + + /* Check error */ + if (cdc_ecm_host_from_system_change_function != UX_NULL) + { + + printf("ERROR #%d.%ld: device detected when there is memory error\n", __LINE__, test_n); + test_control_return(1); + } + } + + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + } + ux_test_utility_sim_mem_alloc_error_generation_stop(); + if (rsc_cdc_mem_alloc_count) stepinfo("\n"); + + /* Test device deinit. */ + stepinfo(">>>>>>>>>>>>>>>>>>> Test class deinit\n"); + ux_test_disconnect_slave(); + ux_test_disconnect_host_wait_for_enum_completion(); + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_ecm_name, ux_device_class_cdc_ecm_entry); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_count_reset(); + ux_test_utility_sim_mutex_create_count_reset(); + ux_test_utility_sim_sem_create_count_reset(); + ux_test_utility_sim_sem_get_count_reset(); + + stepinfo(">>>>>>>>>>>>>>>>>>> Test class init\n"); + UX_TEST_CHECK_SUCCESS(ux_device_stack_class_register(_ux_system_slave_class_cdc_ecm_name, ux_device_class_cdc_ecm_entry, 1, 0, &cdc_ecm_parameter)); + + /* Log create counts for further tests. */ + rsc_cdc_mutex_usage = ux_test_utility_sim_mutex_create_count(); + rsc_cdc_sem_usage = ux_test_utility_sim_sem_create_count(); + rsc_cdc_mem_alloc_count = ux_test_utility_sim_mem_alloc_count(); + + /* Lock log base for tests. */ + ux_test_utility_sim_mem_alloc_log_lock(); + + if (rsc_cdc_mem_alloc_count) stepinfo(">>>>>>>>>>>>>>>>>>> Memory errors class init test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_cdc_mem_alloc_count; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_cdc_mem_alloc_count - 1); + + /* Deinit. */ + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_ecm_name, ux_device_class_cdc_ecm_entry); + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d.%ld: Memory level different after re-init %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Set memory error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n); + + /* Init. */ + + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_ecm_name, ux_device_class_cdc_ecm_entry, 1, 0, &cdc_ecm_parameter); + + /* Check error */ + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("ERROR #%d.%ld: code 0x%x\n", __LINE__, test_n, status); + test_control_return(1); + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + } + ux_test_utility_sim_mem_alloc_error_generation_stop(); + if (rsc_cdc_mem_alloc_count) stepinfo("\n"); + + stepinfo(">>>>>>>>>>>>>>>>>>> Test connect to avoid post post operation\n"); + /* Connect. */ + UX_TEST_CHECK_SUCCESS(ux_device_stack_class_register(_ux_system_slave_class_cdc_ecm_name, ux_device_class_cdc_ecm_entry, 1, 0, &cdc_ecm_parameter)); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + class_cdc_ecm_get_host(); + + stepinfo(">>>>>>>>>>>>>>>>>>> post_init_host done\n"); +} + +static void post_init_device() +{ + stepinfo(">>>>>>>>>>>>>>>>>>> post_init_device empty\n"); +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_basic_test.c b/test/regression/usbx_cdc_ecm_basic_test.c new file mode 100644 index 00000000..23030c82 --- /dev/null +++ b/test/regression/usbx_cdc_ecm_basic_test.c @@ -0,0 +1,56 @@ +/* Include necessary system files. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static UCHAR device_is_finished; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_basic_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC ECM Basic Functionality Test............................ "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static void post_init_host() +{ + + /* Running TCP test. */ + stepinfo("running TCP test.\n"); + cdc_ecm_basic_test(BASIC_TEST_HOST, BASIC_TEST_TCP); + + /* Running UDP test. */ + stepinfo("running UDP test.\n"); + cdc_ecm_basic_test(BASIC_TEST_HOST, BASIC_TEST_UDP); + + /* Wait for device to finish. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uchar(&device_is_finished, UX_TRUE)); + + /* Disconnect. */ + ux_test_disconnect_slave_and_host_wait_for_enum_completion(); + + /* Connect with null system change function. */ + _ux_system_host->ux_system_host_change_function = UX_NULL; + + /* Connect. */ + ux_test_connect_slave_and_host_wait_for_enum_completion(); + + /* We're done. */ +} + +static void post_init_device() +{ + + cdc_ecm_basic_test(BASIC_TEST_DEVICE, BASIC_TEST_TCP); + cdc_ecm_basic_test(BASIC_TEST_DEVICE, BASIC_TEST_UDP); + + device_is_finished = UX_TRUE; +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_control_interface_no_interrupt_endpoint_test.c b/test/regression/usbx_cdc_ecm_control_interface_no_interrupt_endpoint_test.c new file mode 100644 index 00000000..ef2d87fc --- /dev/null +++ b/test/regression/usbx_cdc_ecm_control_interface_no_interrupt_endpoint_test.c @@ -0,0 +1,170 @@ +/* This tests the case where there is no interrupt endpoint in the CDC-ECM control + interface. Host should not report an error since this endpoint is optional. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static unsigned char no_interrupt_endpoint_configuration_descriptor[] = { + + /* Device Descriptor */ + 0x12, /* bLength */ + 0x01, /* bDescriptorType */ + 0x10, 0x01, /* bcdUSB */ + 0xef, /* bDeviceClass - Depends on bDeviceSubClass */ + 0x02, /* bDeviceSubClass - Depends on bDeviceProtocol */ + 0x01, /* bDeviceProtocol - There's an IAD */ + 0x40, /* bMaxPacketSize0 */ + 0x70, 0x07, /* idVendor */ + 0x42, 0x10, /* idProduct */ + 0x00, 0x01, /* bcdDevice */ + 0x01, /* iManufacturer */ + 0x02, /* iProduct */ + 0x03, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ + + /* Configuration Descriptor */ + 0x09, /* bLength */ + 0x02, /* bDescriptorType */ + 0x5f, 0x00, /* wTotalLength */ + 0x02, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xc0, /* bmAttributes - Self-powered */ + 0x00, /* bMaxPower */ + + /* Interface Association Descriptor */ + 0x08, /* bLength */ + 0x0b, /* bDescriptorType */ + 0x00, /* bFirstInterface */ + 0x02, /* bInterfaceCount */ + 0x02, /* bFunctionClass - CDC - Communication */ + 0x06, /* bFunctionSubClass - ECM */ + 0x00, /* bFunctionProtocol - No class specific protocol required */ + 0x00, /* iFunction */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x02, /* bNumEndpoints */ + 0x02, /* bInterfaceClass - CDC - Communication */ + 0x06, /* bInterfaceSubClass - ECM */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* CDC Header Functional Descriptor */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x00, /* bDescriptorSubType */ + 0x10, 0x01, /* bcdCDC */ + + /* CDC ECM Functional Descriptor */ + 0x0d, /* bLength */ + 0x24, /* bDescriptorType */ + 0x0f, /* bDescriptorSubType */ + 0x04, /* iMACAddress */ + 0x00, 0x00, 0x00, 0x00, /* bmEthernetStatistics */ + 0xea, 0x05, /* wMaxSegmentSize */ + 0x00, 0x00, /* wNumberMCFilters */ + 0x00, /* bNumberPowerFilters */ + + /* CDC Union Functional Descriptor */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x06, /* bDescriptorSubType */ + 0x00, /* bmMasterInterface */ + 0x01, /* bmSlaveInterface0 */ + + /* ??? out (to hit non-in case) */ + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x01, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + + /* ??? in (to hit non-interrupt case) */ + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x82, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x01, /* bAlternateSetting */ + 0x02, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x03, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x84, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + +}; + +static DEVICE_INIT_DATA device_init_data = { + .framework = no_interrupt_endpoint_configuration_descriptor, + .framework_length = sizeof(no_interrupt_endpoint_configuration_descriptor), + .dont_register_hcd = 1, +}; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_control_interface_no_interrupt_endpoint_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC-ECM No Interrupt Endpoint Test.......................... "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize_use_framework(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ + + /* Enumerate. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + + /* The HCD init function put()s the HCD semaphore, so we can do this here. */ + ux_test_wait_for_enum_thread_completion(); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_data_iface_non_bulko_and_non_bulki_endpt_test.c b/test/regression/usbx_cdc_ecm_data_iface_non_bulko_and_non_bulki_endpt_test.c new file mode 100644 index 00000000..ac2cf237 --- /dev/null +++ b/test/regression/usbx_cdc_ecm_data_iface_non_bulko_and_non_bulki_endpt_test.c @@ -0,0 +1,177 @@ +/* This tests the following cases: + 1. There is an out endpoint, but not bulk. + 2. There is an in endpoint, but in bulk. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static unsigned char non_bulk_out_endpoint[] = { + + /* Device Descriptor */ + 0x12, /* bLength */ + 0x01, /* bDescriptorType */ + 0x10, 0x01, /* bcdUSB */ + 0xef, /* bDeviceClass - Depends on bDeviceSubClass */ + 0x02, /* bDeviceSubClass - Depends on bDeviceProtocol */ + 0x01, /* bDeviceProtocol - There's an IAD */ + 0x40, /* bMaxPacketSize0 */ + 0x70, 0x07, /* idVendor */ + 0x42, 0x10, /* idProduct */ + 0x00, 0x01, /* bcdDevice */ + 0x01, /* iManufacturer */ + 0x02, /* iProduct */ + 0x03, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ + + /* Configuration Descriptor */ + 0x09, /* bLength */ + 0x02, /* bDescriptorType */ + 0x66, 0x00, /* wTotalLength */ + 0x02, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xc0, /* bmAttributes - Self-powered */ + 0x00, /* bMaxPower */ + + /* Interface Association Descriptor */ + 0x08, /* bLength */ + 0x0b, /* bDescriptorType */ + 0x00, /* bFirstInterface */ + 0x02, /* bInterfaceCount */ + 0x02, /* bFunctionClass - CDC - Communication */ + 0x06, /* bFunctionSubClass - ECM */ + 0x00, /* bFunctionProtocol - No class specific protocol required */ + 0x00, /* iFunction */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x02, /* bInterfaceClass - CDC - Communication */ + 0x06, /* bInterfaceSubClass - ECM */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* CDC Header Functional Descriptor */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x00, /* bDescriptorSubType */ + 0x10, 0x01, /* bcdCDC */ + + /* CDC ECM Functional Descriptor */ + 0x0d, /* bLength */ + 0x24, /* bDescriptorType */ + 0x0f, /* bDescriptorSubType */ + 0x04, /* iMACAddress */ + 0x00, 0x00, 0x00, 0x00, /* bmEthernetStatistics */ + 0xea, 0x05, /* wMaxSegmentSize */ + 0x00, 0x00, /* wNumberMCFilters */ + 0x00, /* bNumberPowerFilters */ + + /* CDC Union Functional Descriptor */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x06, /* bDescriptorSubType */ + 0x00, /* bmMasterInterface */ + 0x01, /* bmSlaveInterface0 */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x81, /* bEndpointAddress */ + 0x03, /* bmAttributes - Interrupt */ + 0x08, 0x00, /* wMaxPacketSize */ + 0x08, /* bInterval */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x01, /* bAlternateSetting */ + 0x04, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x02, /* bEndpointAddress */ + 0x03, /* bmAttributes - Interrupt */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x01, /* bInterval */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x83, /* bEndpointAddress */ + 0x03, /* bmAttributes - Interrupt */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x01, /* bInterval */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x04, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x85, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + +}; + +static DEVICE_INIT_DATA device_init_data = { + .framework = non_bulk_out_endpoint, + .framework_length = sizeof(non_bulk_out_endpoint), + .dont_register_hcd = 1, +}; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_data_interface_non_bulk_out_and_non_bulk_in_endpoint_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC-ECM Non Bulk Out and Non Bulk In Endpoint Test.......... "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize_use_framework(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ + + /* Enumerate. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + + /* The HCD init function put()s the HCD semaphore, so we can do this here. */ + ux_test_wait_for_enum_thread_completion(); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_data_interface_no_bulk_in_endpoint_test.c b/test/regression/usbx_cdc_ecm_data_interface_no_bulk_in_endpoint_test.c new file mode 100644 index 00000000..94082fcd --- /dev/null +++ b/test/regression/usbx_cdc_ecm_data_interface_no_bulk_in_endpoint_test.c @@ -0,0 +1,177 @@ +/* This tests the case where there is no bulk in endpoint in the CDC-ECM data + interface. Host should report an error. + + Unfortunately, the device fails during activation if we use the 'no bulk-in + endpoint' descriptor, so we have the device use a correct descriptor, then + force the host to receive the invalid descriptor when it sends the GetDescriptor + request for the configuration descriptor. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static unsigned char no_bulk_in_endpoint_framework[] = { + + /* Configuration Descriptor */ + 0x09, /* bLength */ + 0x02, /* bDescriptorType */ + 0x58, 0x00, /* wTotalLength */ + 0x02, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xc0, /* bmAttributes - Self-powered */ + 0x00, /* bMaxPower */ + + /* Interface Association Descriptor */ + 0x08, /* bLength */ + 0x0b, /* bDescriptorType */ + 0x00, /* bFirstInterface */ + 0x02, /* bInterfaceCount */ + 0x02, /* bFunctionClass - CDC - Communication */ + 0x06, /* bFunctionSubClass - ECM */ + 0x00, /* bFunctionProtocol - No class specific protocol required */ + 0x00, /* iFunction */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x02, /* bInterfaceClass - CDC - Communication */ + 0x06, /* bInterfaceSubClass - ECM */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* CDC Header Functional Descriptor */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x00, /* bDescriptorSubType */ + 0x10, 0x01, /* bcdCDC */ + + /* CDC ECM Functional Descriptor */ + 0x0d, /* bLength */ + 0x24, /* bDescriptorType */ + 0x0f, /* bDescriptorSubType */ + 0x04, /* iMACAddress */ + 0x00, 0x00, 0x00, 0x00, /* bmEthernetStatistics */ + 0xea, 0x05, /* wMaxSegmentSize */ + 0x00, 0x00, /* wNumberMCFilters */ + 0x00, /* bNumberPowerFilters */ + + /* CDC Union Functional Descriptor */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x06, /* bDescriptorSubType */ + 0x00, /* bmMasterInterface */ + 0x01, /* bmSlaveInterface0 */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x83, /* bEndpointAddress */ + 0x03, /* bmAttributes - Interrupt */ + 0x08, 0x00, /* wMaxPacketSize */ + 0x08, /* bInterval */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x01, /* bAlternateSetting */ + 0x02, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* We use two bulk-out endpoints so that the lengths are the same (makes things easier). */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x02, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x01, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + +}; + +static DEVICE_INIT_DATA device_init_data = { + .framework = default_device_framework, + .framework_length = sizeof(default_device_framework), + .dont_register_hcd = 1, +}; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_data_interface_no_bulk_in_endpoint_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC-ECM No Bulk In Endpiont Test............................ "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize_use_framework(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ + +int i; + + /* We need to intercept the configuration descriptor. */ + UX_TEST_ACTION change_config_desc_action = {0}; + change_config_desc_action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + change_config_desc_action.function = UX_HCD_TRANSFER_REQUEST; + change_config_desc_action.req_action = UX_TEST_MATCH_REQ_LEN | UX_TEST_SIM_REQ_ANSWER; + change_config_desc_action.req_requested_len = 0x58; /* Length of config descriptor. */ + change_config_desc_action.req_data = no_bulk_in_endpoint_framework; + change_config_desc_action.req_actual_len = sizeof(no_bulk_in_endpoint_framework); + change_config_desc_action.req_status = UX_SUCCESS; + change_config_desc_action.do_after = 0; + change_config_desc_action.no_return = 0; + + /* We expect this to fail multiple times since enumeration tries multiple times. */ + for (i = 0; i < UX_RH_ENUMERATION_RETRY; i++) + { + ux_test_add_action_to_main_list(change_config_desc_action); + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_ENDPOINT_HANDLE_UNKNOWN)); + } + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE)); + + /* Enumerate. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + + /* The HCD init function put()s the HCD semaphore, so we can do this here. */ + ux_test_wait_for_enum_thread_completion(); + + /* Enumeration should've failed. */ + UX_TEST_ASSERT(ux_test_check_actions_empty()); + UX_TEST_ASSERT(cdc_ecm_host_from_system_change_function == UX_NULL); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_data_interface_no_bulk_out_endpoint_test.c b/test/regression/usbx_cdc_ecm_data_interface_no_bulk_out_endpoint_test.c new file mode 100644 index 00000000..62e44475 --- /dev/null +++ b/test/regression/usbx_cdc_ecm_data_interface_no_bulk_out_endpoint_test.c @@ -0,0 +1,177 @@ +/* This tests the case where there is no bulk out endpoint in the CDC-ECM data + interface. Host should report an error. + + Unfortunately, the device fails during activation if we use the 'no bulk-out + endpoint' descriptor, so we have the device use a correct descriptor, then + force the host to receive the invalid descriptor when it sends the GetDescriptor + request for the configuration descriptor. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static unsigned char no_bulk_out_endpoint_framework[] = { + + /* Configuration Descriptor */ + 0x09, /* bLength */ + 0x02, /* bDescriptorType */ + 0x58, 0x00, /* wTotalLength */ + 0x02, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xc0, /* bmAttributes - Self-powered */ + 0x00, /* bMaxPower */ + + /* Interface Association Descriptor */ + 0x08, /* bLength */ + 0x0b, /* bDescriptorType */ + 0x00, /* bFirstInterface */ + 0x02, /* bInterfaceCount */ + 0x02, /* bFunctionClass - CDC - Communication */ + 0x06, /* bFunctionSubClass - ECM */ + 0x00, /* bFunctionProtocol - No class specific protocol required */ + 0x00, /* iFunction */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x02, /* bInterfaceClass - CDC - Communication */ + 0x06, /* bInterfaceSubClass - ECM */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* CDC Header Functional Descriptor */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x00, /* bDescriptorSubType */ + 0x10, 0x01, /* bcdCDC */ + + /* CDC ECM Functional Descriptor */ + 0x0d, /* bLength */ + 0x24, /* bDescriptorType */ + 0x0f, /* bDescriptorSubType */ + 0x04, /* iMACAddress */ + 0x00, 0x00, 0x00, 0x00, /* bmEthernetStatistics */ + 0xea, 0x05, /* wMaxSegmentSize */ + 0x00, 0x00, /* wNumberMCFilters */ + 0x00, /* bNumberPowerFilters */ + + /* CDC Union Functional Descriptor */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x06, /* bDescriptorSubType */ + 0x00, /* bmMasterInterface */ + 0x01, /* bmSlaveInterface0 */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x83, /* bEndpointAddress */ + 0x03, /* bmAttributes - Interrupt */ + 0x08, 0x00, /* wMaxPacketSize */ + 0x08, /* bInterval */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x01, /* bAlternateSetting */ + 0x02, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* We use two bulk-in endpoints so that the lengths are the same (makes things easier). */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x82, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x81, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + +}; + +static DEVICE_INIT_DATA device_init_data = { + .framework = default_device_framework, + .framework_length = sizeof(default_device_framework), + .dont_register_hcd = 1, +}; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_data_interface_no_bulk_out_endpoint_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC-ECM No Bulk Out Endpoint Test........................... "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize_use_framework(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ + +int i; + + /* We need to intercept the configuration descriptor. */ + UX_TEST_ACTION change_config_desc_action = {0}; + change_config_desc_action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + change_config_desc_action.function = UX_HCD_TRANSFER_REQUEST; + change_config_desc_action.req_action = UX_TEST_MATCH_REQ_LEN | UX_TEST_SIM_REQ_ANSWER; + change_config_desc_action.req_requested_len = 0x58; /* Length of config descriptor. */ + change_config_desc_action.req_data = no_bulk_out_endpoint_framework; + change_config_desc_action.req_actual_len = sizeof(no_bulk_out_endpoint_framework); + change_config_desc_action.req_status = UX_SUCCESS; + change_config_desc_action.do_after = 0; + change_config_desc_action.no_return = 0; + + /* We expect this to fail multiple times since enumeration tries multiple times. */ + for (i = 0; i < UX_RH_ENUMERATION_RETRY; i++) + { + ux_test_add_action_to_main_list(change_config_desc_action); + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_ENDPOINT_HANDLE_UNKNOWN)); + } + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE)); + + /* Enumerate. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + + /* The HCD init function put()s the HCD semaphore, so we can do this here. */ + ux_test_wait_for_enum_thread_completion(); + + /* Enumeration should've failed. */ + UX_TEST_ASSERT(ux_test_check_actions_empty()); + UX_TEST_ASSERT(cdc_ecm_host_from_system_change_function == UX_NULL); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_data_interface_setting_select_fails_test.c b/test/regression/usbx_cdc_ecm_data_interface_setting_select_fails_test.c new file mode 100644 index 00000000..7821bb2a --- /dev/null +++ b/test/regression/usbx_cdc_ecm_data_interface_setting_select_fails_test.c @@ -0,0 +1,76 @@ +/* This tests the case where the setting the data interface with endpoints fails. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static DEVICE_INIT_DATA device_init_data = { + .framework = default_device_framework, + .framework_length = sizeof(default_device_framework), + .dont_register_hcd = 1, +}; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_data_interface_setting_select_fails_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Data Interface Setting Select Fails Test.................... "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize_use_framework(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ + +int i; + +#if 0 + /* Create a transfer_request for the SET_INTERFACE request. No data for this request */ + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_SET_INTERFACE; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_index = (USHORT) interface -> ux_interface_descriptor.bInterfaceNumber; + transfer_request -> ux_transfer_request_value = (USHORT) interface -> ux_interface_descriptor.bAlternateSetting; +#endif + + UX_TEST_SETUP alternate_setting_set_setup; + alternate_setting_set_setup.ux_test_setup_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_INTERFACE; + alternate_setting_set_setup.ux_test_setup_request = UX_SET_INTERFACE; + alternate_setting_set_setup.ux_test_setup_value = 1; /* Alternate Setting */ + alternate_setting_set_setup.ux_test_setup_index = 1; /* Interface (data is 1) */ + + /* We need to intercept the configuration descriptor. */ + UX_TEST_ACTION alternate_setting_fail_action = {0}; + alternate_setting_fail_action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + alternate_setting_fail_action.function = UX_HCD_TRANSFER_REQUEST; + alternate_setting_fail_action.req_action = UX_TEST_SETUP_MATCH_REQUEST; + alternate_setting_fail_action.req_setup = &alternate_setting_set_setup; + alternate_setting_fail_action.status = UX_ERROR; + alternate_setting_fail_action.no_return = 0; + + /* We expect this to fail multiple times since enumeration tries multiple times. */ + for (i = 0; i < UX_RH_ENUMERATION_RETRY; i++) + { + ux_test_add_action_to_main_list(alternate_setting_fail_action); + } + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE)); + + /* Enumerate. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + + /* The HCD init function put()s the HCD semaphore, so we can do this here. */ + ux_test_wait_for_enum_thread_completion(); + + /* Enumeration should've failed. */ + UX_TEST_ASSERT(ux_test_check_actions_empty()); + UX_TEST_ASSERT(cdc_ecm_host_from_system_change_function == UX_NULL); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_default_data_interface_setting_with_endpoints_test.c b/test/regression/usbx_cdc_ecm_default_data_interface_setting_with_endpoints_test.c new file mode 100644 index 00000000..2c2edea1 --- /dev/null +++ b/test/regression/usbx_cdc_ecm_default_data_interface_setting_with_endpoints_test.c @@ -0,0 +1,149 @@ +/* This tests the case where the default data interface has endpoints - note that + this is a violation of the specification since according to it, the default + data interface should have 0 endpoints, however, our host supports it since + so many devices violate the spec! */ + +#include "usbx_ux_test_cdc_ecm.h" + +static unsigned char device_framework_high_speed_default_data_interface_with_endpoints[] = { + + /* Device Descriptor */ + 0x12, /* bLength */ + 0x01, /* bDescriptorType */ + 0x10, 0x01, /* bcdUSB */ + 0xef, /* bDeviceClass - Depends on bDeviceSubClass */ + 0x02, /* bDeviceSubClass - Depends on bDeviceProtocol */ + 0x01, /* bDeviceProtocol - There's an IAD */ + 0x40, /* bMaxPacketSize0 */ + 0x70, 0x07, /* idVendor */ + 0x42, 0x10, /* idProduct */ + 0x00, 0x01, /* bcdDevice */ + 0x01, /* iManufacturer */ + 0x02, /* iProduct */ + 0x03, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ + + /* Configuration Descriptor */ + 0x09, /* bLength */ + 0x02, /* bDescriptorType */ + 0x4f, 0x00, /* wTotalLength */ + 0x02, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xc0, /* bmAttributes - Self-powered */ + 0x00, /* bMaxPower */ + + /* Interface Association Descriptor */ + 0x08, /* bLength */ + 0x0b, /* bDescriptorType */ + 0x00, /* bFirstInterface */ + 0x02, /* bInterfaceCount */ + 0x02, /* bFunctionClass - CDC - Communication */ + 0x06, /* bFunctionSubClass - ECM */ + 0x00, /* bFunctionProtocol - No class specific protocol required */ + 0x00, /* iFunction */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x02, /* bInterfaceClass - CDC - Communication */ + 0x06, /* bInterfaceSubClass - ECM */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* CDC Header Functional Descriptor */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x00, /* bDescriptorSubType */ + 0x10, 0x01, /* bcdCDC */ + + /* CDC ECM Functional Descriptor */ + 0x0d, /* bLength */ + 0x24, /* bDescriptorType */ + 0x0f, /* bDescriptorSubType */ + 0x04, /* iMACAddress */ + 0x00, 0x00, 0x00, 0x00, /* bmEthernetStatistics */ + 0xea, 0x05, /* wMaxSegmentSize */ + 0x00, 0x00, /* wNumberMCFilters */ + 0x00, /* bNumberPowerFilters */ + + /* CDC Union Functional Descriptor */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x06, /* bDescriptorSubType */ + 0x00, /* bmMasterInterface */ + 0x01, /* bmSlaveInterface0 */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x83, /* bEndpointAddress */ + 0x03, /* bmAttributes - Interrupt */ + 0x08, 0x00, /* wMaxPacketSize */ + 0x08, /* bInterval */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x02, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x02, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x81, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + +}; + +static DEVICE_INIT_DATA device_init_data = { + .framework = device_framework_high_speed_default_data_interface_with_endpoints, + .framework_length = sizeof(device_framework_high_speed_default_data_interface_with_endpoints), + .dont_register_hcd = 0, +}; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_default_data_interface_with_endpoints_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC-ECM default data interface with endpoints Test.......... "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize_use_framework(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ + + cdc_ecm_basic_test(BASIC_TEST_HOST, BASIC_TEST_TCP); +} + +static void post_init_device() +{ + + cdc_ecm_basic_test(BASIC_TEST_DEVICE, BASIC_TEST_TCP); +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_disconnect_and_reconnect_test.c b/test/regression/usbx_cdc_ecm_disconnect_and_reconnect_test.c new file mode 100644 index 00000000..6ef3088b --- /dev/null +++ b/test/regression/usbx_cdc_ecm_disconnect_and_reconnect_test.c @@ -0,0 +1,53 @@ +/* This test ensures everything works after a disconnection and reconnection. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static UCHAR host_ready_for_test_after_reconnection; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_disconnect_and_reconnect_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC-ECM Disconnect And Reconnect Test....................... "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static void post_init_host() +{ + + cdc_ecm_basic_test(BASIC_TEST_HOST, BASIC_TEST_TCP); + + /* Now disconnect. */ + ux_test_disconnect_host_wait_for_enum_completion(); + + /* Now reconnect. */ + ux_test_connect_host_wait_for_enum_completion(); + + /* Get class instance. */ + class_cdc_ecm_get_host(); + + /* Tell device we're ready. */ + host_ready_for_test_after_reconnection = 1; + + /* Now run the basic test again. */ + cdc_ecm_basic_test(BASIC_TEST_HOST, BASIC_TEST_TCP); +} + +static void post_init_device() +{ + + cdc_ecm_basic_test(BASIC_TEST_DEVICE, BASIC_TEST_TCP); + + /* Now wait for the host to tell us to run the test again. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uchar(&host_ready_for_test_after_reconnection, 1)); + + cdc_ecm_basic_test(BASIC_TEST_DEVICE, BASIC_TEST_TCP); +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_host_bulk_in_semaphore_create_fail_test.c b/test/regression/usbx_cdc_ecm_host_bulk_in_semaphore_create_fail_test.c new file mode 100644 index 00000000..e5f2ff60 --- /dev/null +++ b/test/regression/usbx_cdc_ecm_host_bulk_in_semaphore_create_fail_test.c @@ -0,0 +1,58 @@ +/* This tests the case where the bulk in semaphore at the class level creation + fails. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static DEVICE_INIT_DATA device_init_data = { + .framework = default_device_framework, + .framework_length = sizeof(default_device_framework), + .dont_register_hcd = 1, +}; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_host_bulk_in_semaphore_create_fail_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC-ECM Host Bulk In Semaphore Create Fail Test............. "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize_use_framework(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ + +int i; + + UX_TEST_ACTION semaphore_create_fail_action = {0}; + semaphore_create_fail_action.usbx_function = UX_TEST_OVERRIDE_TX_SEMAPHORE_CREATE; + semaphore_create_fail_action.semaphore_name = "host CDC-ECM bulk in wait semaphore"; + semaphore_create_fail_action.no_return = 0; + semaphore_create_fail_action.status = UX_ERROR; + + for (i = 0; i < UX_RH_ENUMERATION_RETRY; i++) + { + ux_test_add_action_to_main_list(semaphore_create_fail_action); + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_UTILITY, UX_ERROR)); + } + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE)); + + /* Enumerate. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + + /* The HCD init function put()s the HCD semaphore, so we can do this here. */ + ux_test_wait_for_enum_thread_completion(); + + UX_TEST_ASSERT(ux_test_check_actions_empty()); + UX_TEST_ASSERT(cdc_ecm_host_from_system_change_function == UX_NULL); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_host_bulk_in_transfer_arming_during_deactivate_test.c b/test/regression/usbx_cdc_ecm_host_bulk_in_transfer_arming_during_deactivate_test.c new file mode 100644 index 00000000..43bfb79b --- /dev/null +++ b/test/regression/usbx_cdc_ecm_host_bulk_in_transfer_arming_during_deactivate_test.c @@ -0,0 +1,80 @@ +/* This tests the case where there is an ongoing transfer on the bulk in endpoint + during deactivation. The deactivate routine should wait for it to finish. + + We do this by having the CDC-ECM thread suspend during the transfer arm, + and then begin deactivation. We resume the CDC-ECM thread later! */ + +#include "usbx_ux_test_cdc_ecm.h" + +static UCHAR cdc_ecm_thread_suspended; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_host_bulk_in_transfer_arming_during_deactivate_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC-ECM Host Bulk In Transfer Arming During... Test......... "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static VOID suspend_cdc_ecm_thread_action_func(UX_TEST_ACTION *action, VOID *params) +{ + + /* The CDC-ECM thread is calling us. */ + + /* Notify test thread. */ + cdc_ecm_thread_suspended = 1; + + /* Suspend. Test thread should wake us back up. */ + tx_thread_suspend(tx_thread_identify()); +} + +static void post_init_host() +{ + + /* Right now, host CDC-ECM thread is waiting for a bulk in transfer. We + need for it to re-do a transfer so that we can get it to suspend via our + action. First, we need to create and add our actions. */ + UX_TEST_ACTION bulk_in_transfer_suspend_action = {0}; + bulk_in_transfer_suspend_action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + bulk_in_transfer_suspend_action.function = UX_HCD_TRANSFER_REQUEST; + bulk_in_transfer_suspend_action.req_action = UX_TEST_MATCH_EP; + bulk_in_transfer_suspend_action.req_ep_address = 0x81; + bulk_in_transfer_suspend_action.action_func = suspend_cdc_ecm_thread_action_func; + bulk_in_transfer_suspend_action.no_return = 1; + ux_test_add_action_to_main_list(bulk_in_transfer_suspend_action); + + /* Now have the CDC-ECM thread re-do the transfer. */ + write_packet_tcp(&tcp_socket_device, &packet_pool_device, 1, "device"); + + /* Wait for CDC-ECM thread to stall. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uchar(&cdc_ecm_thread_suspended, 1)); + + /* Just for the hell of it, null out the system change function so we can hit that case too. */ + _ux_system_host->ux_system_host_change_function = UX_NULL; + + /* Now disconnect the host. */ + ux_test_disconnect_host_no_wait(); + + /* Now wait for deactivation to suspend, waiting for bulk in to finish. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uchar(&cdc_ecm_host -> ux_host_class_cdc_ecm_bulk_in_transfer_waiting_for_check_and_arm_to_finish, UX_TRUE)); + + /* Now resume the CDC-ECM thread. */ + tx_thread_resume(&cdc_ecm_host->ux_host_class_cdc_ecm_thread); + + /* And now wait for deactivation to complete. */ + ux_test_wait_for_enum_thread_completion(); + + /* And now wait for... wait a second, we're done! Smiley face! That was easier than I thought! I'M SO FRICKEN HAPPY RIGHT NOWWWWWW! */ +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_host_bulk_in_transfer_arming_during_link_down_test.c b/test/regression/usbx_cdc_ecm_host_bulk_in_transfer_arming_during_link_down_test.c new file mode 100644 index 00000000..a74824c1 --- /dev/null +++ b/test/regression/usbx_cdc_ecm_host_bulk_in_transfer_arming_during_link_down_test.c @@ -0,0 +1,80 @@ +/* This tests the case where there is an ongoing transfer on the bulk in endpoint + during link down. The interrupt notification function should wait for it to finish. + + We do this by having the CDC-ECM thread suspend during the transfer arm, + and then begin link down event. We resume the HCD thread later! */ + +#include "usbx_ux_test_cdc_ecm.h" + +static UCHAR cdc_ecm_thread_suspended; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_host_bulk_in_transfer_arming_during_link_down_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC-ECM Host Bulk In Transfer Arming During... Test......... "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static VOID suspend_cdc_ecm_thread_action_func(UX_TEST_ACTION *action, VOID *params) +{ + + /* The CDC-ECM thread is calling us. */ + + /* Notify test thread. */ + cdc_ecm_thread_suspended = 1; + + /* Suspend. Test thread should wake us back up. */ + tx_thread_suspend(tx_thread_identify()); +} + +static void post_init_host() +{ + + /* Right now, host CDC-ECM thread is waiting for a bulk in transfer. We + need for it to re-do a transfer so that we can get it to suspend via our + action. First, we need to create and add our actions. */ + UX_TEST_ACTION bulk_in_transfer_suspend_action = {0}; + bulk_in_transfer_suspend_action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + bulk_in_transfer_suspend_action.function = UX_HCD_TRANSFER_REQUEST; + bulk_in_transfer_suspend_action.req_action = UX_TEST_MATCH_EP; + bulk_in_transfer_suspend_action.req_ep_address = 0x81; + bulk_in_transfer_suspend_action.action_func = suspend_cdc_ecm_thread_action_func; + bulk_in_transfer_suspend_action.no_return = 1; + ux_test_add_action_to_main_list(bulk_in_transfer_suspend_action); + + /* Now have the CDC-ECM thread re-do the transfer. */ + write_packet_tcp(&tcp_socket_device, &packet_pool_device, 1, "device"); + + /* Wait for CDC-ECM thread to stall. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uchar(&cdc_ecm_thread_suspended, 1)); + + /* Just for the hell of it, null out the system change function so we can hit that case too. */ + _ux_system_host->ux_system_host_change_function = UX_NULL; + + /* Now change the link to down. */ + ux_test_device_class_cdc_ecm_set_link_state(cdc_ecm_device, 0); + + /* Now wait for interrupt notification function (AKA hcd thread) to suspend, waiting for bulk in to finish. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uchar(&cdc_ecm_host -> ux_host_class_cdc_ecm_bulk_in_transfer_waiting_for_check_and_arm_to_finish, UX_TRUE)); + + /* Now resume the CDC-ECM thread. */ + tx_thread_resume(&cdc_ecm_host->ux_host_class_cdc_ecm_thread); + + /* And now wait for CDC-ECM instance to go down. */ + ux_test_wait_for_value_ulong(&cdc_ecm_host->ux_host_class_cdc_ecm_link_state, 0); + + /* And now wait for... wait a second, we're done! Smiley face! That was easier than I thought! I'M SO FRICKEN HAPPY RIGHT NOWWWWWW! */ +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_host_bulk_in_transfer_fail_test.c b/test/regression/usbx_cdc_ecm_host_bulk_in_transfer_fail_test.c new file mode 100644 index 00000000..ec99cf0f --- /dev/null +++ b/test/regression/usbx_cdc_ecm_host_bulk_in_transfer_fail_test.c @@ -0,0 +1,65 @@ +/* This tests the case where the bulk in transfer fails (in the cdc-ecm thread). */ + +#include "usbx_ux_test_cdc_ecm.h" + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_host_bulk_in_transfer_fail_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC-ECM Host Bulk In Transfer Fail Test..................... "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static UCHAR is_cdc_ecm_thread_suspended; + +static VOID suspend_cdc_ecm_thread_action_func(UX_TEST_ACTION *action, VOID *params) +{ + + is_cdc_ecm_thread_suspended = 1; + + /* We're being called by nx_packet_allocate in cdc-ecm thread. Wait for test + thread to resume us. */ + tx_thread_suspend(tx_thread_identify()); +} + +static void post_init_host() +{ + + /* Currently, the cdc-ecm thread should be waiting for a transfer to complete. + We need to create an action for having the bulk in transfer fail, add + the action, then send data to host so the cdc-ecm thread will re-arm the + transfer (which should fail). */ + + /* Create the action for having bulk in transfer fail. */ + UX_TEST_ACTION bulk_transfer_fail_action = {0}; + bulk_transfer_fail_action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + bulk_transfer_fail_action.function = UX_HCD_TRANSFER_REQUEST; + bulk_transfer_fail_action.req_action = UX_TEST_MATCH_EP; + bulk_transfer_fail_action.req_ep_address = 0x81; + bulk_transfer_fail_action.no_return = 0; + bulk_transfer_fail_action.status = UX_ERROR; + ux_test_add_action_to_main_list(bulk_transfer_fail_action); + + /* Write to the host so the cdc-ecm thread will redo the bulk in transfer. */ + write_packet_udp(&udp_socket_device, &packet_pool_device, HOST_IP_ADDRESS, HOST_SOCKET_PORT_UDP, 0, "device"); + + /* Wait for the arm and fail. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_empty_actions()); + + /* Wait for the host to re-arm and wait for the transfer. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uint(&cdc_ecm_host->ux_host_class_cdc_ecm_bulk_in_endpoint->ux_endpoint_transfer_request.ux_transfer_request_semaphore.tx_semaphore_suspended_count, 1)); + + /* Now we're done. */ +} + +static void post_init_device() +{ +} diff --git a/test/regression/usbx_cdc_ecm_host_bulk_out_semaphore_create_fail_test.c b/test/regression/usbx_cdc_ecm_host_bulk_out_semaphore_create_fail_test.c new file mode 100644 index 00000000..f3797455 --- /dev/null +++ b/test/regression/usbx_cdc_ecm_host_bulk_out_semaphore_create_fail_test.c @@ -0,0 +1,58 @@ +/* This tests the case where the bulk out semaphore at the class level creation + fails. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static DEVICE_INIT_DATA device_init_data = { + .framework = default_device_framework, + .framework_length = sizeof(default_device_framework), + .dont_register_hcd = 1, +}; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_host_bulk_out_semaphore_create_fail_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC-ECM Host Bulk Out Semaphore Create Fail Test............ "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize_use_framework(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ + +int i; + + UX_TEST_ACTION semaphore_create_fail_action = {0}; + semaphore_create_fail_action.usbx_function = UX_TEST_OVERRIDE_TX_SEMAPHORE_CREATE; + semaphore_create_fail_action.semaphore_name = "host CDC-ECM bulk out wait semaphore"; + semaphore_create_fail_action.no_return = 0; + semaphore_create_fail_action.status = UX_ERROR; + + for (i = 0; i < UX_RH_ENUMERATION_RETRY; i++) + { + ux_test_add_action_to_main_list(semaphore_create_fail_action); + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_UTILITY, UX_ERROR)); + } + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE)); + + /* Enumerate. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + + /* The HCD init function put()s the HCD semaphore, so we can do this here. */ + ux_test_wait_for_enum_thread_completion(); + + UX_TEST_ASSERT(ux_test_check_actions_empty()); + UX_TEST_ASSERT(cdc_ecm_host_from_system_change_function == UX_NULL); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_host_bulk_out_transfer_fail_test.c b/test/regression/usbx_cdc_ecm_host_bulk_out_transfer_fail_test.c new file mode 100644 index 00000000..f66e5470 --- /dev/null +++ b/test/regression/usbx_cdc_ecm_host_bulk_out_transfer_fail_test.c @@ -0,0 +1,45 @@ +/* This tests the case where the bulk out transfer fails (in the cdc_ecm_write). */ + +#include "usbx_ux_test_cdc_ecm.h" + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_host_bulk_out_transfer_fail_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC-ECM Host Bulk Out Transfer Fail Test.................... "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static void post_init_host() +{ + + /* Create the action for having bulk in transfer fail. */ + UX_TEST_ACTION bulk_transfer_fail_action = {0}; + bulk_transfer_fail_action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + bulk_transfer_fail_action.function = UX_HCD_TRANSFER_REQUEST; + bulk_transfer_fail_action.req_action = UX_TEST_MATCH_EP; + bulk_transfer_fail_action.req_ep_address = 0x02; + bulk_transfer_fail_action.no_return = 0; + bulk_transfer_fail_action.status = UX_ERROR; + ux_test_add_action_to_main_list(bulk_transfer_fail_action); + + /* Now send a packet so write function will run. */ + write_packet_tcp(&tcp_socket_host, &packet_pool_host, 0, "host"); + + /* Ensure write failed. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_empty_actions()); + + /* Now we're done. */ +} + +static void post_init_device() +{ +} diff --git a/test/regression/usbx_cdc_ecm_host_bulki_arm_err_dueto_link_dn_thread_wait_test.c b/test/regression/usbx_cdc_ecm_host_bulki_arm_err_dueto_link_dn_thread_wait_test.c new file mode 100644 index 00000000..84b15c63 --- /dev/null +++ b/test/regression/usbx_cdc_ecm_host_bulki_arm_err_dueto_link_dn_thread_wait_test.c @@ -0,0 +1,83 @@ +/* This tests the case where the link is down and a thread is waiting for the + bulk in transfer check-and-arm to finish. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static UCHAR cdc_ecm_thread_suspended; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_host_bulk_in_transfer_arming_fails_due_to_link_down_and_thread_waiting_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC-ECM Host Bulk In Transfer Arming During... Test......... "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static VOID suspend_cdc_ecm_thread_action_func(UX_TEST_ACTION *action, VOID *params) +{ + + /* The CDC-ECM thread is calling us. */ + + /* Notify test thread. */ + cdc_ecm_thread_suspended = 1; + + /* Suspend. Test thread should wake us back up. */ + tx_thread_suspend(tx_thread_identify()); +} + +VOID cdc_ecm_thread_suspend_action_func(UX_TEST_ACTION *action, VOID *params) +{ + cdc_ecm_thread_suspended = 1; + tx_thread_suspend(tx_thread_identify()); +} + +static void post_init_host() +{ + + /* Right now, host CDC-ECM thread is waiting for a bulk in transfer. We + need for it to re-do a transfer so that we can get it to suspend via our + action. First, we need to create and add our actions. */ + UX_TEST_ACTION bulk_in_transfer_suspend_action = {0}; + bulk_in_transfer_suspend_action.usbx_function = UX_TEST_OVERRIDE_NX_PACKET_ALLOCATE; + bulk_in_transfer_suspend_action.name_ptr = ip_pool_host_name; + bulk_in_transfer_suspend_action.action_func = cdc_ecm_thread_suspend_action_func; + ux_test_add_action_to_main_list(bulk_in_transfer_suspend_action); + + /* Send data so thread does packet allocate. */ + write_packet_udp(&udp_socket_device, &packet_pool_device, HOST_IP_ADDRESS, HOST_SOCKET_PORT_UDP, 0, "device"); + + /* Wait for the thread to be suspended. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uchar(&cdc_ecm_thread_suspended, 1)); + + /* Set link state to down. */ + ux_test_device_class_cdc_ecm_set_link_state(cdc_ecm_device, 0); + + /* Now wait for the link to be set to pending down (it won't be down since thread is suspended). */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_ulong(&cdc_ecm_host->ux_host_class_cdc_ecm_link_state, UX_HOST_CLASS_CDC_ECM_LINK_STATE_PENDING_DOWN)); + + /* Make CDC-ECM thread think a thread is indeed waiting. */ + cdc_ecm_host->ux_host_class_cdc_ecm_bulk_in_transfer_waiting_for_check_and_arm_to_finish = UX_TRUE; + + /* Now resume CDC-ECM thread. */ + tx_thread_resume(&cdc_ecm_host->ux_host_class_cdc_ecm_thread); + + /* Now wait for the semaphore to be put. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_ulong(&cdc_ecm_host->ux_host_class_cdc_ecm_bulk_in_transfer_waiting_for_check_and_arm_to_finish_semaphore.tx_semaphore_count, 1)); + + /* Now get the semaphore so the count is okay. */ + tx_semaphore_get(&cdc_ecm_host->ux_host_class_cdc_ecm_bulk_in_transfer_waiting_for_check_and_arm_to_finish_semaphore, TX_WAIT_FOREVER); + + /* And now we're done. */ +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_host_bulko_transfer_arming_during_link_dn_test.c b/test/regression/usbx_cdc_ecm_host_bulko_transfer_arming_during_link_dn_test.c new file mode 100644 index 00000000..9d80ff7c --- /dev/null +++ b/test/regression/usbx_cdc_ecm_host_bulko_transfer_arming_during_link_dn_test.c @@ -0,0 +1,89 @@ +/* This tests the case where there is an ongoing transfer on the bulk out endpoint + during link down. The interrupt notification function should wait for it to finish. + + We do this by having the CDC-ECM thread suspend during the transfer arm, + and then begin link down event. We resume the HCD thread later! */ + +#include "usbx_ux_test_cdc_ecm.h" + +static UCHAR write_thread_suspended; +static TX_THREAD write_thread; +static UCHAR write_thread_stack[2048]; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_host_bulk_out_transfer_arming_during_link_down_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC-ECM Host Bulk Out Transfer Arming During... Test........ "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static VOID suspend_write_thread_action_func(UX_TEST_ACTION *action, VOID *params) +{ + + /* The write thread is calling us. */ + + /* Notify test thread. */ + write_thread_suspended = 1; + + /* Suspend. Test thread should wake us back up. */ + tx_thread_suspend(tx_thread_identify()); +} + +static void write_thread_entry(ULONG input) +{ + + /* Do the write. */ + write_packet_tcp(&tcp_socket_host, &packet_pool_host, 0, "host"); +} + +static void post_init_host() +{ + + /* Create the thread that will do the write. */ + UX_TEST_CHECK_SUCCESS(tx_thread_create(&write_thread, "write thread", write_thread_entry, 0, write_thread_stack, sizeof(write_thread_stack), 20, 20, 0, TX_DONT_START)); + + /* Right now, host CDC-ECM thread is waiting for a bulk out transfer. We + need for it to re-do a transfer so that we can get it to suspend via our + action. First, we need to create and add our actions. */ + UX_TEST_ACTION bulk_out_transfer_suspend_action = {0}; + bulk_out_transfer_suspend_action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + bulk_out_transfer_suspend_action.function = UX_HCD_TRANSFER_REQUEST; + bulk_out_transfer_suspend_action.req_action = UX_TEST_MATCH_EP; + bulk_out_transfer_suspend_action.req_ep_address = 0x02; + bulk_out_transfer_suspend_action.action_func = suspend_write_thread_action_func; + bulk_out_transfer_suspend_action.no_return = 1; + ux_test_add_action_to_main_list(bulk_out_transfer_suspend_action); + + /* Now start the write thread. */ + tx_thread_resume(&write_thread); + + /* Now wait for it to be suspended. */ + ux_test_wait_for_value_uchar(&write_thread_suspended, 1); + + /* Now change the link to down. */ + ux_test_device_class_cdc_ecm_set_link_state(cdc_ecm_device, 0); + + /* Now wait for CDC-ECM thread to suspend, waiting for bulk out to finish. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uchar(&cdc_ecm_host -> ux_host_class_cdc_ecm_bulk_out_transfer_waiting_for_check_and_arm_to_finish, UX_TRUE)); + + /* Now resume the write thread. */ + tx_thread_resume(&write_thread); + + /* And now wait for write instance to go down. */ + ux_test_wait_for_value_ulong(&cdc_ecm_host->ux_host_class_cdc_ecm_link_state, 0); + + /* And now wait for... wait a second, we're done! Smiley face! That was easier than I thought! I'M SO FRICKEN HAPPY RIGHT NOWWWWWW! */ +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_host_first_interrupt_transfer_fail_test.c b/test/regression/usbx_cdc_ecm_host_first_interrupt_transfer_fail_test.c new file mode 100644 index 00000000..f540bae2 --- /dev/null +++ b/test/regression/usbx_cdc_ecm_host_first_interrupt_transfer_fail_test.c @@ -0,0 +1,58 @@ +/* This tests the case where the CDC-ECM thread creation fails. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static DEVICE_INIT_DATA device_init_data = { + .framework = default_device_framework, + .framework_length = sizeof(default_device_framework), + .dont_register_hcd = 1, +}; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_host_first_interrupt_transfer_fail_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC-ECM Host First Interrupt Transfer Fail Test............. "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize_use_framework(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ + +int i; + + UX_TEST_ACTION force_interrupt_transfer_fail_action = {0}; + force_interrupt_transfer_fail_action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + force_interrupt_transfer_fail_action.function = UX_HCD_TRANSFER_REQUEST; + force_interrupt_transfer_fail_action.req_action = UX_TEST_MATCH_EP; + force_interrupt_transfer_fail_action.req_ep_address = 0x83; + force_interrupt_transfer_fail_action.no_return = 0; + force_interrupt_transfer_fail_action.status = UX_ERROR; + + for (i = 0; i < UX_RH_ENUMERATION_RETRY; i++) + { + ux_test_add_action_to_main_list(force_interrupt_transfer_fail_action); + } + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE)); + + /* Enumerate. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + + /* The HCD init function put()s the HCD semaphore, so we can do this here. */ + ux_test_wait_for_enum_thread_completion(); + + UX_TEST_ASSERT(ux_test_check_actions_empty()); + UX_TEST_ASSERT(cdc_ecm_host_from_system_change_function == UX_NULL); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_host_int_notification_semaphore_create_fail_test.c b/test/regression/usbx_cdc_ecm_host_int_notification_semaphore_create_fail_test.c new file mode 100644 index 00000000..38db9a60 --- /dev/null +++ b/test/regression/usbx_cdc_ecm_host_int_notification_semaphore_create_fail_test.c @@ -0,0 +1,57 @@ +/* This tests the case where the interrupt notification semaphore creation fails. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static DEVICE_INIT_DATA device_init_data = { + .framework = default_device_framework, + .framework_length = sizeof(default_device_framework), + .dont_register_hcd = 1, +}; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_host_interrupt_notification_semaphore_create_fail_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC-ECM Host Interrupt Notification Semaphore Fail Test..... "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize_use_framework(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ + +int i; + + UX_TEST_ACTION semaphore_create_fail_action = {0}; + semaphore_create_fail_action.usbx_function = UX_TEST_OVERRIDE_TX_SEMAPHORE_CREATE; + semaphore_create_fail_action.semaphore_name = "host CDC-ECM interrupt notification semaphore"; + semaphore_create_fail_action.no_return = 0; + semaphore_create_fail_action.status = UX_ERROR; + + for (i = 0; i < UX_RH_ENUMERATION_RETRY; i++) + { + ux_test_add_action_to_main_list(semaphore_create_fail_action); + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_UTILITY, UX_ERROR)); + } + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE)); + + /* Enumerate. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + + /* The HCD init function put()s the HCD semaphore, so we can do this here. */ + ux_test_wait_for_enum_thread_completion(); + + UX_TEST_ASSERT(ux_test_check_actions_empty()); + UX_TEST_ASSERT(cdc_ecm_host_from_system_change_function == UX_NULL); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_host_non_ip_packet_received_test.c b/test/regression/usbx_cdc_ecm_host_non_ip_packet_received_test.c new file mode 100644 index 00000000..9f665c9d --- /dev/null +++ b/test/regression/usbx_cdc_ecm_host_non_ip_packet_received_test.c @@ -0,0 +1,63 @@ +/* This tests the case where the host receives a non-IP packet. */ + +#include "usbx_ux_test_cdc_ecm.h" + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_host_non_ip_packet_received_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC-ECM Host Non IP Packet Received Test.................... "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static void post_init_host() +{ + +NX_PACKET *out_packet; + + /* Note that the packets we send to the host will just get released by NetX + for being invalid. */ + + /** Test '*(packet -> nx_packet_prepend_ptr + 12) != 0x08' **/ + + UX_TEST_CHECK_SUCCESS(nx_packet_allocate(&packet_pool_device, &out_packet, NX_UDP_PACKET, NX_WAIT_FOREVER)); + + out_packet->nx_packet_length = (ULONG)(out_packet->nx_packet_data_end - out_packet->nx_packet_prepend_ptr); + memset(out_packet->nx_packet_prepend_ptr, 'a', out_packet->nx_packet_length); + out_packet->nx_packet_prepend_ptr[12] = 0x00; + + /* Now send the packet. */ + _ux_device_class_cdc_ecm_write(cdc_ecm_device, out_packet); + + /* Wait for host to receive it. */ + tx_thread_sleep(500); + + /** Test '*(packet -> nx_packet_prepend_ptr + 13) != 0' **/ + + UX_TEST_CHECK_SUCCESS(nx_packet_allocate(&packet_pool_device, &out_packet, NX_UDP_PACKET, NX_WAIT_FOREVER)); + + out_packet->nx_packet_length = (ULONG)(out_packet->nx_packet_data_end - out_packet->nx_packet_prepend_ptr); + memset(out_packet->nx_packet_prepend_ptr, 'a', out_packet->nx_packet_length); + out_packet->nx_packet_prepend_ptr[12] = 0x08; + out_packet->nx_packet_prepend_ptr[13] = 0x01; + + /* Now send the packet. */ + _ux_device_class_cdc_ecm_write(cdc_ecm_device, out_packet); + + /* Wait for host to receive it. */ + tx_thread_sleep(500); + + /* We're done!? */ +} + +static void post_init_device() +{ +} diff --git a/test/regression/usbx_cdc_ecm_host_packet_pool_create_fail_test.c b/test/regression/usbx_cdc_ecm_host_packet_pool_create_fail_test.c new file mode 100644 index 00000000..3a23314b --- /dev/null +++ b/test/regression/usbx_cdc_ecm_host_packet_pool_create_fail_test.c @@ -0,0 +1,72 @@ +/* This tests the case where the CDC-ECM thread creation fails. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static DEVICE_INIT_DATA device_init_data = { + .framework = default_device_framework, + .framework_length = sizeof(default_device_framework), + .dont_register_hcd = 1, +}; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_host_packet_pool_create_fail_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC-ECM Host Packet Pool Create Test........................ "); + printf("Deprecated\n"); + test_control_return(0); + return; + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize_use_framework(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ + +int i; + + /* Enumerate first so we can initialize memory test. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + + /* The HCD init function put()s the HCD semaphore, so we can do this here. */ + ux_test_wait_for_enum_thread_completion(); + + /* We want at least one memory test. */ + ux_test_memory_test_initialize(); + + /* Disconnect so we can setup test. */ + ux_test_disconnect_host_wait_for_enum_completion(); + + UX_TEST_ACTION packet_pool_create_fail_action = {0}; + packet_pool_create_fail_action.usbx_function = UX_TEST_OVERRIDE_NX_PACKET_POOL_CREATE; + packet_pool_create_fail_action.name_ptr = "host CDC-ECM packet pool"; + packet_pool_create_fail_action.no_return = 0; + packet_pool_create_fail_action.status = UX_ERROR; + + for (i = 0; i < UX_RH_ENUMERATION_RETRY; i++) + { + ux_test_add_action_to_main_list(packet_pool_create_fail_action); + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ENUMERATOR, UX_ERROR)); + } + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE)); + + /* Start enumeration. */ + ux_test_connect_slave_and_host_wait_for_enum_completion(); + + /* Disconnect. Note that this also does the memory check. */ + ux_test_disconnect_slave_and_host_wait_for_enum_completion(); + + UX_TEST_ASSERT(ux_test_check_actions_empty()); + UX_TEST_ASSERT(cdc_ecm_host_from_system_change_function == UX_NULL); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_host_thread_create_fail_test.c b/test/regression/usbx_cdc_ecm_host_thread_create_fail_test.c new file mode 100644 index 00000000..fb993a2d --- /dev/null +++ b/test/regression/usbx_cdc_ecm_host_thread_create_fail_test.c @@ -0,0 +1,57 @@ +/* This tests the case where the CDC-ECM thread creation fails. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static DEVICE_INIT_DATA device_init_data = { + .framework = default_device_framework, + .framework_length = sizeof(default_device_framework), + .dont_register_hcd = 1, +}; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_host_thread_create_fail_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC-ECM Host Thread Fail Test............................... "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize_use_framework(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ + +int i; + + UX_TEST_ACTION thread_create_fail_action = {0}; + thread_create_fail_action.usbx_function = UX_TEST_OVERRIDE_TX_THREAD_CREATE; + thread_create_fail_action.name_ptr = "ux_host_cdc_ecm_thread"; + thread_create_fail_action.no_return = 0; + thread_create_fail_action.status = UX_ERROR; + + for (i = 0; i < UX_RH_ENUMERATION_RETRY; i++) + { + ux_test_add_action_to_main_list(thread_create_fail_action); + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_UTILITY, UX_ERROR)); + } + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE)); + + /* Enumerate. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + + /* The HCD init function put()s the HCD semaphore, so we can do this here. */ + ux_test_wait_for_enum_thread_completion(); + + UX_TEST_ASSERT(ux_test_check_actions_empty()); + UX_TEST_ASSERT(cdc_ecm_host_from_system_change_function == UX_NULL); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_host_thread_link_down_before_transfer_test.c b/test/regression/usbx_cdc_ecm_host_thread_link_down_before_transfer_test.c new file mode 100644 index 00000000..64d47f75 --- /dev/null +++ b/test/regression/usbx_cdc_ecm_host_thread_link_down_before_transfer_test.c @@ -0,0 +1,72 @@ +/* This tests the case where right before the transfer is armed, the link state + is down in the cdc-ecm thread. */ + +#include "usbx_ux_test_cdc_ecm.h" + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_host_thread_link_down_before_transfer_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC-ECM Host Thread Link Down Before Transfer Test.......... "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static UCHAR is_cdc_ecm_thread_suspended; + +static VOID suspend_cdc_ecm_thread_action_func(UX_TEST_ACTION *action, VOID *params) +{ + + is_cdc_ecm_thread_suspended = 1; + + /* We're being called by nx_packet_allocate in cdc-ecm thread. Wait for test + thread to resume us. */ + tx_thread_suspend(tx_thread_identify()); +} + +static void post_init_host() +{ + + /* Currently, the cdc-ecm thread should be waiting for a transfer to complete. + We need to create an action for having the cdc-ecm thread suspend during + the packet allocate, then do a write from the device so the cdc-ecm thread + call the packet allocate, then set the link to down, then resume the thread. */ + + /* Create the action for having cdc-ecm thread suspend on packet allocate. */ + UX_TEST_ACTION packet_allocate_suspend_action = {0}; + packet_allocate_suspend_action.usbx_function = UX_TEST_OVERRIDE_NX_PACKET_ALLOCATE; + packet_allocate_suspend_action.name_ptr = ip_pool_host_name; + packet_allocate_suspend_action.action_func = suspend_cdc_ecm_thread_action_func; + ux_test_add_action_to_main_list(packet_allocate_suspend_action); + + /* Write to the host so the cdc-ecm thread will redo the nx_packet_allocate. */ + write_packet_udp(&udp_socket_device, &packet_pool_device, HOST_IP_ADDRESS, HOST_SOCKET_PORT_UDP, 0, "device"); + + /* Now wait for the cdc-ecm thread to suspend. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uchar(&is_cdc_ecm_thread_suspended, 1)); + + /* Now set the link state to down. */ + ux_test_device_class_cdc_ecm_set_link_state(cdc_ecm_device, 0); + + /* Now wait for the link to be set to pending down (it won't be down since thread is suspended). */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_ulong(&cdc_ecm_host->ux_host_class_cdc_ecm_link_state, UX_HOST_CLASS_CDC_ECM_LINK_STATE_PENDING_DOWN)); + + /* Now resume the cdc-ecm thread. */ + tx_thread_resume(&cdc_ecm_host->ux_host_class_cdc_ecm_thread); + + /* Now wait for link to be down. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_ulong(&cdc_ecm_host->ux_host_class_cdc_ecm_link_state, UX_HOST_CLASS_CDC_ECM_LINK_STATE_DOWN)); + + /* Now we're done. */ +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_host_thread_packet_allocate_fail_test.c b/test/regression/usbx_cdc_ecm_host_thread_packet_allocate_fail_test.c new file mode 100644 index 00000000..55125c89 --- /dev/null +++ b/test/regression/usbx_cdc_ecm_host_thread_packet_allocate_fail_test.c @@ -0,0 +1,59 @@ +/* This tests the case the nx_packet_allocate fails in the cdc-ecm thread. */ + +#include "usbx_ux_test_cdc_ecm.h" + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_host_thread_packet_allocate_fail_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC-ECM Host Thread Packet Allocate Fail Test............... "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static void post_init_host() +{ + +int i; +int device_num_writes = 0; +int host_num_reads = 0; + + /* Have the device send the max number of packets to the host. */ + for (i = 0; i < UX_HOST_CLASS_CDC_ECM_NX_PKPOOL_ENTRIES; i++) + { + + write_packet_udp(&udp_socket_device, &packet_pool_device, HOST_IP_ADDRESS, HOST_SOCKET_PORT_UDP, device_num_writes++, "device"); + } + + /* Time to setup our action since we expect an error. */ + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_MEMORY_INSUFFICIENT)); + + /* Now send the one that should make the call overflow. */ + write_packet_udp(&udp_socket_device, &packet_pool_device, HOST_IP_ADDRESS, HOST_SOCKET_PORT_UDP, device_num_writes++, "device"); + + /* Now wait for error to occur. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_empty_actions()); + + /* Let's be good sports and make sure everything else works. */ + for (i = 0; i < UX_HOST_CLASS_CDC_ECM_NX_PKPOOL_ENTRIES + 1; i++) + { + + read_packet_udp(&udp_socket_host, host_num_reads++, "host"); + } + + /* Send one more. */ + write_packet_udp(&udp_socket_device, &packet_pool_device, HOST_IP_ADDRESS, HOST_SOCKET_PORT_UDP, device_num_writes++, "device"); + /* Read one more. */ + read_packet_udp(&udp_socket_host, host_num_reads++, "host"); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_host_thread_packet_append_fail_test.c b/test/regression/usbx_cdc_ecm_host_thread_packet_append_fail_test.c new file mode 100644 index 00000000..06841ecc --- /dev/null +++ b/test/regression/usbx_cdc_ecm_host_thread_packet_append_fail_test.c @@ -0,0 +1,61 @@ +/* This tests the case the nx_packet_allocate fails in the cdc-ecm thread. */ + +#define TEST_NX_PACKET_CHAIN +#include "usbx_ux_test_cdc_ecm.h" + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_host_thread_packet_allocate_fail_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC-ECM Host Thread Packet Append Fail Test................. "); + stepinfo("\n"); +#if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && defined(UX_DEVICE_CLASS_CDC_ECM_ZERO_COPY) + printf("Skipped\n"); + return; +#endif + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static void post_init_host() +{ + +ULONG n_available; +int i; +int device_num_writes = 0; +int host_num_reads = 0; + + /* Have the device send the max number of packets to the host. */ + ux_utility_delay_ms(1000); + n_available = cdc_ecm_host->ux_host_class_cdc_ecm_packet_pool->nx_packet_pool_available; + for (i = 0; i < n_available; i++) + write_udp(&udp_socket_device, &packet_pool_device, HOST_IP_ADDRESS, HOST_SOCKET_PORT_UDP, device_num_writes++, "device", 4); + ux_utility_delay_ms(1000); + + /* Time to setup our action since we expect an error. */ + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CLASS_ETH_PACKET_ERROR)); + + /* Now send the one that should make the append error (discarded). */ + write_packet_udp(&udp_socket_device, &packet_pool_device, HOST_IP_ADDRESS, HOST_SOCKET_PORT_UDP, device_num_writes, "device"); + + /* Now wait for error to occur. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_empty_actions()); + + /* Let's be good sports and make sure everything else works. */ + for (i = 0; i < n_available; i++) + read_packet_udp(&udp_socket_host, host_num_reads++, "host"); + + /* Send one more. */ + write_packet_udp(&udp_socket_device, &packet_pool_device, HOST_IP_ADDRESS, HOST_SOCKET_PORT_UDP, device_num_writes++, "device"); + /* Read one more. */ + read_packet_udp(&udp_socket_host, host_num_reads++, "host"); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_interface_before_control_interface_test.c b/test/regression/usbx_cdc_ecm_interface_before_control_interface_test.c new file mode 100644 index 00000000..eb1c6370 --- /dev/null +++ b/test/regression/usbx_cdc_ecm_interface_before_control_interface_test.c @@ -0,0 +1,189 @@ +/* This test tests the case where there is an interface before the control interface. In this case, it's a storage class interface. + We do this because during activation, we need to link the the control interface into the class instance, so we need to find it. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static unsigned char interface_before_control_interface_framework[] = { + + /* Device Descriptor */ + 0x12, /* bLength */ + 0x01, /* bDescriptorType */ + 0x10, 0x01, /* bcdUSB */ + 0xef, /* bDeviceClass - Depends on bDeviceSubClass */ + 0x02, /* bDeviceSubClass - Depends on bDeviceProtocol */ + 0x01, /* bDeviceProtocol - There's an IAD */ + 0x40, /* bMaxPacketSize0 */ + 0x70, 0x07, /* idVendor */ + 0x42, 0x10, /* idProduct */ + 0x00, 0x01, /* bcdDevice */ + 0x01, /* iManufacturer */ + 0x02, /* iProduct */ + 0x03, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ + + /* Configuration Descriptor */ + 0x09, /* bLength */ + 0x02, /* bDescriptorType */ + 0x76, 0x00, /* wTotalLength */ + 0x02, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xc0, /* bmAttributes - Self-powered */ + 0x00, /* bMaxPower */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x03, /* bNumEndpoints */ + 0x08, /* bInterfaceClass - Mass Storage */ + 0x06, /* bInterfaceSubClass */ + 0x50, /* bInterfaceProtocol */ + 0x00, /* iInterface */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x81, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x02, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x83, /* bEndpointAddress */ + 0x03, /* bmAttributes - Interrupt */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x01, /* bInterval */ + + /* Interface Association Descriptor */ + 0x08, /* bLength */ + 0x0b, /* bDescriptorType */ + 0x00, /* bFirstInterface */ + 0x02, /* bInterfaceCount */ + 0x02, /* bFunctionClass - CDC - Communication */ + 0x06, /* bFunctionSubClass - ECM */ + 0x00, /* bFunctionProtocol - No class specific protocol required */ + 0x00, /* iFunction */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x02, /* bInterfaceClass - CDC - Communication */ + 0x06, /* bInterfaceSubClass - ECM */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* CDC Header Functional Descriptor */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x00, /* bDescriptorSubType */ + 0x10, 0x01, /* bcdCDC */ + + /* CDC ECM Functional Descriptor */ + 0x0d, /* bLength */ + 0x24, /* bDescriptorType */ + 0x0f, /* bDescriptorSubType */ + 0x04, /* iMACAddress */ + 0x00, 0x00, 0x00, 0x00, /* bmEthernetStatistics */ + 0xea, 0x05, /* wMaxSegmentSize */ + 0x00, 0x00, /* wNumberMCFilters */ + 0x00, /* bNumberPowerFilters */ + + /* CDC Union Functional Descriptor */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x06, /* bDescriptorSubType */ + 0x00, /* bmMasterInterface */ + 0x01, /* bmSlaveInterface0 */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x84, /* bEndpointAddress */ + 0x03, /* bmAttributes - Interrupt */ + 0x08, 0x00, /* wMaxPacketSize */ + 0x08, /* bInterval */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x01, /* bAlternateSetting */ + 0x02, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x05, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x86, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + +}; + +static DEVICE_INIT_DATA device_init_data = { interface_before_control_interface_framework, sizeof(interface_before_control_interface_framework) }; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_interface_before_control_interface_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running cdc_ecm interface before control interface Test............. "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize_use_framework(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ + + cdc_ecm_basic_test(BASIC_TEST_HOST, BASIC_TEST_TCP); +} + +static void post_init_device() +{ + + cdc_ecm_basic_test(BASIC_TEST_DEVICE, BASIC_TEST_TCP); +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_invalid_alt_setting_after_zero_endpt_data_iface_test.c b/test/regression/usbx_cdc_ecm_invalid_alt_setting_after_zero_endpt_data_iface_test.c new file mode 100644 index 00000000..791efb18 --- /dev/null +++ b/test/regression/usbx_cdc_ecm_invalid_alt_setting_after_zero_endpt_data_iface_test.c @@ -0,0 +1,170 @@ +/* This tests the case where the default data interface has zero endpoints, and + the interface right after is also a data interface but contains an invalid + alternate setting value. Host should report error. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static unsigned char non_data_interface_after_zero_endpoint_data_interface_framework[] = { + + /* Device Descriptor */ + 0x12, /* bLength */ + 0x01, /* bDescriptorType */ + 0x10, 0x01, /* bcdUSB */ + 0xef, /* bDeviceClass - Depends on bDeviceSubClass */ + 0x02, /* bDeviceSubClass - Depends on bDeviceProtocol */ + 0x01, /* bDeviceProtocol - There's an IAD */ + 0x40, /* bMaxPacketSize0 */ + 0x70, 0x07, /* idVendor */ + 0x42, 0x10, /* idProduct */ + 0x00, 0x01, /* bcdDevice */ + 0x01, /* iManufacturer */ + 0x02, /* iProduct */ + 0x03, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ + + /* Configuration Descriptor */ + 0x09, /* bLength */ + 0x02, /* bDescriptorType */ + 0x58, 0x00, /* wTotalLength */ + 0x02, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xc0, /* bmAttributes - Self-powered */ + 0x00, /* bMaxPower */ + + /* Interface Association Descriptor */ + 0x08, /* bLength */ + 0x0b, /* bDescriptorType */ + 0x00, /* bFirstInterface */ + 0x02, /* bInterfaceCount */ + 0x02, /* bFunctionClass - CDC - Communication */ + 0x06, /* bFunctionSubClass - ECM */ + 0x00, /* bFunctionProtocol - No class specific protocol required */ + 0x00, /* iFunction */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x02, /* bInterfaceClass - CDC - Communication */ + 0x06, /* bInterfaceSubClass - ECM */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* CDC Header Functional Descriptor */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x00, /* bDescriptorSubType */ + 0x10, 0x01, /* bcdCDC */ + + /* CDC ECM Functional Descriptor */ + 0x0d, /* bLength */ + 0x24, /* bDescriptorType */ + 0x0f, /* bDescriptorSubType */ + 0x04, /* iMACAddress */ + 0x00, 0x00, 0x00, 0x00, /* bmEthernetStatistics */ + 0xea, 0x05, /* wMaxSegmentSize */ + 0x00, 0x00, /* wNumberMCFilters */ + 0x00, /* bNumberPowerFilters */ + + /* CDC Union Functional Descriptor */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x06, /* bDescriptorSubType */ + 0x00, /* bmMasterInterface */ + 0x01, /* bmSlaveInterface0 */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x83, /* bEndpointAddress */ + 0x03, /* bmAttributes - Interrupt */ + 0x08, 0x00, /* wMaxPacketSize */ + 0x08, /* bInterval */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + /* Invalid alternate setting. */ + 0xff, /* bAlternateSetting */ + 0x02, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x02, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x81, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + +}; + +static DEVICE_INIT_DATA device_init_data = { + .framework = non_data_interface_after_zero_endpoint_data_interface_framework, + .framework_length = sizeof(non_data_interface_after_zero_endpoint_data_interface_framework), + .dont_register_hcd = 1, +}; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_invalid_alternate_setting_after_zero_endpoint_data_interface_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC-ECM Invalid Alternate Setting After... Test............. "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize_use_framework(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ + + /* We expect this to fail multiple times since enumeration tries multiple times. */ + ux_test_add_action_to_main_list_multiple(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED), 3); + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE)); + + /* Enumerate. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + + /* The HCD init function put()s the HCD semaphore, so we can do this here. */ + ux_test_wait_for_enum_thread_completion(); + + /* Enumeration should've failed. */ + UX_TEST_ASSERT(ux_test_check_actions_empty()); + UX_TEST_ASSERT(cdc_ecm_host_from_system_change_function == UX_NULL); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_link_down_while_ongoing_transfers_test.c b/test/regression/usbx_cdc_ecm_link_down_while_ongoing_transfers_test.c new file mode 100644 index 00000000..9aec09e0 --- /dev/null +++ b/test/regression/usbx_cdc_ecm_link_down_while_ongoing_transfers_test.c @@ -0,0 +1,199 @@ +/* This test the case where a LINK DOWN event is received while transfers are + ongoing. */ + +#include "usbx_ux_test_cdc_ecm.h" +#include "ux_device_stack.h" + +static ULONG global_basic_test_num_writes_host; +static ULONG global_basic_test_num_reads_host; + +static ULONG global_basic_test_num_writes_device; +static ULONG global_basic_test_num_reads_device; + +static UCHAR host_waiting_for_link_down; +static UCHAR host_waiting_for_link_up; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_link_down_while_ongoing_transfers_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC-ECM Host Link Down While Ongoing Transfers Test......... "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static void basic_test_host() +{ + +UINT num_iters; +UINT i; + + /*** Basic test - no transfers going on. ***/ + stepinfo("Basic test - no transfers going on.\n"); + + /* Now wait for the link to be down. */ + host_waiting_for_link_down = 1; + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_ulong(&cdc_ecm_host->ux_host_class_cdc_ecm_link_state, UX_HOST_CLASS_CDC_ECM_LINK_STATE_DOWN)); + + /* Wait for everything to get cleaned up. */ + tx_thread_sleep(MS_TO_TICK(1000)); + + /* Now wait for the link to be up. */ + host_waiting_for_link_up = 1; + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_ulong(&cdc_ecm_host->ux_host_class_cdc_ecm_link_state, UX_HOST_CLASS_CDC_ECM_LINK_STATE_UP)); + + /* Run that basic test again. */ + for (num_iters = 0; num_iters < 10; num_iters++) + { + + for (i = 0; i < 10; i++) + write_packet_udp(&udp_socket_host, &packet_pool_host, DEVICE_IP_ADDRESS, DEVICE_SOCKET_PORT_UDP, global_basic_test_num_writes_host++, "host"); + + for (i = 0; i < 10; i++) + read_packet_udp(&udp_socket_host, global_basic_test_num_reads_host++, "host"); + } + + /* Wait for all transfers to complete. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_ulong(&global_basic_test_num_reads_host, 100)); + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_ulong(&global_basic_test_num_reads_device, 100)); +} + +static void basic_test_device() +{ + +UINT num_iters; +UINT i; + + /*** Basic test. ***/ + + /* Wait for host to wait for link down. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uchar(&host_waiting_for_link_down, 1)); + host_waiting_for_link_down = 0; + + /* Now set the link to down. */ + ux_test_device_class_cdc_ecm_set_link_state(cdc_ecm_device, UX_DEVICE_CLASS_CDC_ECM_LINK_STATE_DOWN); + + /* Wait for host to wait for link up. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uchar(&host_waiting_for_link_up, 1)); + host_waiting_for_link_up = 0; + + /* Now set the link to up. */ + ux_test_device_class_cdc_ecm_set_link_state(cdc_ecm_device, UX_DEVICE_CLASS_CDC_ECM_LINK_STATE_UP); + + /* Now do basic test. */ + for (num_iters = 0; num_iters < 10; num_iters++) + { + + for (i = 0; i < 10; i++) + write_packet_udp(&udp_socket_device, &packet_pool_device, HOST_IP_ADDRESS, HOST_SOCKET_PORT_UDP, global_basic_test_num_writes_device++, "device"); + + for (i = 0; i < 10; i++) + read_packet_udp(&udp_socket_device, global_basic_test_num_reads_device++, "device"); + } + + /* Wait for all transfers to complete. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_ulong(&global_basic_test_num_reads_host, 100)); + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_ulong(&global_basic_test_num_reads_device, 100)); +} + +#define NUM_WRITES 500 +#define NUM_WRITES_BEFORE_LINK_DOWN 10 +#define MAX_WRITE_WHILE_LINK_DOWN (NUM_WRITES - NUM_WRITES_BEFORE_LINK_DOWN) + +static void ongoing_writes_test_host() +{ + +UINT i; +UINT pre_write_fail_num_packet_pool_packets_available; +UINT num_writes = 0; + + /*** Link down when there are queued writes, and we try to add writes. ***/ + stepinfo("Ongoing writes test.\n"); + + pre_write_fail_num_packet_pool_packets_available = packet_pool_host.nx_packet_pool_available; + + /* We expect some errors. */ + UX_TEST_ACTION error_match_action = create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CLASS_CDC_ECM_LINK_STATE_DOWN_ERROR); + ux_test_add_action_to_main_list_multiple(error_match_action, MAX_WRITE_WHILE_LINK_DOWN); + + /* Queue up some writes - device isn't going to read them, so they stay queued. */ + for (i = 0; i < NUM_WRITES; i++) + { + + /* Write packet. */ + write_packet_udp(&udp_socket_host, &packet_pool_host, DEVICE_IP_ADDRESS, DEVICE_SOCKET_PORT_UDP, num_writes++, "host"); + + /* Have we queued 10 packets? */ + if (i == NUM_WRITES_BEFORE_LINK_DOWN) + { + + /* Set the link to down. The _hope_ here is to have the CDC-ECM thread + process the link down while we're still writing packets. This + should be improved in the future. I don't want to be the poor + SOB that has to do it! + + We cheat here by calling a device API from the host. */ + ux_test_device_class_cdc_ecm_set_link_state(cdc_ecm_device, UX_DEVICE_CLASS_CDC_ECM_LINK_STATE_DOWN); + + while (cdc_ecm_host->ux_host_class_cdc_ecm_link_state != UX_HOST_CLASS_CDC_ECM_LINK_STATE_DOWN) + tx_thread_sleep(10); + } + } + + /* Make sure everything is ok. */ + UX_TEST_ASSERT(cdc_ecm_host->ux_host_class_cdc_ecm_link_state == UX_HOST_CLASS_CDC_ECM_LINK_STATE_DOWN); +NX_PACKET_POOL *packet_pool_host_local = &packet_pool_host; +UX_HOST_CLASS_CDC_ECM *cdc_ecm_host_local = cdc_ecm_host; + UX_TEST_ASSERT(packet_pool_host.nx_packet_pool_available == pre_write_fail_num_packet_pool_packets_available); + + /* Make sure at least one error was reported. */ + UX_TEST_ASSERT(ux_test_get_num_actions_left() != 90); + + /* Now clear the error match actions out. */ + ux_test_clear_main_list_actions(); + + /* Run that basic test again. */ + + /* Now wait for the link to be up. */ + host_waiting_for_link_up = 1; + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_ulong(&cdc_ecm_host->ux_host_class_cdc_ecm_link_state, UX_HOST_CLASS_CDC_ECM_LINK_STATE_UP)); + + cdc_ecm_basic_test(BASIC_TEST_HOST, BASIC_TEST_TCP); +} + +static void ongoing_writes_test_device() +{ + + /*** Ongoing writes test. ***/ + + /* The host is gonna do all the work. At some point, he'll want the link back + up to run the basic test again. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uchar(&host_waiting_for_link_up, 1)); + + /* Set link to up. */ + ux_test_device_class_cdc_ecm_set_link_state(cdc_ecm_device, UX_DEVICE_CLASS_CDC_ECM_LINK_STATE_UP); + + /* Now do basic test. */ + cdc_ecm_basic_test(BASIC_TEST_DEVICE, BASIC_TEST_TCP); +} + +static void post_init_host() +{ + + //basic_test_host(); + ongoing_writes_test_host(); +} + +static void post_init_device(ULONG input) +{ + + //basic_test_device(); + ongoing_writes_test_device(); +} diff --git a/test/regression/usbx_cdc_ecm_mac_address_invalid_length_test.c b/test/regression/usbx_cdc_ecm_mac_address_invalid_length_test.c new file mode 100644 index 00000000..1b2f14d1 --- /dev/null +++ b/test/regression/usbx_cdc_ecm_mac_address_invalid_length_test.c @@ -0,0 +1,81 @@ +/* This tests the case where the mac address string is too long. This is an + error. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static unsigned char invalid_mac_address_string_length[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL CDCECM Device" */ + 0x09, 0x04, 0x02, 0x10, + 0x45, 0x4c, 0x20, 0x43, 0x44, 0x43, 0x45, 0x43, + 0x4d, 0x20, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31, + + /* MAC Address string descriptor : Index 4 - "001E5841B878" */ + 0x09, 0x04, 0x04, + 0x1b, /* This byte is the length of the string. It just needs to be greater than 26 (look in mac_address_get.c). */ + 0x30, 0x30, 0x31, 0x45, 0x35, 0x38, + 0x34, 0x31, 0x42, 0x38, 0x37, 0x38, + 0x30, 0x30, 0x31, 0x45, 0x35, 0x38, + 0x34, 0x31, 0x42, 0x38, 0x37, 0x38, + 0x37, 0x38, 0x37, + +}; + +static DEVICE_INIT_DATA device_init_data = { + .string_framework = invalid_mac_address_string_length, + .string_framework_length = sizeof(invalid_mac_address_string_length), + .dont_register_hcd = 1, +}; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_mac_address_invalid_length_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC-ECM Mac Address Invalid Length Test..................... "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize_use_framework(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ + +int i; + + /* We expect this to fail multiple times since enumeration tries multiple times. */ + for (i = 0; i < UX_RH_ENUMERATION_RETRY; i++) + { + + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED)); + } + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE)); + + /* Enumerate. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + + /* The HCD init function put()s the HCD semaphore, so we can do this here. */ + ux_test_wait_for_enum_thread_completion(); + + /* Enumeration should've failed. */ + UX_TEST_ASSERT(ux_test_check_actions_empty()); + UX_TEST_ASSERT(cdc_ecm_host_from_system_change_function == UX_NULL); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_mac_address_test.c b/test/regression/usbx_cdc_ecm_mac_address_test.c new file mode 100644 index 00000000..a2746ec4 --- /dev/null +++ b/test/regression/usbx_cdc_ecm_mac_address_test.c @@ -0,0 +1,78 @@ +/* This tests general cases in the mac address string like hexadecimal values. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static unsigned char mac_address_test_string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL CDCECM Device" */ + 0x09, 0x04, 0x02, 0x10, + 0x45, 0x4c, 0x20, 0x43, 0x44, 0x43, 0x45, 0x43, + 0x4d, 0x20, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31, + + /* MAC Address string descriptor : Index 4 - "001E5841B878" */ + 0x09, 0x04, 0x04, 0x0C, + 'A', 'A', /* Test capital upper and lower element. */ + '0', '1', + '2', '3', + '4', 'b', + 'c', 'D', + 'e', 'f', + +}; + +static DEVICE_INIT_DATA device_init_data = { + .string_framework = mac_address_test_string_framework, + .string_framework_length = sizeof(mac_address_test_string_framework), +}; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_mac_address_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC-ECM Mac Address Test.................................... "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize_use_framework(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ + /* Ensure the mac address is correct. */ + UX_TEST_ASSERT(cdc_ecm_host->ux_host_class_cdc_ecm_node_id[0] == 0xaa); + UX_TEST_ASSERT(cdc_ecm_host->ux_host_class_cdc_ecm_node_id[1] == 0x01); + UX_TEST_ASSERT(cdc_ecm_host->ux_host_class_cdc_ecm_node_id[2] == 0x23); + UX_TEST_ASSERT(cdc_ecm_host->ux_host_class_cdc_ecm_node_id[3] == 0x4b); + UX_TEST_ASSERT(cdc_ecm_host->ux_host_class_cdc_ecm_node_id[4] == 0xcd); + UX_TEST_ASSERT(cdc_ecm_host->ux_host_class_cdc_ecm_node_id[5] == 0xef); + + /* Configuration descriptor invalid while parsing MAC address */ + /* descriptor_length < 3 */ + default_device_framework[18] = 0; + UX_TEST_ASSERT(UX_DESCRIPTOR_CORRUPTED == _ux_host_class_cdc_ecm_mac_address_get(cdc_ecm_host)); + /* descriptor_length > total_configuration_length */ + default_device_framework[18] = 0xFF; + UX_TEST_ASSERT(UX_DESCRIPTOR_CORRUPTED == _ux_host_class_cdc_ecm_mac_address_get(cdc_ecm_host)); + /* Restore. */ + default_device_framework[18] = 9; + UX_TEST_ASSERT(UX_SUCCESS == _ux_host_class_cdc_ecm_mac_address_get(cdc_ecm_host)); + +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_no_control_interface_test.c b/test/regression/usbx_cdc_ecm_no_control_interface_test.c new file mode 100644 index 00000000..77df447e --- /dev/null +++ b/test/regression/usbx_cdc_ecm_no_control_interface_test.c @@ -0,0 +1,111 @@ +/* This test tests the case where there is no control interface. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static unsigned char no_control_interface_framework[] = { + + /* Device Descriptor */ + 0x12, /* bLength */ + 0x01, /* bDescriptorType */ + 0x10, 0x01, /* bcdUSB */ + 0xef, /* bDeviceClass - Depends on bDeviceSubClass */ + 0x02, /* bDeviceSubClass - Depends on bDeviceProtocol */ + 0x01, /* bDeviceProtocol - There's an IAD */ + 0x40, /* bMaxPacketSize0 */ + 0x70, 0x07, /* idVendor */ + 0x42, 0x10, /* idProduct */ + 0x00, 0x01, /* bcdDevice */ + 0x01, /* iManufacturer */ + 0x02, /* iProduct */ + 0x03, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ + + /* Configuration Descriptor */ + 0x09, /* bLength */ + 0x02, /* bDescriptorType */ + 0x29, 0x00, /* wTotalLength */ + 0x02, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xc0, /* bmAttributes - Self-powered */ + 0x00, /* bMaxPower */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x01, /* bAlternateSetting */ + 0x02, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x05, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x86, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + +}; + +static DEVICE_INIT_DATA device_init_data = { no_control_interface_framework, sizeof(no_control_interface_framework), .dont_register_hcd = 1 }; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_no_control_interface_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC-ECM No Control Interface Test........................... "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize_use_framework(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ + + /* We expect this to fail multiple times since enumeration tries multiple times. */ + ux_test_add_action_to_main_list_multiple(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED), 3); + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE)); + + /* Begin enumeration. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + + /* The HCD init function put()s the HCD semaphore, so we can do this here. */ + ux_test_wait_for_enum_thread_completion(); + + /* Enumeration should've failed. */ + UX_TEST_ASSERT(ux_test_check_actions_empty()); + UX_TEST_ASSERT(cdc_ecm_host_from_system_change_function == UX_NULL); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_no_functional_descriptor_test.c b/test/regression/usbx_cdc_ecm_no_functional_descriptor_test.c new file mode 100644 index 00000000..3e394d64 --- /dev/null +++ b/test/regression/usbx_cdc_ecm_no_functional_descriptor_test.c @@ -0,0 +1,164 @@ +/* This tests the case where there no functional descriptor. There should be a + functional descriptor, so this is an error. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static unsigned char no_function_descriptor_framework[] = { + + /* Device Descriptor */ + 0x12, /* bLength */ + 0x01, /* bDescriptorType */ + 0x10, 0x01, /* bcdUSB */ + 0xef, /* bDeviceClass - Depends on bDeviceSubClass */ + 0x02, /* bDeviceSubClass - Depends on bDeviceProtocol */ + 0x01, /* bDeviceProtocol - There's an IAD */ + 0x40, /* bMaxPacketSize0 */ + 0x70, 0x07, /* idVendor */ + 0x42, 0x10, /* idProduct */ + 0x00, 0x01, /* bcdDevice */ + 0x01, /* iManufacturer */ + 0x02, /* iProduct */ + 0x03, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ + + /* Configuration Descriptor */ + 0x09, /* bLength */ + 0x02, /* bDescriptorType */ + 0x4b, 0x00, /* wTotalLength */ + 0x02, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xc0, /* bmAttributes - Self-powered */ + 0x00, /* bMaxPower */ + + /* Interface Association Descriptor */ + 0x08, /* bLength */ + 0x0b, /* bDescriptorType */ + 0x00, /* bFirstInterface */ + 0x02, /* bInterfaceCount */ + 0x02, /* bFunctionClass - CDC - Communication */ + 0x06, /* bFunctionSubClass - ECM */ + 0x00, /* bFunctionProtocol - No class specific protocol required */ + 0x00, /* iFunction */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x02, /* bInterfaceClass - CDC - Communication */ + 0x06, /* bInterfaceSubClass - ECM */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* CDC Header Functional Descriptor */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x00, /* bDescriptorSubType */ + 0x10, 0x01, /* bcdCDC */ + + /* CDC Union Functional Descriptor */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x06, /* bDescriptorSubType */ + 0x00, /* bmMasterInterface */ + 0x01, /* bmSlaveInterface0 */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x83, /* bEndpointAddress */ + 0x03, /* bmAttributes - Interrupt */ + 0x08, 0x00, /* wMaxPacketSize */ + 0x08, /* bInterval */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x01, /* bAlternateSetting */ + 0x02, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x02, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x81, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + +}; + +static DEVICE_INIT_DATA device_init_data = { + .framework = no_function_descriptor_framework, + .framework_length = sizeof(no_function_descriptor_framework), + .dont_register_hcd = 1, +}; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_no_functional_descriptor_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC-ECM No Functional Descriptor Test....................... "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize_use_framework(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ + +int i; + + /* We expect this to fail multiple times since enumeration tries multiple times. */ + for (i = 0; i < UX_RH_ENUMERATION_RETRY; i++) + { + + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED)); + } + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE)); + + /* Enumerate. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + + /* The HCD init function put()s the HCD semaphore, so we can do this here. */ + ux_test_wait_for_enum_thread_completion(); + + /* Enumeration should've failed. */ + UX_TEST_ASSERT(ux_test_check_actions_empty()); + UX_TEST_ASSERT(cdc_ecm_host_from_system_change_function == UX_NULL); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_non_data_iface_after_zero_endpt_data_iface_test.c b/test/regression/usbx_cdc_ecm_non_data_iface_after_zero_endpt_data_iface_test.c new file mode 100644 index 00000000..177a2b0b --- /dev/null +++ b/test/regression/usbx_cdc_ecm_non_data_iface_after_zero_endpt_data_iface_test.c @@ -0,0 +1,176 @@ +/* This tests the case where the default data interface has zero endpoints, and + the interface right after it is a non-data interface. Host should report error. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static unsigned char non_data_interface_after_zero_endpoint_data_interface_framework[] = { + + /* Device Descriptor */ + 0x12, /* bLength */ + 0x01, /* bDescriptorType */ + 0x10, 0x01, /* bcdUSB */ + 0xef, /* bDeviceClass - Depends on bDeviceSubClass */ + 0x02, /* bDeviceSubClass - Depends on bDeviceProtocol */ + 0x01, /* bDeviceProtocol - There's an IAD */ + 0x40, /* bMaxPacketSize0 */ + 0x70, 0x07, /* idVendor */ + 0x42, 0x10, /* idProduct */ + 0x00, 0x01, /* bcdDevice */ + 0x01, /* iManufacturer */ + 0x02, /* iProduct */ + 0x03, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ + + /* Configuration Descriptor */ + 0x09, /* bLength */ + 0x02, /* bDescriptorType */ + 0x5f, 0x00, /* wTotalLength */ + 0x02, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xc0, /* bmAttributes - Self-powered */ + 0x00, /* bMaxPower */ + + /* Interface Association Descriptor */ + 0x08, /* bLength */ + 0x0b, /* bDescriptorType */ + 0x00, /* bFirstInterface */ + 0x02, /* bInterfaceCount */ + 0x02, /* bFunctionClass - CDC - Communication */ + 0x06, /* bFunctionSubClass - ECM */ + 0x00, /* bFunctionProtocol - No class specific protocol required */ + 0x00, /* iFunction */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x02, /* bInterfaceClass - CDC - Communication */ + 0x06, /* bInterfaceSubClass - ECM */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* CDC Header Functional Descriptor */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x00, /* bDescriptorSubType */ + 0x10, 0x01, /* bcdCDC */ + + /* CDC ECM Functional Descriptor */ + 0x0d, /* bLength */ + 0x24, /* bDescriptorType */ + 0x0f, /* bDescriptorSubType */ + 0x04, /* iMACAddress */ + 0x00, 0x00, 0x00, 0x00, /* bmEthernetStatistics */ + 0xea, 0x05, /* wMaxSegmentSize */ + 0x00, 0x00, /* wNumberMCFilters */ + 0x00, /* bNumberPowerFilters */ + + /* CDC Union Functional Descriptor */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x06, /* bDescriptorSubType */ + 0x00, /* bmMasterInterface */ + 0x01, /* bmSlaveInterface0 */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x83, /* bEndpointAddress */ + 0x03, /* bmAttributes - Interrupt */ + 0x08, 0x00, /* wMaxPacketSize */ + 0x08, /* bInterval */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x03, /* bNumEndpoints */ + 0x08, /* bInterfaceClass - Mass Storage */ + 0x06, /* bInterfaceSubClass */ + 0x50, /* bInterfaceProtocol */ + 0x00, /* iInterface */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x81, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x02, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x84, /* bEndpointAddress */ + 0x03, /* bmAttributes - Interrupt */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x01, /* bInterval */ + +}; + +static DEVICE_INIT_DATA device_init_data = { + .framework = non_data_interface_after_zero_endpoint_data_interface_framework, + .framework_length = sizeof(non_data_interface_after_zero_endpoint_data_interface_framework), + .dont_register_hcd = 1, +}; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_non_data_interface_after_zero_endpoint_data_interface_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC-ECM Non-Data Interface After Zero... Test............... "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize_use_framework(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ + + /* We expect this to fail multiple times since enumeration tries multiple times. */ + ux_test_add_action_to_main_list_multiple(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED), 3); + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE)); + + /* Enumerate. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + + /* The HCD init function put()s the HCD semaphore, so we can do this here. */ + ux_test_wait_for_enum_thread_completion(); + + /* Enumeration should've failed. */ + UX_TEST_ASSERT(ux_test_check_actions_empty()); + UX_TEST_ASSERT(cdc_ecm_host_from_system_change_function == UX_NULL); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_nx_packet_chain_test.c b/test/regression/usbx_cdc_ecm_nx_packet_chain_test.c new file mode 100644 index 00000000..b90c215e --- /dev/null +++ b/test/regression/usbx_cdc_ecm_nx_packet_chain_test.c @@ -0,0 +1,77 @@ +/* Include necessary system files. */ + +#define TEST_NX_PACKET_CHAIN +#define BASIC_TEST_NUM_ITERATIONS 5 +#define BASIC_TEST_NUM_PACKETS_PER_ITERATION 5 +#include "usbx_ux_test_cdc_ecm.h" + +static UCHAR device_is_finished; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_nx_packet_chain_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC ECM NX Packet Chain Test................................ "); + + stepinfo("\n"); + +#if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && defined(UX_DEVICE_CLASS_CDC_ECM_ZERO_COPY) + printf("Skipped for Zero Copy mode\n"); +#else + ux_test_cdc_ecm_initialize(first_unused_memory); +#endif +} + +static void post_init_host() +{ +UCHAR *temp_buf = UX_NULL; +ULONG n_available; +int i; +int device_num_writes = 0; + + /*======== RX buffer allocation fail test. */ + + if (cdc_ecm_host->ux_host_class_cdc_ecm_receive_buffer) + temp_buf = cdc_ecm_host->ux_host_class_cdc_ecm_receive_buffer; + tx_thread_suspend(&cdc_ecm_host -> ux_host_class_cdc_ecm_thread); + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_MEMORY_INSUFFICIENT)); + ux_test_utility_sim_mem_allocate_until_flagged(UX_HOST_CLASS_CDC_ECM_NX_PAYLOAD_SIZE, UX_CACHE_SAFE_MEMORY); + cdc_ecm_host -> ux_host_class_cdc_ecm_receive_buffer = UX_NULL; + tx_thread_resume(&cdc_ecm_host -> ux_host_class_cdc_ecm_thread); + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_empty_actions()); + if (temp_buf) + cdc_ecm_host -> ux_host_class_cdc_ecm_receive_buffer = temp_buf; + ux_test_utility_sim_mem_free_all_flagged(UX_CACHE_SAFE_MEMORY); + + + /* Running UDP test. */ + stepinfo("running UDP test.\n"); + cdc_ecm_basic_test(BASIC_TEST_HOST, BASIC_TEST_UDP); + + /* Wait for device to finish. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uchar(&device_is_finished, UX_TRUE)); + + /* Disconnect. */ + ux_test_disconnect_slave_and_host_wait_for_enum_completion(); + + /* Connect with null system change function. */ + _ux_system_host->ux_system_host_change_function = UX_NULL; + + /* Connect. */ + ux_test_connect_slave_and_host_wait_for_enum_completion(); + + /* We're done. */ +} + +static void post_init_device() +{ + + /* Running UDP test. */ + cdc_ecm_basic_test(BASIC_TEST_DEVICE, BASIC_TEST_UDP); + device_is_finished = UX_TRUE; +} \ No newline at end of file diff --git a/test/regression/usbx_cdc_ecm_one_data_interface_with_no_endpoints_test.c b/test/regression/usbx_cdc_ecm_one_data_interface_with_no_endpoints_test.c new file mode 100644 index 00000000..ae6bbd34 --- /dev/null +++ b/test/regression/usbx_cdc_ecm_one_data_interface_with_no_endpoints_test.c @@ -0,0 +1,141 @@ +/* This tests the case where there is only one default data interface and it + has no endpoints. Host should report an error. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static unsigned char one_data_interface_with_no_endpoints_framework[] = { + + /* Device Descriptor */ + 0x12, /* bLength */ + 0x01, /* bDescriptorType */ + 0x10, 0x01, /* bcdUSB */ + 0xef, /* bDeviceClass - Depends on bDeviceSubClass */ + 0x02, /* bDeviceSubClass - Depends on bDeviceProtocol */ + 0x01, /* bDeviceProtocol - There's an IAD */ + 0x40, /* bMaxPacketSize0 */ + 0x70, 0x07, /* idVendor */ + 0x42, 0x10, /* idProduct */ + 0x00, 0x01, /* bcdDevice */ + 0x01, /* iManufacturer */ + 0x02, /* iProduct */ + 0x03, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ + + /* Configuration Descriptor */ + 0x09, /* bLength */ + 0x02, /* bDescriptorType */ + 0x41, 0x00, /* wTotalLength */ + 0x02, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xc0, /* bmAttributes - Self-powered */ + 0x00, /* bMaxPower */ + + /* Interface Association Descriptor */ + 0x08, /* bLength */ + 0x0b, /* bDescriptorType */ + 0x00, /* bFirstInterface */ + 0x02, /* bInterfaceCount */ + 0x02, /* bFunctionClass - CDC - Communication */ + 0x06, /* bFunctionSubClass - ECM */ + 0x00, /* bFunctionProtocol - No class specific protocol required */ + 0x00, /* iFunction */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x02, /* bInterfaceClass - CDC - Communication */ + 0x06, /* bInterfaceSubClass - ECM */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* CDC Header Functional Descriptor */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x00, /* bDescriptorSubType */ + 0x10, 0x01, /* bcdCDC */ + + /* CDC ECM Functional Descriptor */ + 0x0d, /* bLength */ + 0x24, /* bDescriptorType */ + 0x0f, /* bDescriptorSubType */ + 0x04, /* iMACAddress */ + 0x00, 0x00, 0x00, 0x00, /* bmEthernetStatistics */ + 0xea, 0x05, /* wMaxSegmentSize */ + 0x00, 0x00, /* wNumberMCFilters */ + 0x00, /* bNumberPowerFilters */ + + /* CDC Union Functional Descriptor */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x06, /* bDescriptorSubType */ + 0x00, /* bmMasterInterface */ + 0x01, /* bmSlaveInterface0 */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x83, /* bEndpointAddress */ + 0x03, /* bmAttributes - Interrupt */ + 0x08, 0x00, /* wMaxPacketSize */ + 0x08, /* bInterval */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + +}; + +static DEVICE_INIT_DATA device_init_data = { + .framework = one_data_interface_with_no_endpoints_framework, + .framework_length = sizeof(one_data_interface_with_no_endpoints_framework), + .dont_register_hcd = 1, +}; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_cdc_ecm_one_data_interface_with_no_endpoints_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running CDC-ECM One Data Interface With No Endpoints Test........... "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize_use_framework(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ + + /* We expect this to fail multiple times since enumeration tries multiple times. */ + ux_test_add_action_to_main_list_multiple(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED), 3); + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE)); + + /* Enumerate. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + + /* The HCD init function put()s the HCD semaphore, so we can do this here. */ + ux_test_wait_for_enum_thread_completion(); + + /* Enumeration should've failed. */ + UX_TEST_ASSERT(ux_test_check_actions_empty()); + UX_TEST_ASSERT(cdc_ecm_host_from_system_change_function == UX_NULL); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_class_device_enumeration_test.c b/test/regression/usbx_class_device_enumeration_test.c new file mode 100644 index 00000000..07d64881 --- /dev/null +++ b/test/regression/usbx_class_device_enumeration_test.c @@ -0,0 +1,400 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_host_class_dummy.h" +#include "ux_device_class_dummy.h" +#include "ux_test.h" + + +/* Define USBX demo constants. */ + +#define UX_DEMO_STACK_SIZE 4096 +#define UX_DEMO_BUFFER_SIZE 2048 +#define UX_DEMO_RUN 1 +#define UX_DEMO_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the demo application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + + +/* Define USBX demo global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DUMMY *dummy; +static UX_DEVICE_CLASS_DUMMY *dummy_slave; + +static UINT expected_error; + +#define _W0(w) ( (w) & 0xFF) +#define _W1(w) (((w) >> 8) & 0xFF) + +#define _DEVICE_DESCRIPTOR(cls, sub, protocol, pktsize, vid, pid, n_cfg) \ + 0x12, 0x01, 0x10, 0x01, \ + (cls), (sub), (protocol), (pktsize), \ + _W0(vid), _W1(vid), _W0(pid), _W1(pid), \ + 0x00, 0x00, 0x00, 0x00, 0x00, (n_cfg), + +#define _QUALIFIER_DESCRIPTOR(cls, sub, protocol, n_cfg) \ + 0x0a, 0x06, 0x00, 0x02, \ + (cls), (sub), (protocol), 0x40, (n_cfg), 0x00, + +#define _CONFIGURATION_DESCRIPTOR(total_len, n_ifc, cfg_val) \ + 0x09, 0x02, _W0(total_len), _W1(total_len), (n_ifc), (cfg_val), \ + 0x00, 0xc0, 0x32, + +#define _INTERFACE_DESCRIPTOR(ifc_n, alt, n_ep, cls, sub, protocol) \ + 0x09, 0x04, (ifc_n), (alt), (n_ep), (cls), (sub), (protocol), 0x00, + +#define _ENDPOINT_DESCRIPTOR(addr, attr, pktsize, interval) \ + 0x07, 0x05, (addr), (attr), _W0(pktsize), _W1(pktsize), (interval), + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +static UCHAR device_framework_full_speed[] = { + _DEVICE_DESCRIPTOR(0x99, 0x99, 0x99, 8, 0x08EC, 0x0001, 1) + _CONFIGURATION_DESCRIPTOR(32, 1, 1) + _INTERFACE_DESCRIPTOR(0, 0, 2, 0x99, 0x99, 0x99) + _ENDPOINT_DESCRIPTOR(0x01, 0x02, 64, 0x00) + _ENDPOINT_DESCRIPTOR(0x82, 0x02, 64, 0x00) +}; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) +static UCHAR device_framework_high_speed[] = { + _DEVICE_DESCRIPTOR(0x99, 0x99, 0x99, 64, 0x08EC, 0x0001, 1) + _QUALIFIER_DESCRIPTOR(0, 0, 0, 1) + _CONFIGURATION_DESCRIPTOR(32, 1, 1) + _INTERFACE_DESCRIPTOR(0, 0, 2, 0x99, 0x99, 0x99) + _ENDPOINT_DESCRIPTOR(0x01, 0x02, 512, 0x00) + _ENDPOINT_DESCRIPTOR(0x82, 0x02, 512, 0x00) +}; + +/* 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 sizeof(string_framework) +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* 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 sizeof(language_id_framework) +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID tx_demo_instance_activate(VOID *dummy_instance); +static VOID tx_demo_instance_deactivate(VOID *dummy_instance); + +#if defined(UX_HOST_STANDALONE) +static UINT tx_demo_host_change_function(ULONG e, UX_HOST_CLASS *c, VOID *p); +#else +#define tx_demo_host_change_function UX_NULL +#endif + +UINT ux_hcd_sim_initialize(UX_HCD *hcd); + +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); +static void tx_demo_thread_slave_simulation_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (expected_error == 0 || error_code != expected_error) + { + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %x\n", __LINE__, system_level, system_context, error_code); + // test_control_return(1); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_class_device_enumeration_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_DEVICE_CLASS_DUMMY_PARAMETER parameter; + + + printf("Running Basic Device Class Enumeration Test......................... "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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 #%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(tx_demo_host_change_function); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_host_class_dummy_name, _ux_host_class_dummy_device_entry); + + /* Check for error. */ + 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 */ + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + _ux_utility_memory_set((void *)¶meter, 0x00, sizeof(parameter)); + parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_instance_activate = tx_demo_instance_activate; + parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_instance_deactivate = tx_demo_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_device_class_dummy_name, _ux_device_class_dummy_entry, + 1, 0, ¶meter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%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 #%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 #%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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG actual_length; +UCHAR current_char; +UX_HOST_CLASS *cls; +UINT i; + + stepinfo(">>>>> Dummy Class Get\n"); + status = ux_host_stack_class_get(_ux_host_class_dummy_name, &cls); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>> Dummy Class Instance Wait\n"); + do + { + status = ux_host_stack_class_instance_get(cls, 0, (VOID **) &dummy); +#if defined(UX_HOST_STANDALONE) + ux_system_tasks_run(); +#endif + tx_thread_relinquish(); + } while (status != UX_SUCCESS); + + stepinfo(">>>>> Dummy Class State Wait\n"); + while(dummy -> ux_host_class_dummy_state != UX_HOST_CLASS_INSTANCE_LIVE) + { +#if defined(UX_HOST_STANDALONE) + ux_system_tasks_run(); +#endif + tx_thread_relinquish(); + } + + expected_error = 0; + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* DPUMP error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + + +static void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG actual_length; + + + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + + /* Run device tasks. */ + ux_system_tasks_run(); +#endif + /* Increment thread counter. */ + thread_1_counter++; + + /* Relinquish to other thread. */ + tx_thread_relinquish(); + } +} + +static VOID tx_demo_instance_activate(VOID *inst) +{ + dummy_slave = (UX_DEVICE_CLASS_DUMMY *)inst; +} + +static VOID tx_demo_instance_deactivate(VOID *inst) +{ + dummy_slave = UX_NULL; +} + +#if defined(UX_HOST_STANDALONE) +static UINT tx_demo_host_change_function(ULONG e, UX_HOST_CLASS *c, VOID *p) +{ + if (e == UX_STANDALONE_WAIT_BACKGROUND_TASK) + { + tx_thread_relinquish(); + } +} +#endif diff --git a/test/regression/usbx_class_hid_basic_memory_test.c b/test/regression/usbx_class_hid_basic_memory_test.c new file mode 100644 index 00000000..6703dc40 --- /dev/null +++ b/test/regression/usbx_class_hid_basic_memory_test.c @@ -0,0 +1,840 @@ +/* This file tests the ux_device_class_hid API. */ + +#include "usbx_test_common_hid.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#include "ux_host_class_hid_mouse.h" +#include "ux_host_class_hid_keyboard.h" +#include "ux_host_class_hid_remote_control.h" + + +static UCHAR hid_keyboard_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0, // END_COLLECTION + + 0xa1, 0x01, // COLLECTION (Application) + 0x19, 0x01, // USAGE_MINIMUM (1) + 0x29, 0x04, // USAGE_MAXIMUM (4) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x04, // REPORT_COUNT (4) + 0xb1, 0x02, // FEATURE (Data,Var,Abs) + 0x85, 0x02, // REPORT_ID (2) + 0x19, 0x05, // USAGE_MINIMUM (5) + 0x29, 0x07, // USAGE_MAXIMUM (7) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x03, // REPORT_COUNT (3) + 0xb1, 0x02, // FEATURE (Data,Var,Abs) + 0x85, 0x04, // REPORT_ID (4) + 0x09, 0x08, // USAGE (8) + 0x75, 0x10, // REPORT_SIZE (16) + 0x95, 0x01, // REPORT_COUNT (1) + 0xb1, 0x02, // FEATURE (Data,Var,Abs) + 0xc0, // END_COLLECTION +}; +#define HID_KEYBOARD_REPORT_LENGTH sizeof(hid_keyboard_report)/sizeof(hid_keyboard_report[0]) + + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +static UCHAR hid_remote_control_report[] = { + + 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) + 0x09, 0x01, // USAGE (Consumer Control) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x02, // USAGE (Numeric Key Pad) + 0xa1, 0x02, // COLLECTION (Logical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x0a, // USAGE_MAXIMUM (Button 10) + 0x15, 0x01, // LOGICAL_MINIMUM (1) + 0x25, 0x0a, // LOGICAL_MAXIMUM (10) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0, // END_COLLECTION + 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) + 0x09, 0x86, // USAGE (Channel) + 0x09, 0xe0, // USAGE (Volume) + 0x15, 0xff, // LOGICAL_MINIMUM (-1) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x02, // REPORT_SIZE (2) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x46, // INPUT (Data,Var,Rel,Null) + 0xc0 // END_COLLECTION +}; +#define HID_REMOTE_CONTROL_REPORT_LENGTH (sizeof(hid_remote_control_report)/sizeof(hid_remote_control_report[0])) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN (9) + + +/* HID Mouse/Keyboard interface descriptors 9+9+7=25 bytes */ +#define HID_IFC_DESC_ALL(ifc, report_len, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(report_len),\ + MSB(report_len),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_IFC_DESC_ALL_LEN (9+9+7) + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC(CFG_DESC_LEN+3*HID_IFC_DESC_ALL_LEN, 2, 1) + /* Keyboard */ + HID_IFC_DESC_ALL(0, HID_KEYBOARD_REPORT_LENGTH, 0x82) + /* Mouse */ + HID_IFC_DESC_ALL(1, HID_MOUSE_REPORT_LENGTH, 0x81) + /* Remote control */ + HID_IFC_DESC_ALL(2, HID_REMOTE_CONTROL_REPORT_LENGTH, 0x83) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC(CFG_DESC_LEN+3*HID_IFC_DESC_ALL_LEN, 2, 1) + /* Keyboard */ + HID_IFC_DESC_ALL(0, HID_KEYBOARD_REPORT_LENGTH, 0x82) + /* Mouse */ + HID_IFC_DESC_ALL(1, HID_MOUSE_REPORT_LENGTH, 0x81) + /* Remote control */ + HID_IFC_DESC_ALL(2, HID_REMOTE_CONTROL_REPORT_LENGTH, 0x83) +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +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 +}; +#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. */ +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +static UX_HOST_CLASS_HID *hid = UX_NULL; +static UX_HOST_CLASS_HID_MOUSE *hid_mouse = UX_NULL; +static UX_HOST_CLASS_HID_KEYBOARD *hid_keyboard = UX_NULL; +static UX_HOST_CLASS_HID_REMOTE_CONTROL *hid_remote_control = UX_NULL; + +static UX_SLAVE_CLASS_HID *hid_mouse_slave = UX_NULL; +static UX_SLAVE_CLASS_HID *hid_keyboard_slave = UX_NULL; +static UX_SLAVE_CLASS_HID *hid_remote_control_slave = UX_NULL; + +static UX_SLAVE_CLASS_HID_PARAMETER hid_mouse_parameter; +static UX_SLAVE_CLASS_HID_PARAMETER hid_keyboard_parameter; +static UX_SLAVE_CLASS_HID_PARAMETER hid_remote_control_parameter; + +static ULONG rsc_mem_alloc_cnt_on_set_cfg; +static ULONG rsc_enum_mem_alloc_count; +static ULONG rsc_hid_mem_alloc_count; + +static ULONG error_callback_counter; +static UCHAR error_callback_ignore; + +static ULONG error_counter = 0; + +static UINT _is_mouse(UX_HOST_CLASS_HID_CLIENT *client) +{ + return(UX_SUCCESS == _ux_utility_memory_compare(client->ux_host_class_hid_client_name, + _ux_system_host_class_hid_client_mouse_name, + _ux_utility_string_length_get(_ux_system_host_class_hid_client_mouse_name))); +} +static UINT _is_keyboard(UX_HOST_CLASS_HID_CLIENT *client) +{ + return(UX_SUCCESS == _ux_utility_memory_compare(client->ux_host_class_hid_client_name, + _ux_system_host_class_hid_client_keyboard_name, + _ux_utility_string_length_get(_ux_system_host_class_hid_client_keyboard_name))); +} +static UINT ux_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_HID_CLIENT *client = (UX_HOST_CLASS_HID_CLIENT *)inst; + + // if(event >= UX_HID_CLIENT_INSERTION) printf("hChg: ev %lx, cls %p, inst %p, %s\n", event, cls, inst, _is_mouse(client) ? "Mouse" : _is_keyboard(client) ? "Keyboard" : "Remote Control"); + switch(event) + { + + case UX_HID_CLIENT_INSERTION: + if (_is_mouse(client)) + hid_mouse = (UX_HOST_CLASS_HID_MOUSE *)client->ux_host_class_hid_client_local_instance; + else + { + if (_is_keyboard(client)) + hid_keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)client->ux_host_class_hid_client_local_instance; + else + hid_remote_control = (UX_HOST_CLASS_HID_REMOTE_CONTROL *)client->ux_host_class_hid_client_local_instance; + } + break; + + case UX_HID_CLIENT_REMOVAL: + if (_is_mouse(client)) + hid_mouse = UX_NULL; + else + { + if (_is_keyboard(client)) + hid_keyboard = UX_NULL; + else + hid_remote_control = UX_NULL; + } + break; + + default: + break; + } + return 0; +} + +static VOID mouse_instance_activate_callback(VOID *parameter) +{ + // printf("dMouse: %p\n", parameter); + hid_mouse_slave = (UX_SLAVE_CLASS_HID *)parameter; +} + +static VOID keyboard_instance_activate_callback(VOID *parameter) +{ + // printf("dKeyboard: %p\n", parameter); + hid_keyboard_slave = (UX_SLAVE_CLASS_HID *)parameter; +} + +static VOID remote_control_instance_activate_callback(VOID *parameter) +{ + // printf("dKeyboard: %p\n", parameter); + hid_remote_control_slave = (UX_SLAVE_CLASS_HID *)parameter; +} + +static VOID instance_deactivate_callback(VOID *parameter) +{ + // printf("dRm: %p\n", parameter); + if ((VOID *)hid_mouse_slave == parameter) + hid_mouse_slave = UX_NULL; + + if ((VOID *)hid_keyboard_slave == parameter) + hid_keyboard_slave = UX_NULL; + + if ((VOID *)hid_remote_control_slave == parameter) + hid_remote_control_slave = UX_NULL; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (error_code == UX_MEMORY_INSUFFICIENT) + error_callback_counter ++; + // printf("ERROR #%d: 0x%x, 0x%x, 0x%x\n", __LINE__, system_level, system_context, error_code); +} + +static UINT break_on_all_activated(VOID) +{ + + if (hid_mouse_slave == UX_NULL) + return 0; + if (hid_keyboard_slave == UX_NULL) + return 0; + if (hid_remote_control_slave == UX_NULL) + return 0; + if (hid_mouse == UX_NULL) + return 0; + if (hid_keyboard == UX_NULL) + return 0; + if (hid_remote_control == UX_NULL) + return 0; + + return 1; +} + + +static UINT break_on_all_removed(VOID) +{ + if (hid_mouse_slave || hid_keyboard_slave || hid_remote_control_slave) + return 0; + if (hid_mouse || hid_keyboard || hid_remote_control) + return 0; + + return 1; +} + + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *_params) +{ + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); +} + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_hid_basic_memory_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +ULONG mem_free; +ULONG alloc_count; +ULONG test_n; + + /* Inform user. */ + printf("Running UX Class HID Basic Memory test ............................. "); + stepinfo("\n"); + + /* Initialize memory logger. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + + /* 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 #%d, code 0x%x\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + 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 #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Register the HID client(s). */ + status |= ux_host_class_hid_client_register(_ux_system_host_class_hid_client_mouse_name, ux_host_class_hid_mouse_entry); + status |= ux_host_class_hid_client_register(_ux_system_host_class_hid_client_keyboard_name, ux_host_class_hid_keyboard_entry); + status |= ux_host_class_hid_client_register(_ux_system_host_class_hid_client_remote_control_name, ux_host_class_hid_remote_control_entry); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if (status != UX_SUCCESS) + { + + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } +#endif + + /* 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, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Initialize the hid class parameters for mouse and keyboard. */ + hid_mouse_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_mouse_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_REPORT_LENGTH; + hid_mouse_parameter.ux_device_class_hid_parameter_callback = demo_thread_hid_callback; + hid_mouse_parameter.ux_slave_class_hid_instance_activate = mouse_instance_activate_callback; + hid_mouse_parameter.ux_slave_class_hid_instance_deactivate = instance_deactivate_callback; + + hid_keyboard_parameter.ux_device_class_hid_parameter_report_address = hid_keyboard_report; + hid_keyboard_parameter.ux_device_class_hid_parameter_report_length = HID_KEYBOARD_REPORT_LENGTH; + hid_keyboard_parameter.ux_device_class_hid_parameter_callback = demo_thread_hid_callback; + hid_keyboard_parameter.ux_slave_class_hid_instance_activate = keyboard_instance_activate_callback; + hid_keyboard_parameter.ux_slave_class_hid_instance_deactivate = instance_deactivate_callback; + + hid_remote_control_parameter.ux_device_class_hid_parameter_report_address = hid_remote_control_report; + hid_remote_control_parameter.ux_device_class_hid_parameter_report_length = HID_REMOTE_CONTROL_REPORT_LENGTH; + hid_remote_control_parameter.ux_device_class_hid_parameter_callback = demo_thread_hid_callback; + hid_remote_control_parameter.ux_slave_class_hid_instance_activate = remote_control_instance_activate_callback; + hid_remote_control_parameter.ux_slave_class_hid_instance_deactivate = instance_deactivate_callback; + + stepinfo(">>>>>>>>>> Test HID Class Initialize/deinitialize memory\n"); + + stepinfo(">>>>>>>>>> - Reset counts\n"); + ux_test_utility_sim_mem_alloc_count_reset(); + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + stepinfo(">>>>>>>>>> - _class_register\n"); + + /* Initilize the device hid class. */ + status = ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,1, (VOID *)&hid_mouse_parameter); + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,0, (VOID *)&hid_keyboard_parameter); + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,2, (VOID *)&hid_remote_control_parameter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } +#endif +#if 1 + /* Log create counts when instances active for further tests. */ + alloc_count = ux_test_utility_sim_mem_alloc_count(); + + /* Lock log base for tests. */ + ux_test_utility_sim_mem_alloc_log_lock(); + + stepinfo("init & uninit alloc : %ld\n", alloc_count); + stepinfo("mem free : %ld, %ld\n", _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); + + if (alloc_count) stepinfo(">>>>>>>>>> - Init/deinit memory errors test\n"); + mem_free = (~0); + for (test_n = 0; test_n < alloc_count; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, alloc_count - 1); + + /* Unregister. */ + ux_device_stack_class_unregister(_ux_system_slave_class_hid_name, ux_device_class_hid_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_hid_name, ux_device_class_hid_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_hid_name, ux_device_class_hid_entry); + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + error_counter ++; + test_control_return(1); + } + + /* Set memory error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n); + + /* Register. */ + status = ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,1, (VOID *)&hid_mouse_parameter); + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,0, (VOID *)&hid_keyboard_parameter); + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,2, (VOID *)&hid_remote_control_parameter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + /* Check error */ + if (status == UX_SUCCESS) + { + + printf("ERROR #%d.%ld: registered when there is memory error\n", __LINE__, test_n); + error_counter ++; + } +#endif + + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + } + ux_test_utility_sim_mem_alloc_error_generation_stop(); + if (alloc_count) stepinfo("\n"); + + /* Unregister. */ + ux_device_stack_class_unregister(_ux_system_slave_class_hid_name, ux_device_class_hid_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_hid_name, ux_device_class_hid_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_hid_name, ux_device_class_hid_entry); + + /* Register. */ + status = ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,1, (VOID *)&hid_mouse_parameter); + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,0, (VOID *)&hid_keyboard_parameter); + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,2, (VOID *)&hid_remote_control_parameter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } +#endif +#endif + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + 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 #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + +#if defined(UX_DEVICE_STANDALONE) + + /* Create the main device simulation thread. */ + status = tx_thread_create(&tx_demo_thread_device_simulation, "tx demo device simulation", tx_demo_thread_device_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } +#endif +} + +#if defined(UX_DEVICE_STANDALONE) +static void tx_demo_thread_device_simulation_entry(ULONG arg) +{ + while(1) + { + ux_system_tasks_run(); + tx_thread_relinquish(); + } +} +#endif + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_DEVICE *device; +ULONG mem_free; +ULONG alloc_count; +ULONG test_n; +UX_HCD *hcd; + + + stepinfo(">>>>>>>>>> Thread start\n"); + + hcd = &_ux_system_host->ux_system_host_hcd_array[0]; + + ux_test_breakable_sleep(500, break_on_all_activated); + + /* Get device instance. */ + status = ux_host_stack_device_get(0, &device); + + if (status != UX_SUCCESS) + { + printf("ERROR #%d: get_device fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>> Disconnect\n"); + + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + if (hid_keyboard || hid_mouse) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>> Reset counts\n"); + + ux_test_utility_sim_mem_alloc_count_reset(); + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + rsc_mem_alloc_cnt_on_set_cfg = 0; + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + + stepinfo(">>>>>>>>>> Connect\n"); + + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + ux_test_breakable_sleep(500, break_on_all_activated); + + /* Log create counts for further tests. */ + rsc_enum_mem_alloc_count = rsc_mem_alloc_cnt_on_set_cfg; + + /* Log create counts when instances active for further tests. */ + alloc_count = ux_test_utility_sim_mem_alloc_count(); + + /* Lock log base for tests. */ + ux_test_utility_sim_mem_alloc_log_lock(); + + rsc_hid_mem_alloc_count = alloc_count - rsc_enum_mem_alloc_count; + + stepinfo("enum mem: %ld\n", rsc_enum_mem_alloc_count); + stepinfo("hid mem : %ld\n", rsc_hid_mem_alloc_count); + stepinfo("mem free: %ld, %ld\n", _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); + + if (hid_mouse == UX_NULL +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + || hid_keyboard == UX_NULL +#endif + ) + { + printf("ERROR #%d: %p %p\n", __LINE__, hid_keyboard, hid_mouse); + test_control_return(1); + } + + /* Simulate detach and attach for FS enumeration, + and test possible memory allocation error handlings. + */ + if (rsc_hid_mem_alloc_count) stepinfo(">>>>>>>>>> Memory errors enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_hid_mem_alloc_count; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_hid_mem_alloc_count - 1); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check number of devices. */ + if (hcd->ux_hcd_nb_devices != 0) + { + printf("ERROR #%d.%ld: number of devices (%d) must be 0\n", __LINE__, test_n, hcd->ux_hcd_nb_devices); + error_counter ++; + } + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + error_counter ++; + test_control_return(1); + } + + /* Set memory error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n + rsc_enum_mem_alloc_count); + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); +#if 1 /* @nick */ + ux_test_hcd_sim_host_connect_no_wait(UX_FULL_SPEED_DEVICE); + + /* Wait for enum thread to complete. */ + ux_test_wait_for_enum_thread_completion(); +#else + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on errors. */ + ux_test_breakable_sleep(400, sleep_break_on_error); +#endif + + /* Check error */ + if (hid_mouse && hid_keyboard && hid_mouse_slave && hid_keyboard_slave && hid_remote_control && hid_remote_control_slave) + { + + printf("ERROR #%d.%ld: device detected when there is memory error\n", __LINE__, test_n); + error_counter ++; + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + ux_test_utility_sim_mem_alloc_error_generation_stop(); + } + if (alloc_count) stepinfo("\n"); + + stepinfo(">>>>>>>>>> Test done\n"); + + /* 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(); + + if (error_counter) + { + printf("FAIL %ld errors!\n", error_counter); + test_control_return(1); + } + + /* 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_class_hid_basic_test.c b/test/regression/usbx_class_hid_basic_test.c new file mode 100644 index 00000000..5b114adb --- /dev/null +++ b/test/regression/usbx_class_hid_basic_test.c @@ -0,0 +1,610 @@ +/* This file tests basic HID functionalities. */ + +#include "usbx_test_common_hid.h" + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_keyboard_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + + 0xc0 // END_COLLECTION +}; +#define HID_KEYBOARD_REPORT_LENGTH sizeof(hid_keyboard_report)/sizeof(hid_keyboard_report[0]) + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x85, 0x01, // REPORT_ID (1) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + + 0x19, 0x01, // USAGE_MINIMUM (1) + 0x29, 0x04, // USAGE_MAXIMUM (4) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x04, // REPORT_COUNT (4) + 0xb1, 0x02, // FEATURE (Data,Var,Abs) + + 0x85, 0x02, // REPORT_ID (2) + 0x19, 0x05, // USAGE_MINIMUM (5) + 0x29, 0x07, // USAGE_MAXIMUM (7) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x03, // REPORT_COUNT (3) + 0xb1, 0x02, // FEATURE (Data,Var,Abs) + + 0x85, 0x04, // REPORT_ID (4) + 0x09, 0x08, // USAGE (8) + 0x75, 0x10, // REPORT_SIZE (16) + 0x95, 0x01, // REPORT_COUNT (1) + 0xb1, 0x02, // FEATURE (Data,Var,Abs) + + /* USBX requires at least one input report. */ + 0x09, 0x01, // USAGE (1) + 0x75, 0x10, // REPORT_SIZE (16) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* USBX expects keyboards to have at least one output report, otherwise it's an error. */ + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + + 0xc0, // END_COLLECTION +}; +#define HID_REPORT_LENGTH sizeof(hid_report_descriptor)/sizeof(hid_report_descriptor[0]) + + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN (9) + + +/* HID Mouse/Keyboard interface descriptors 9+9+7=25 bytes */ +#define HID_IFC_DESC_ALL(ifc, report_len, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(report_len),\ + MSB(report_len),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_IFC_DESC_ALL_LEN (9+9+7) + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC(CFG_DESC_LEN+1*HID_IFC_DESC_ALL_LEN, 1, 1) + /* Keyboard */ + HID_IFC_DESC_ALL(0, HID_REPORT_LENGTH, 0x81) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC(CFG_DESC_LEN+1*HID_IFC_DESC_ALL_LEN, 1, 1) + /* Keyboard */ + HID_IFC_DESC_ALL(0, HID_REPORT_LENGTH, 0x81) +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +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 +}; +#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. */ +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + switch(event) + { + case UX_HID_CLIENT_INSERTION: + break; + case UX_HID_CLIENT_REMOVAL: + break; +#if defined(UX_HOST_STANDALONE) + case UX_STANDALONE_WAIT_BACKGROUND_TASK: + /* Let other threads to run. */ + tx_thread_relinquish(); + break; +#endif + default: + break; + } + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_class_hid_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running HID Class Basic 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* No client registered, just HID. */ + + /* 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, error code: %d\n", __LINE__, status); + 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_set_callback; + hid_parameter.ux_device_class_hid_parameter_get_callback = demo_thread_hid_get_callback; + + hid_parameter.ux_slave_class_hid_instance_activate = demo_device_hid_instance_activate; + hid_parameter.ux_slave_class_hid_instance_deactivate = demo_device_hid_instance_deactivate; + + /* 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, 0, (VOID *)&hid_parameter); + if(status!=UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Create the main device simulation thread. */ + status = tx_thread_create(&tx_demo_thread_device_simulation, "tx demo device simulation", tx_demo_thread_device_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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + stack_pointer += UX_DEMO_STACK_SIZE; + + /* 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_device_simulation_entry(ULONG arg) +{ + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); +#else + tx_thread_suspend(&tx_demo_thread_device_simulation); +#endif + } +} + +static UINT demo_wait(ULONG tick, UINT (*check)()) +{ +ULONG t0, t1; +UINT status; + + t0 = tx_time_get(); + while(1) + { +#if defined(UX_HOST_STANDALONE) + ux_system_tasks_run(); +#endif + if (check) + { + status = check(); + if (status == UX_SUCCESS) + break; + } + t1 = tx_time_get(); + if (_ux_utility_time_elapsed(t0, t1) >= tick) + { + return(UX_TIMEOUT); + } + } + return(UX_SUCCESS); +} + +static UINT demo_class_hid_wait(ULONG tick) +{ + return(demo_wait(tick, demo_class_hid_get)); +} + +static void test_hid_idle_requests(VOID) +{ +USHORT idle_time; +UINT status; +INT i; +#define N_TEST_IDLES 4 +USHORT test_idles[N_TEST_IDLES] = {1, 8, 20, 0}; +ULONG mem_level = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + + /* Get input report. */ + hid_report_id.ux_host_class_hid_report_get_report = UX_NULL; + hid_report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = _ux_host_class_hid_report_id_get(hid, &hid_report_id); + UX_TEST_ASSERT(status == UX_SUCCESS); + + status = _ux_host_class_hid_idle_get(hid, &idle_time, hid_report_id.ux_host_class_hid_report_get_id); + UX_TEST_ASSERT(status == UX_SUCCESS); + test_idles[N_TEST_IDLES - 1] = idle_time; + + for (i = 0; i < N_TEST_IDLES; i ++) + { + status = _ux_host_class_hid_idle_set(hid, test_idles[i], hid_report_id.ux_host_class_hid_report_get_id); + UX_TEST_ASSERT(status == UX_SUCCESS); + status = _ux_host_class_hid_idle_get(hid, &idle_time, hid_report_id.ux_host_class_hid_report_get_id); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(idle_time == test_idles[i]); + } + + UX_TEST_ASSERT(mem_level == _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); +} + +static void test_hid_report_requests(VOID) +{ +ULONG tmp_bytes[2]; +UINT status; +INT i; +#define N_TEST_REPORT_REQS 5 +ULONG mem_level = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + /* Get output report. */ + hid_report_id.ux_host_class_hid_report_get_report = UX_NULL; + hid_report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_FEATURE; + status = _ux_host_class_hid_report_id_get(hid, &hid_report_id); + UX_TEST_ASSERT(status == UX_SUCCESS); + + /* Memorize the report pointer. */ + client_report.ux_host_class_hid_client_report = hid_report_id.ux_host_class_hid_report_get_report; + + /* The report set is raw since the LEDs mask is already in the right format. */ + client_report.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_RAW; + + /* The length of this report is 2 byte (16 bits). */ + client_report.ux_host_class_hid_client_report_length = 2; + + /* The output report buffer is the LED mask field. */ + client_report.ux_host_class_hid_client_report_buffer = tmp_bytes; + + for (i = 0; i < N_TEST_REPORT_REQS; i ++) + { + _ux_utility_memory_set(tmp_bytes, i, sizeof(tmp_bytes)); + status = _ux_host_class_hid_report_set(hid, &client_report); + UX_TEST_ASSERT(status == UX_SUCCESS); + + _ux_utility_memory_set(tmp_bytes, 0xFF, sizeof(tmp_bytes)); + status = _ux_host_class_hid_report_get(hid, &client_report); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "0x%x\n", status); + UX_TEST_ASSERT(*(UCHAR *)tmp_bytes == i); + } + + UX_TEST_ASSERT(mem_level == _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); +} + +static ULONG test_hid_report_callback_count = 0; +static ULONG test_hid_report_callback_wait = 0; +static VOID test_hid_report_callback(UX_HOST_CLASS_HID_REPORT_CALLBACK *callback) +{ + test_hid_report_callback_count ++; +} +static UINT test_hid_report_callback_count_check(VOID) +{ + return(test_hid_report_callback_count >= test_hid_report_callback_wait ? + UX_SUCCESS : UX_ERROR); +} +static void test_hid_periodic_reports(VOID) +{ +UINT status; +ULONG mem_level; + + /* Get input report. */ + hid_report_id.ux_host_class_hid_report_get_report = UX_NULL; + hid_report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = _ux_host_class_hid_report_id_get(hid, &hid_report_id); + UX_TEST_ASSERT(status == UX_SUCCESS); + + /* Initialize the report callback. */ + hid_report_callback.ux_host_class_hid_report_callback_id = hid_report_id.ux_host_class_hid_report_get_id; + hid_report_callback.ux_host_class_hid_report_callback_function = test_hid_report_callback; + hid_report_callback.ux_host_class_hid_report_callback_buffer = UX_NULL; + hid_report_callback.ux_host_class_hid_report_callback_flags = UX_HOST_CLASS_HID_REPORT_RAW; + hid_report_callback.ux_host_class_hid_report_callback_length = hid_report_id.ux_host_class_hid_report_get_report->ux_host_class_hid_report_byte_length; + + /* Register the report call back when data comes it on this report. */ + status = _ux_host_class_hid_report_callback_register(hid, &hid_report_callback); + UX_TEST_ASSERT(status == UX_SUCCESS); + + /* Start background report reading. */ + _ux_host_class_hid_periodic_report_start(hid); + + mem_level = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + device_hid_event.ux_device_class_hid_event_length = 4; + device_hid_event.ux_device_class_hid_event_buffer[0] = 0; + device_hid_event.ux_device_class_hid_event_buffer[1] = 0; + device_hid_event.ux_device_class_hid_event_buffer[2] = '0'; + device_hid_event.ux_device_class_hid_event_buffer[3] = '1'; + + test_hid_report_callback_count = 0; + test_hid_report_callback_wait = 1; + _ux_device_class_hid_event_set(device_hid, &device_hid_event); + demo_wait(10, test_hid_report_callback_count_check); + UX_TEST_ASSERT(test_hid_report_callback_count == 1); + + test_hid_report_callback_count = 0; + test_hid_report_callback_wait = 2; + _ux_device_class_hid_event_set(device_hid, &device_hid_event); + _ux_device_class_hid_event_set(device_hid, &device_hid_event); + demo_wait(10, test_hid_report_callback_count_check); + UX_TEST_ASSERT(test_hid_report_callback_count == 2); + + UX_TEST_ASSERT(mem_level == _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; + + /* Find the HID class */ + status = demo_class_hid_wait(100); + UX_TEST_ASSERT(status == UX_SUCCESS); + + + test_hid_idle_requests(); + test_hid_report_requests(); + test_hid_periodic_reports(); + + /* 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_set_callback(UX_SLAVE_CLASS_HID *class, UX_SLAVE_CLASS_HID_EVENT *event) +{ + _ux_utility_memory_copy(&device_hid_event, event, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + return(UX_SUCCESS); +} +static UINT demo_thread_hid_get_callback(UX_SLAVE_CLASS_HID *class, UX_SLAVE_CLASS_HID_EVENT *event) +{ + _ux_utility_memory_copy(event, &device_hid_event, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + return(UX_SUCCESS); +} + +static void demo_device_hid_instance_activate(VOID *inst) +{ + if (device_hid == UX_NULL) + device_hid = (UX_SLAVE_CLASS_HID *)inst; +} +static void demo_device_hid_instance_deactivate(VOID *inst) +{ + if (inst == (VOID *)device_hid) + device_hid = UX_NULL; +} diff --git a/test/regression/usbx_class_hid_keyboard_basic_test.c b/test/regression/usbx_class_hid_keyboard_basic_test.c new file mode 100644 index 00000000..a1ae34b8 --- /dev/null +++ b/test/regression/usbx_class_hid_keyboard_basic_test.c @@ -0,0 +1,493 @@ +/* This file tests basic HID functionalities. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_keyboard_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + + 0xc0 // END_COLLECTION +}; +#define HID_KEYBOARD_REPORT_LENGTH sizeof(hid_keyboard_report)/sizeof(hid_keyboard_report[0]) + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x85, 0x01, // REPORT_ID (1) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +#define hid_report_descriptor hid_keyboard_report +#define HID_REPORT_LENGTH HID_KEYBOARD_REPORT_LENGTH + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN (9) + + +/* HID Mouse/Keyboard interface descriptors 9+9+7=25 bytes */ +#define HID_IFC_DESC_ALL(ifc, report_len, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(report_len),\ + MSB(report_len),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_IFC_DESC_ALL_LEN (9+9+7) + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC(CFG_DESC_LEN+1*HID_IFC_DESC_ALL_LEN, 1, 1) + /* Keyboard */ + HID_IFC_DESC_ALL(0, HID_REPORT_LENGTH, 0x81) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC(CFG_DESC_LEN+1*HID_IFC_DESC_ALL_LEN, 1, 1) + /* Keyboard */ + HID_IFC_DESC_ALL(0, HID_REPORT_LENGTH, 0x81) +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +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 +}; +#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. */ +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + switch(event) + { + case UX_HID_CLIENT_INSERTION: + break; + case UX_HID_CLIENT_REMOVAL: + break; +#if defined(UX_HOST_STANDALONE) + case UX_STANDALONE_WAIT_BACKGROUND_TASK: + /* Let other threads to run. */ + tx_thread_relinquish(); + break; +#endif + default: + break; + } + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_class_hid_keyboard_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running HID Class Keyboard Basic 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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: 0x%x\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, error code: %d\n", __LINE__, status); + 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_set_callback; + hid_parameter.ux_device_class_hid_parameter_get_callback = demo_thread_hid_get_callback; + + hid_parameter.ux_slave_class_hid_instance_activate = demo_device_hid_instance_activate; + hid_parameter.ux_slave_class_hid_instance_deactivate = demo_device_hid_instance_deactivate; + + /* 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, 0, (VOID *)&hid_parameter); + if(status!=UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Create the main device simulation thread. */ + status = tx_thread_create(&tx_demo_thread_device_simulation, "tx demo device simulation", tx_demo_thread_device_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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + stack_pointer += UX_DEMO_STACK_SIZE; + + /* 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_device_simulation_entry(ULONG arg) +{ + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); +#else + tx_thread_suspend(&tx_demo_thread_device_simulation); +#endif + } +} + +static UINT demo_class_hid_wait(ULONG tick) +{ + return(ux_test_sleep_break_on_success(tick, demo_class_hid_keyboard_get)); +} + +static UINT _wait_key(UX_HOST_CLASS_HID_KEYBOARD *keyboard, ULONG *keyboard_key, ULONG *keyboard_state) +{ + +UINT status; +UINT i; + + + for(i = 0; i < 200; i ++) + { +#if defined(UX_HOST_STANDALONE) + ux_system_tasks_run(); +#endif + status = ux_host_class_hid_keyboard_key_get(keyboard, keyboard_key, keyboard_state); + if (status == UX_SUCCESS) + { + // printf("Key: %lx,%lx\n", *keyboard_key, *keyboard_state); + +#if defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE_REPORT_LOCK_KEYS) || defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE_REPORT_MODIFIER_KEYS) + if (*keyboard_state & UX_HID_KEYBOARD_STATE_FUNCTION) + continue; +#endif + +#if !defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE_REPORT_KEY_DOWN_ONLY) + if (*keyboard_state & UX_HID_KEYBOARD_STATE_KEY_UP) + continue; +#endif + return UX_SUCCESS; + } + _ux_utility_delay_ms(1); + } + return UX_ERROR; +} + + +static void test_hid_keyboard_keys(VOID) +{ +UINT status; +ULONG keyboard_key; +ULONG keyboard_state; + + /* Initialize key event. */ + device_hid_event.ux_device_class_hid_event_length = 4; + device_hid_event.ux_device_class_hid_event_buffer[0] = 0; /* Modifier. */ + device_hid_event.ux_device_class_hid_event_buffer[1] = 0; /* Reserved. */ + device_hid_event.ux_device_class_hid_event_buffer[2] = 0; /* Key ...... */ + device_hid_event.ux_device_class_hid_event_buffer[3] = 0; /* Key ...... */ + + /* Set modifier + key. */ + device_hid_event.ux_device_class_hid_event_buffer[0] = 1; /* Left CTRL */ + device_hid_event.ux_device_class_hid_event_buffer[2] = 4; /* a */ + _ux_device_class_hid_event_set(device_hid, &device_hid_event); + status = _wait_key(hid_keyboard, &keyboard_key, &keyboard_state); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(keyboard_state & UX_HID_KEYBOARD_STATE_LEFT_CTRL); + UX_TEST_ASSERT(keyboard_key == 'a'); + + /* Set modifier + key. */ + device_hid_event.ux_device_class_hid_event_buffer[0] = (1 << 5); /* Right SHIFT */ + device_hid_event.ux_device_class_hid_event_buffer[2] = 5; /* b -> B */ + _ux_device_class_hid_event_set(device_hid, &device_hid_event); + status = _wait_key(hid_keyboard, &keyboard_key, &keyboard_state); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(keyboard_state & UX_HID_KEYBOARD_STATE_RIGHT_SHIFT); + UX_TEST_ASSERT(keyboard_key == 'B'); + + /* Send CAPS_Lock. */ + device_hid_event.ux_device_class_hid_event_buffer[0] = 0; + device_hid_event.ux_device_class_hid_event_buffer[2] = UX_HID_LED_KEY_CAPS_LOCK; + _ux_device_class_hid_event_set(device_hid, &device_hid_event); + device_hid_event.ux_device_class_hid_event_buffer[0] = 0; + device_hid_event.ux_device_class_hid_event_buffer[2] = 6; /* c -> C */ + _ux_device_class_hid_event_set(device_hid, &device_hid_event); + status = _wait_key(hid_keyboard, &keyboard_key, &keyboard_state); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(keyboard_state & UX_HID_KEYBOARD_STATE_CAPS_LOCK); + UX_TEST_ASSERT(keyboard_key == 'C'); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; + + /* Find the HID class */ + status = demo_class_hid_wait(100); + UX_TEST_ASSERT(status == UX_SUCCESS); + + test_hid_keyboard_keys(); + + /* 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_set_callback(UX_SLAVE_CLASS_HID *class, UX_SLAVE_CLASS_HID_EVENT *event) +{ + _ux_utility_memory_copy(&device_hid_event, event, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + return(UX_SUCCESS); +} +static UINT demo_thread_hid_get_callback(UX_SLAVE_CLASS_HID *class, UX_SLAVE_CLASS_HID_EVENT *event) +{ + _ux_utility_memory_copy(event, &device_hid_event, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + return(UX_SUCCESS); +} + +static void demo_device_hid_instance_activate(VOID *inst) +{ + if (device_hid == UX_NULL) + device_hid = (UX_SLAVE_CLASS_HID *)inst; +} +static void demo_device_hid_instance_deactivate(VOID *inst) +{ + if (inst == (VOID *)device_hid) + device_hid = UX_NULL; +} diff --git a/test/regression/usbx_class_hid_mouse_basic_test.c b/test/regression/usbx_class_hid_mouse_basic_test.c new file mode 100644 index 00000000..16d547ac --- /dev/null +++ b/test/regression/usbx_class_hid_mouse_basic_test.c @@ -0,0 +1,530 @@ +/* This file tests basic HID functionalities. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_keyboard_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + + 0xc0 // END_COLLECTION +}; +#define HID_KEYBOARD_REPORT_LENGTH sizeof(hid_keyboard_report)/sizeof(hid_keyboard_report[0]) + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +#define hid_report_descriptor hid_mouse_report +#define HID_REPORT_LENGTH HID_MOUSE_REPORT_LENGTH + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN (9) + + +/* HID Mouse/Keyboard interface descriptors 9+9+7=25 bytes */ +#define HID_IFC_DESC_ALL(ifc, report_len, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(report_len),\ + MSB(report_len),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_IFC_DESC_ALL_LEN (9+9+7) + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC(CFG_DESC_LEN+1*HID_IFC_DESC_ALL_LEN, 1, 1) + /* Keyboard */ + HID_IFC_DESC_ALL(0, HID_REPORT_LENGTH, 0x81) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC(CFG_DESC_LEN+1*HID_IFC_DESC_ALL_LEN, 1, 1) + /* Keyboard */ + HID_IFC_DESC_ALL(0, HID_REPORT_LENGTH, 0x81) +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +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 +}; +#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. */ +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + switch(event) + { + case UX_HID_CLIENT_INSERTION: + break; + case UX_HID_CLIENT_REMOVAL: + break; +#if defined(UX_HOST_STANDALONE) + case UX_STANDALONE_WAIT_BACKGROUND_TASK: + /* Let other threads to run. */ + tx_thread_relinquish(); + break; +#endif + default: + break; + } + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_class_hid_mouse_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running HID Class Mouse Basic 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Register the HID client(s). */ + status = ux_host_class_hid_client_register(_ux_system_host_class_hid_client_mouse_name, ux_host_class_hid_mouse_entry); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Initialize the hid class parameters. */ + ux_utility_memory_set(&hid_parameter, 0, sizeof(hid_parameter)); + 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_set_callback; + hid_parameter.ux_device_class_hid_parameter_get_callback = demo_thread_hid_get_callback; + + hid_parameter.ux_slave_class_hid_instance_activate = demo_device_hid_instance_activate; + hid_parameter.ux_slave_class_hid_instance_deactivate = demo_device_hid_instance_deactivate; + + /* Initialize 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, 0, (VOID *)&hid_parameter); + if(status!=UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Create the main device simulation thread. */ + status = tx_thread_create(&tx_demo_thread_device_simulation, "tx demo device simulation", tx_demo_thread_device_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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + stack_pointer += UX_DEMO_STACK_SIZE; + + /* 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_device_simulation_entry(ULONG arg) +{ + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); +#else + tx_thread_suspend(&tx_demo_thread_device_simulation); +#endif + } +} + +static UINT demo_class_hid_wait(ULONG tick) +{ + return(ux_test_sleep_break_on_success(tick, demo_class_hid_mouse_get)); +} + +static UINT _wait_mouse_change(UX_HOST_CLASS_HID_MOUSE *mouse, + ULONG *buttons, SLONG *x, SLONG *y, SLONG *w) +{ +UINT status; +UINT i; +ULONG buttons_bak = *buttons; +SLONG x_bak = *x, y_bak = *y; +SLONG w_bak = *w; + + for (i = 0; i < 200; i ++) + { +#if defined(UX_HOST_STANDALONE) + ux_system_tasks_run(); +#endif + ux_host_class_hid_mouse_buttons_get(hid_mouse, buttons); + ux_host_class_hid_mouse_position_get(hid_mouse, x, y); + ux_host_class_hid_mouse_wheel_get(hid_mouse, w); + if (buttons_bak != *buttons || + x_bak != *x || + y_bak != *y || + w_bak != *w) + { + return(UX_SUCCESS); + } + tx_thread_sleep(1); + } + return(UX_ERROR); +} + +static void test_hid_mouse_events(VOID) +{ +UINT status; +ULONG buttons = 0; +SLONG x = 0xFF, y = 0xFF; +SLONG wheel = 0; + + /* Initialize mouse event. */ + device_hid_event.ux_device_class_hid_event_length = 4; + device_hid_event.ux_device_class_hid_event_buffer[0] = 0; /* ...M|R|L */ + device_hid_event.ux_device_class_hid_event_buffer[1] = 0; /* X */ + device_hid_event.ux_device_class_hid_event_buffer[2] = 0; /* Y */ + device_hid_event.ux_device_class_hid_event_buffer[3] = 0; /* Wheel */ + + status = ux_host_class_hid_mouse_buttons_get(hid_mouse, &buttons); + status |= ux_host_class_hid_mouse_position_get(hid_mouse, &x, &y); + status |= ux_host_class_hid_mouse_wheel_get(hid_mouse, &wheel); + UX_ASSERT(status == UX_SUCCESS); + UX_ASSERT(buttons == 0); + UX_ASSERT(x == 0); + UX_ASSERT(y == 0); + UX_ASSERT(wheel == 0); + + /* Set L click. */ + device_hid_event.ux_device_class_hid_event_buffer[0] = 1; /* ...M|R|L */ + _ux_device_class_hid_event_set(device_hid, &device_hid_event); + status = _wait_mouse_change(hid_mouse, &buttons, &x, &y, &wheel); + UX_ASSERT(status == UX_SUCCESS); + UX_ASSERT(buttons == 1); + UX_ASSERT(x == 0); + UX_ASSERT(y == 0); + UX_ASSERT(wheel == 0); + + /* Set R click. */ + device_hid_event.ux_device_class_hid_event_buffer[0] = 3; /* ...M|R|L */ + _ux_device_class_hid_event_set(device_hid, &device_hid_event); + status = _wait_mouse_change(hid_mouse, &buttons, &x, &y, &wheel); + UX_ASSERT(status == UX_SUCCESS); + UX_ASSERT(buttons == 3); + UX_ASSERT(x == 0); + UX_ASSERT(y == 0); + UX_ASSERT(wheel == 0); + + /* Move X. */ + device_hid_event.ux_device_class_hid_event_buffer[1] = -1; /* X */ + _ux_device_class_hid_event_set(device_hid, &device_hid_event); + status = _wait_mouse_change(hid_mouse, &buttons, &x, &y, &wheel); + UX_ASSERT(status == UX_SUCCESS); + UX_ASSERT(buttons == 3); + UX_ASSERT(x == -1); + UX_ASSERT(y == 0); + UX_ASSERT(wheel == 0); + + /* Move X. */ + device_hid_event.ux_device_class_hid_event_buffer[1] = +8; /* X */ + _ux_device_class_hid_event_set(device_hid, &device_hid_event); + status = _wait_mouse_change(hid_mouse, &buttons, &x, &y, &wheel); + UX_ASSERT(status == UX_SUCCESS); + UX_ASSERT(buttons == 3); + UX_ASSERT(x == +7); + UX_ASSERT(y == 0); + UX_ASSERT(wheel == 0); + + /* Move Y. */ + device_hid_event.ux_device_class_hid_event_buffer[2] = +8; /* Y */ + _ux_device_class_hid_event_set(device_hid, &device_hid_event); + status = _wait_mouse_change(hid_mouse, &buttons, &x, &y, &wheel); + UX_ASSERT(status == UX_SUCCESS); + UX_ASSERT(buttons == 3); + UX_ASSERT(x == 15); + UX_ASSERT(y == 8); + UX_ASSERT(wheel == 0); + + /* Move Wheel. */ + device_hid_event.ux_device_class_hid_event_buffer[1] = -2; /* X */ + device_hid_event.ux_device_class_hid_event_buffer[2] = -5; /* Y */ + device_hid_event.ux_device_class_hid_event_buffer[3] = +10; /* Wheel */ + _ux_device_class_hid_event_set(device_hid, &device_hid_event); + status = _wait_mouse_change(hid_mouse, &buttons, &x, &y, &wheel); + UX_ASSERT(status == UX_SUCCESS); + UX_ASSERT(buttons == 3); + UX_ASSERT(x == 13); + UX_ASSERT(y == 3); + UX_ASSERT(wheel == 10); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; + + /* Find the HID class */ + status = demo_class_hid_wait(100); + UX_TEST_ASSERT(status == UX_SUCCESS); + + test_hid_mouse_events(); + + /* 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_set_callback(UX_SLAVE_CLASS_HID *class, UX_SLAVE_CLASS_HID_EVENT *event) +{ + _ux_utility_memory_copy(&device_hid_event, event, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + return(UX_SUCCESS); +} +static UINT demo_thread_hid_get_callback(UX_SLAVE_CLASS_HID *class, UX_SLAVE_CLASS_HID_EVENT *event) +{ + _ux_utility_memory_copy(event, &device_hid_event, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + return(UX_SUCCESS); +} + +static void demo_device_hid_instance_activate(VOID *inst) +{ + if (device_hid == UX_NULL) + device_hid = (UX_SLAVE_CLASS_HID *)inst; +} +static void demo_device_hid_instance_deactivate(VOID *inst) +{ + if (inst == (VOID *)device_hid) + device_hid = UX_NULL; +} diff --git a/test/regression/usbx_class_hid_remote_control_basic_test.c b/test/regression/usbx_class_hid_remote_control_basic_test.c new file mode 100644 index 00000000..67f677f8 --- /dev/null +++ b/test/regression/usbx_class_hid_remote_control_basic_test.c @@ -0,0 +1,503 @@ +/* This file tests basic HID functionalities. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_keyboard_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + + 0xc0 // END_COLLECTION +}; +#define HID_KEYBOARD_REPORT_LENGTH sizeof(hid_keyboard_report)/sizeof(hid_keyboard_report[0]) + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +static UCHAR hid_remote_control_report[] = { + + 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) + 0x09, 0x01, // USAGE (Consumer Control) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x02, // USAGE (Numeric Key Pad) + 0xa1, 0x02, // COLLECTION (Logical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x0a, // USAGE_MAXIMUM (Button 10) + 0x15, 0x01, // LOGICAL_MINIMUM (1) + 0x25, 0x0a, // LOGICAL_MAXIMUM (10) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0, // END_COLLECTION + 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) + 0x09, 0x86, // USAGE (Channel) + 0x09, 0xe0, // USAGE (Volume) + 0x15, 0xff, // LOGICAL_MINIMUM (-1) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x02, // REPORT_SIZE (2) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x46, // INPUT (Data,Var,Rel,Null) + 0xc0 // END_COLLECTION +}; +#define HID_REMOTE_CONTROL_REPORT_LENGTH (sizeof(hid_remote_control_report)/sizeof(hid_remote_control_report[0])) + + +#define hid_report_descriptor hid_remote_control_report +#define HID_REPORT_LENGTH HID_REMOTE_CONTROL_REPORT_LENGTH + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN (9) + + +/* HID Mouse/Keyboard interface descriptors 9+9+7=25 bytes */ +#define HID_IFC_DESC_ALL(ifc, report_len, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(report_len),\ + MSB(report_len),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_IFC_DESC_ALL_LEN (9+9+7) + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC(CFG_DESC_LEN+1*HID_IFC_DESC_ALL_LEN, 1, 1) + /* Keyboard */ + HID_IFC_DESC_ALL(0, HID_REPORT_LENGTH, 0x81) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC(CFG_DESC_LEN+1*HID_IFC_DESC_ALL_LEN, 1, 1) + /* Keyboard */ + HID_IFC_DESC_ALL(0, HID_REPORT_LENGTH, 0x81) +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +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 +}; +#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. */ +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + switch(event) + { + case UX_HID_CLIENT_INSERTION: + break; + case UX_HID_CLIENT_REMOVAL: + break; +#if defined(UX_HOST_STANDALONE) + case UX_STANDALONE_WAIT_BACKGROUND_TASK: + /* Let other threads to run. */ + tx_thread_relinquish(); + break; +#endif + default: + break; + } + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_class_hid_remote_control_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running HID Class Remote Control Basic 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Register the HID client(s). */ + status = ux_host_class_hid_client_register(_ux_system_host_class_hid_client_remote_control_name, ux_host_class_hid_remote_control_entry); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\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, error code: %d\n", __LINE__, status); + 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_set_callback; + hid_parameter.ux_device_class_hid_parameter_get_callback = demo_thread_hid_get_callback; + + hid_parameter.ux_slave_class_hid_instance_activate = demo_device_hid_instance_activate; + hid_parameter.ux_slave_class_hid_instance_deactivate = demo_device_hid_instance_deactivate; + + /* 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, 0, (VOID *)&hid_parameter); + if(status!=UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Create the main device simulation thread. */ + status = tx_thread_create(&tx_demo_thread_device_simulation, "tx demo device simulation", tx_demo_thread_device_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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + stack_pointer += UX_DEMO_STACK_SIZE; + + /* 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_device_simulation_entry(ULONG arg) +{ + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); +#else + tx_thread_suspend(&tx_demo_thread_device_simulation); +#endif + } +} + +static UINT demo_class_hid_wait(ULONG tick) +{ + return(ux_test_sleep_break_on_success(tick, demo_class_hid_remote_control_get)); +} + +static UINT _wait_remote_control_usage(UX_HOST_CLASS_HID_REMOTE_CONTROL *remote_control, + ULONG *usage, ULONG *value) +{ +UINT status; +UINT i; + + for (i = 0; i < 200; i ++) + { +#if defined(UX_HOST_STANDALONE) + ux_system_tasks_run(); +#endif + status = ux_host_class_hid_remote_control_usage_get(remote_control, usage, value); + if (status == UX_SUCCESS) + return(UX_SUCCESS); + tx_thread_sleep(1); + } + return(UX_ERROR); +} + +static void test_hid_remote_control_events(VOID) +{ +UINT status; +ULONG usage; +ULONG value; + + /* Initialize mouse event. */ + device_hid_event.ux_device_class_hid_event_length = 1; + device_hid_event.ux_device_class_hid_event_buffer[0] = 0; /* CH(2)|CH(2)|Bn(4) */ + + device_hid_event.ux_device_class_hid_event_buffer[0] = (3 << 6) | (1 << 4) | (10); /* CH(2)|CH(2)|Bn(4) */ + _ux_device_class_hid_event_set(device_hid, &device_hid_event); + status = _wait_remote_control_usage(hid_remote_control, &usage, &value); + UX_ASSERT(status == UX_SUCCESS); + UX_ASSERT(usage == (0x90000+10)); + UX_ASSERT(value == 10); + status = ux_host_class_hid_remote_control_usage_get(hid_remote_control, &usage, &value); + UX_ASSERT(status == UX_SUCCESS); + UX_ASSERT(usage == 0xc0086); + UX_ASSERT(value == 1); + status = ux_host_class_hid_remote_control_usage_get(hid_remote_control, &usage, &value); + UX_ASSERT(status == UX_SUCCESS); + UX_ASSERT(usage == 0xc00e0); + UX_ASSERT(value == 3); + + device_hid_event.ux_device_class_hid_event_buffer[0] = (1 << 6) | (0 << 4) | (5); /* CH(2)|CH(2)|Bn(4) */ + _ux_device_class_hid_event_set(device_hid, &device_hid_event); + status = _wait_remote_control_usage(hid_remote_control, &usage, &value); + UX_ASSERT(status == UX_SUCCESS); + UX_ASSERT(usage == (0x90000+5)); + UX_ASSERT(value == 5); + status = ux_host_class_hid_remote_control_usage_get(hid_remote_control, &usage, &value); + UX_ASSERT(status == UX_SUCCESS); + UX_ASSERT(usage == 0xc0086); + UX_ASSERT(value == 0); + status = ux_host_class_hid_remote_control_usage_get(hid_remote_control, &usage, &value); + UX_ASSERT(status == UX_SUCCESS); + UX_ASSERT(usage == 0xc00e0); + UX_ASSERT(value == 1); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; + + /* Find the HID class */ + status = demo_class_hid_wait(100); + UX_TEST_ASSERT(status == UX_SUCCESS); + + test_hid_remote_control_events(); + + /* 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_set_callback(UX_SLAVE_CLASS_HID *class, UX_SLAVE_CLASS_HID_EVENT *event) +{ + _ux_utility_memory_copy(&device_hid_event, event, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + return(UX_SUCCESS); +} +static UINT demo_thread_hid_get_callback(UX_SLAVE_CLASS_HID *class, UX_SLAVE_CLASS_HID_EVENT *event) +{ + _ux_utility_memory_copy(event, &device_hid_event, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + return(UX_SUCCESS); +} + +static void demo_device_hid_instance_activate(VOID *inst) +{ + if (device_hid == UX_NULL) + device_hid = (UX_SLAVE_CLASS_HID *)inst; +} +static void demo_device_hid_instance_deactivate(VOID *inst) +{ + if (inst == (VOID *)device_hid) + device_hid = UX_NULL; +} diff --git a/test/regression/usbx_class_interface_enumeration_test.c b/test/regression/usbx_class_interface_enumeration_test.c new file mode 100644 index 00000000..b435ce21 --- /dev/null +++ b/test/regression/usbx_class_interface_enumeration_test.c @@ -0,0 +1,516 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_host_class_dummy.h" +#include "ux_device_class_dummy.h" +#include "ux_test.h" + + +/* Define USBX demo constants. */ + +#define UX_DEMO_STACK_SIZE 4096 +#define UX_DEMO_BUFFER_SIZE 2048 +#define UX_DEMO_RUN 1 +#define UX_DEMO_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the demo application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + + +/* Define USBX demo global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DUMMY *dummy; +static UX_DEVICE_CLASS_DUMMY *dummy_slave; + +static UINT expected_error; + +#define _W0(w) ( (w) & 0xFF) +#define _W1(w) (((w) >> 8) & 0xFF) + +#define _DEVICE_DESCRIPTOR(cls, sub, protocol, pktsize, vid, pid, n_cfg) \ + 0x12, 0x01, 0x10, 0x01, \ + (cls), (sub), (protocol), (pktsize), \ + _W0(vid), _W1(vid), _W0(pid), _W1(pid), \ + 0x00, 0x00, 0x00, 0x00, 0x00, (n_cfg), + +#define _QUALIFIER_DESCRIPTOR(cls, sub, protocol, n_cfg) \ + 0x0a, 0x06, 0x00, 0x02, \ + (cls), (sub), (protocol), 0x40, (n_cfg), 0x00, + +#define _CONFIGURATION_DESCRIPTOR(total_len, n_ifc, cfg_val) \ + 0x09, 0x02, _W0(total_len), _W1(total_len), (n_ifc), (cfg_val), \ + 0x00, 0xc0, 0x32, + +#define _INTERFACE_DESCRIPTOR(ifc_n, alt, n_ep, cls, sub, protocol) \ + 0x09, 0x04, (ifc_n), (alt), (n_ep), (cls), (sub), (protocol), 0x00, + +#define _ENDPOINT_DESCRIPTOR(addr, attr, pktsize, interval) \ + 0x07, 0x05, (addr), (attr), _W0(pktsize), _W1(pktsize), (interval), + +#define _CONFIGURATION_TOTAL_LENGTH (9+9+9+2*7) +#define _CONFIGURATION_DESCRIPTORS(hs) \ + _CONFIGURATION_DESCRIPTOR(_CONFIGURATION_TOTAL_LENGTH, 1, 1) \ + _INTERFACE_DESCRIPTOR(0, 0, 0, 0x99, 0x99, 0x99) \ + _INTERFACE_DESCRIPTOR(0, 1, 2, 0x99, 0x99, 0x99) \ + _ENDPOINT_DESCRIPTOR(0x01, 0x02, (hs) ? 512 : 64, 0x00) \ + _ENDPOINT_DESCRIPTOR(0x82, 0x02, (hs) ? 512 : 64, 0x00) + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +static UCHAR device_framework_full_speed[] = { + _DEVICE_DESCRIPTOR(0x00, 0x00, 0x00, 8, 0x08EC, 0x0001, 1) + _CONFIGURATION_DESCRIPTORS(0) +}; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) +static UCHAR device_framework_high_speed[] = { + _DEVICE_DESCRIPTOR(0x00, 0x00, 0x00, 64, 0x08EC, 0x0001, 1) + _QUALIFIER_DESCRIPTOR(0, 0, 0, 1) + _CONFIGURATION_DESCRIPTORS(1) +}; + +/* 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 sizeof(string_framework) +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* 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 sizeof(language_id_framework) +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID tx_demo_instance_activate(VOID *dummy_instance); +static VOID tx_demo_instance_deactivate(VOID *dummy_instance); +static VOID tx_demo_instance_change(UX_DEVICE_CLASS_DUMMY *dummy_instance); + +#if defined(UX_HOST_STANDALONE) +static UINT tx_demo_host_change_function(ULONG e, UX_HOST_CLASS *c, VOID *p); +#else +#define tx_demo_host_change_function UX_NULL +#endif + +UINT ux_hcd_sim_initialize(UX_HCD *hcd); + +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); +static void tx_demo_thread_slave_simulation_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (expected_error == 0 || error_code != expected_error) + { + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %x\n", __LINE__, system_level, system_context, error_code); + // test_control_return(1); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_class_interface_enumeration_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_DEVICE_CLASS_DUMMY_PARAMETER parameter; + + + printf("Running Basic Interface Class Enumeration Test...................... "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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 #%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(tx_demo_host_change_function); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_host_class_dummy_name, _ux_host_class_dummy_entry); + + /* Check for error. */ + 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 */ + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + _ux_utility_memory_set((void *)¶meter, 0x00, sizeof(parameter)); + parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_instance_activate = tx_demo_instance_activate; + parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_instance_deactivate = tx_demo_instance_deactivate; + parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_change = tx_demo_instance_change; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_device_class_dummy_name, _ux_device_class_dummy_entry, + 1, 0, ¶meter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%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 #%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 #%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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +static UINT ux_demo_dummy_instance_check(VOID) +{ +UINT status; +UX_HOST_CLASS *cls; + status = ux_host_stack_class_get(_ux_host_class_dummy_name, &cls); + if (status != UX_SUCCESS) + return(status); + status = ux_host_stack_class_instance_get(cls, 0, (VOID **) &dummy); + if (status != UX_SUCCESS) + return(status); + if (dummy -> ux_host_class_dummy_state != UX_HOST_CLASS_INSTANCE_LIVE) + return(UX_NO_CLASS_MATCH); + return(UX_SUCCESS); +} + +static UINT ux_demo_dummy_instance_connect_wait(ULONG wait_ticks) +{ +ULONG t0 = tx_time_get(), t1; + while(1) + { +#if defined(UX_HOST_STANDALONE) + ux_system_tasks_run(); +#endif + if (UX_SUCCESS == ux_demo_dummy_instance_check()) + return(UX_SUCCESS); + tx_thread_relinquish(); + + /* Wait forever. */ + if (wait_ticks == 0xFFFFFFFFul) + continue; + + /* No wait. */ + if (wait_ticks == 0) + break; + + /* Check timeout. */ + t1 = tx_time_get(); + if (t1 >= t0) + t1 = t1 - t0; + else + t1 = 0xFFFFFFFFul - t0 + t1; + if (t1 > wait_ticks) + break; + } + return(UX_ERROR); +} + +static UINT ux_demo_dummy_instance_remove_wait(ULONG wait_ticks) +{ +ULONG t0 = tx_time_get(), t1; + while(1) + { +#if defined(UX_HOST_STANDALONE) + ux_system_tasks_run(); +#endif + if (UX_SUCCESS != ux_demo_dummy_instance_check()) + { + dummy = UX_NULL; + return(UX_SUCCESS); + } + tx_thread_relinquish(); + + /* Wait forever. */ + if (wait_ticks == 0xFFFFFFFFul) + continue; + + /* No wait. */ + if (wait_ticks == 0) + break; + + /* Check timeout. */ + t1 = tx_time_get(); + if (t1 >= t0) + t1 = t1 - t0; + else + t1 = 0xFFFFFFFFul - t0 + t1; + if (t1 > wait_ticks) + break; + } + return(UX_ERROR); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ +UINT status; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; + + stepinfo(">>>> Dummy Class Connection Wait\n"); + status = ux_demo_dummy_instance_connect_wait(1000); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>> Dummy Class Configuration Deactivate\n"); + interface = dummy -> ux_host_class_dummy_interface; + configuration = interface -> ux_interface_configuration; + device = configuration -> ux_configuration_device; + status = ux_host_stack_device_configuration_deactivate(device); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + status = ux_demo_dummy_instance_remove_wait(10); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>> Dummy Class Configuration Activate\n"); + status = ux_host_stack_device_configuration_activate(configuration); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + status = ux_demo_dummy_instance_connect_wait(1000); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + +#if UX_TEST_MULTI_ALT_ON + stepinfo(">>>> Dummy Class Interface Change\n"); + status = _ux_host_class_dummy_select_interface(dummy, 0, 1); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _ux_host_class_dummy_select_interface(dummy, 0, 0); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, 0x%x\n", __LINE__, status); + test_control_return(1); + } +#endif + + expected_error = 0; + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* DPUMP error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + + +static void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG actual_length; + + + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + + /* Run device tasks. */ + ux_system_tasks_run(); +#endif + /* Increment thread counter. */ + thread_1_counter++; + + /* Relinquish to other thread. */ + tx_thread_relinquish(); + } +} + +static VOID tx_demo_instance_activate(VOID *inst) +{ + dummy_slave = (UX_DEVICE_CLASS_DUMMY *)inst; +} + +static VOID tx_demo_instance_deactivate(VOID *inst) +{ + dummy_slave = UX_NULL; +} + +static VOID tx_demo_instance_change(UX_DEVICE_CLASS_DUMMY *dummy) +{ + UX_PARAMETER_NOT_USED(dummy); +} + +#if defined(UX_HOST_STANDALONE) +static UINT tx_demo_host_change_function(ULONG e, UX_HOST_CLASS *c, VOID *p) +{ + if (e == UX_STANDALONE_WAIT_BACKGROUND_TASK) + { + tx_thread_relinquish(); + } +} +#endif diff --git a/test/regression/usbx_class_multi_interface_enumeration_test.c b/test/regression/usbx_class_multi_interface_enumeration_test.c new file mode 100644 index 00000000..06c4bae5 --- /dev/null +++ b/test/regression/usbx_class_multi_interface_enumeration_test.c @@ -0,0 +1,561 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_host_class_dummy.h" +#include "ux_device_class_dummy.h" +#include "ux_test.h" + + +/* Define USBX demo constants. */ + +#define UX_DEMO_STACK_SIZE 4096 +#define UX_DEMO_BUFFER_SIZE 2048 +#define UX_DEMO_RUN 1 +#define UX_DEMO_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the demo application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + + +/* Define USBX demo global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DUMMY *dummy; +static UX_DEVICE_CLASS_DUMMY *dummy_slave; + +static UINT expected_error; + +#define _W0(w) ( (w) & 0xFF) +#define _W1(w) (((w) >> 8) & 0xFF) + +#define _DEVICE_DESCRIPTOR(cls, sub, protocol, pktsize, vid, pid, n_cfg) \ + 0x12, 0x01, 0x10, 0x01, \ + (cls), (sub), (protocol), (pktsize), \ + _W0(vid), _W1(vid), _W0(pid), _W1(pid), \ + 0x00, 0x00, 0x00, 0x00, 0x00, (n_cfg), + +#define _QUALIFIER_DESCRIPTOR(cls, sub, protocol, n_cfg) \ + 0x0a, 0x06, 0x00, 0x02, \ + (cls), (sub), (protocol), 0x40, (n_cfg), 0x00, + +#define _CONFIGURATION_DESCRIPTOR(total_len, n_ifc, cfg_val) \ + 0x09, 0x02, _W0(total_len), _W1(total_len), (n_ifc), (cfg_val), \ + 0x00, 0xc0, 0x32, + +#define _INTERFACE_DESCRIPTOR(ifc_n, alt, n_ep, cls, sub, protocol) \ + 0x09, 0x04, (ifc_n), (alt), (n_ep), (cls), (sub), (protocol), 0x00, + +#define _ENDPOINT_DESCRIPTOR(addr, attr, pktsize, interval) \ + 0x07, 0x05, (addr), (attr), _W0(pktsize), _W1(pktsize), (interval), + +#define _CONFIGURATION_TOTAL_LENGTH (9+9*3+7*4) +#define _CONFIGURATION_DESCRIPTORS(hs) \ + _CONFIGURATION_DESCRIPTOR(_CONFIGURATION_TOTAL_LENGTH, 3, 1) \ + _INTERFACE_DESCRIPTOR(0, 0, 1, 0x0E, 0x00, 0x00) \ + _ENDPOINT_DESCRIPTOR(0x03, 0x02, 8, 0x04) \ + _INTERFACE_DESCRIPTOR(1, 0, 2, 0x99, 0x99, 0x99) \ + _ENDPOINT_DESCRIPTOR(0x01, 0x02, (hs) ? 512 : 64, 0x00) \ + _ENDPOINT_DESCRIPTOR(0x82, 0x02, (hs) ? 512 : 64, 0x00) \ + _INTERFACE_DESCRIPTOR(2, 0, 1, 0x0E, 0x00, 0x00) \ + _ENDPOINT_DESCRIPTOR(0x84, 0x02,32, 0x04) + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +static UCHAR device_framework_full_speed[] = { + _DEVICE_DESCRIPTOR(0x00, 0x00, 0x00, 8, 0x08EC, 0x0001, 1) + _CONFIGURATION_DESCRIPTORS(0) +}; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) +static UCHAR device_framework_high_speed[] = { + _DEVICE_DESCRIPTOR(0x00, 0x00, 0x00, 64, 0x08EC, 0x0001, 1) + _QUALIFIER_DESCRIPTOR(0, 0, 0, 1) + _CONFIGURATION_DESCRIPTORS(1) +}; + +/* 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 sizeof(string_framework) +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* 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 sizeof(language_id_framework) +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; + + +static UX_HOST_CLASS_DUMMY_QUERY _accept_0x99_0x99_0x99[] = +{ + {.ux_host_class_query_on = UX_TRUE, + .ux_host_class_query_usage = UX_HOST_CLASS_COMMAND_USAGE_CSP, + .ux_host_class_query_class = 0x99, + .ux_host_class_query_subclass = 0x99, + .ux_host_class_query_protocol = 0x99}, + {0} +}; + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID tx_demo_instance_activate(VOID *dummy_instance); +static VOID tx_demo_instance_deactivate(VOID *dummy_instance); +static VOID tx_demo_instance_change(UX_DEVICE_CLASS_DUMMY *dummy_instance); + +#if defined(UX_HOST_STANDALONE) +static UINT tx_demo_host_change_function(ULONG e, UX_HOST_CLASS *c, VOID *p); +#else +#define tx_demo_host_change_function UX_NULL +#endif + +UINT ux_hcd_sim_initialize(UX_HCD *hcd); + +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); +static void tx_demo_thread_slave_simulation_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (expected_error == 0 || error_code != expected_error) + { + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %x\n", __LINE__, system_level, system_context, error_code); + // test_control_return(1); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_class_multi_interface_enumeration_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_DEVICE_CLASS_DUMMY_PARAMETER parameter; + + + printf("Running Multiple Interface Class Enumeration Test................... "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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 #%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(tx_demo_host_change_function); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_host_class_dummy_name, _ux_host_class_dummy_entry); + + /* Check for error. */ + 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 */ + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + _ux_utility_memory_set((void *)¶meter, 0x00, sizeof(parameter)); + parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_instance_activate = tx_demo_instance_activate; + parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_instance_deactivate = tx_demo_instance_deactivate; + parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_change = tx_demo_instance_change; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + _ux_host_class_dummy_query_reject_unknown_set(UX_TRUE); + _ux_host_class_dummy_query_list_set(_accept_0x99_0x99_0x99); + status = ux_device_stack_class_register(_ux_device_class_dummy_name, _ux_device_class_dummy_entry, + 1, 0, ¶meter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%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 #%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 #%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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +static UINT ux_demo_dummy_instance_check(VOID) +{ +UINT status; +UX_HOST_CLASS *cls; + status = ux_host_stack_class_get(_ux_host_class_dummy_name, &cls); + if (status != UX_SUCCESS) + return(status); + status = ux_host_stack_class_instance_get(cls, 0, (VOID **) &dummy); + if (status != UX_SUCCESS) + return(status); + if (dummy -> ux_host_class_dummy_state != UX_HOST_CLASS_INSTANCE_LIVE) + return(UX_NO_CLASS_MATCH); + return(UX_SUCCESS); +} + +static UINT ux_demo_dummy_instance_connect_wait(ULONG wait_ticks) +{ +ULONG t0 = tx_time_get(), t1; + while(1) + { +#if defined(UX_HOST_STANDALONE) + ux_system_tasks_run(); +#endif + if (UX_SUCCESS == ux_demo_dummy_instance_check()) + return(UX_SUCCESS); + tx_thread_relinquish(); + + /* Wait forever. */ + if (wait_ticks == 0xFFFFFFFFul) + continue; + + /* No wait. */ + if (wait_ticks == 0) + break; + + /* Check timeout. */ + t1 = tx_time_get(); + if (t1 >= t0) + t1 = t1 - t0; + else + t1 = 0xFFFFFFFFul - t0 + t1; + if (t1 > wait_ticks) + break; + } + return(UX_ERROR); +} + +static UINT ux_demo_dummy_instance_remove_wait(ULONG wait_ticks) +{ +ULONG t0 = tx_time_get(), t1; + while(1) + { +#if defined(UX_HOST_STANDALONE) + ux_system_tasks_run(); +#endif + if (UX_SUCCESS != ux_demo_dummy_instance_check()) + { + dummy = UX_NULL; + return(UX_SUCCESS); + } + tx_thread_relinquish(); + + /* Wait forever. */ + if (wait_ticks == 0xFFFFFFFFul) + continue; + + /* No wait. */ + if (wait_ticks == 0) + break; + + /* Check timeout. */ + t1 = tx_time_get(); + if (t1 >= t0) + t1 = t1 - t0; + else + t1 = 0xFFFFFFFFul - t0 + t1; + if (t1 > wait_ticks) + break; + } + return(UX_ERROR); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ +UINT status; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface_ptr; +UX_ENDPOINT *endpoint; + + stepinfo(">>>> Dummy Class Connection Wait\n"); + status = ux_demo_dummy_instance_connect_wait(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>> Dummy Class Configuration Deactivate\n"); + interface_ptr = dummy -> ux_host_class_dummy_interface; + configuration = interface_ptr -> ux_interface_configuration; + device = configuration -> ux_configuration_device; + status = ux_host_stack_device_configuration_deactivate(device); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + status = ux_demo_dummy_instance_remove_wait(10); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>> Dummy Class Configuration Activate\n"); + status = ux_host_stack_device_configuration_activate(configuration); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + status = ux_demo_dummy_instance_connect_wait(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + +#if UX_HOST_STACK_CONFIGURATION_INSTANCE_CREATE_CONTROL == UX_HOST_STACK_CONFIGURATION_INSTANCE_CREATE_ALL + stepinfo(">>>> Check physical endpoints (create all)\n"); + status = ux_host_stack_configuration_interface_get(configuration, 0, 0, &interface_ptr); + UX_TEST_CHECK_SUCCESS(status); + status = ux_host_stack_interface_endpoint_get(interface_ptr, 0, &endpoint); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(endpoint -> ux_endpoint_ed != UX_NULL); + + status = ux_host_stack_configuration_interface_get(configuration, 1, 0, &interface_ptr); + UX_TEST_CHECK_SUCCESS(status); + status = ux_host_stack_interface_endpoint_get(interface_ptr, 0, &endpoint); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(endpoint -> ux_endpoint_ed != UX_NULL); + status = ux_host_stack_interface_endpoint_get(interface_ptr, 1, &endpoint); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(endpoint -> ux_endpoint_ed != UX_NULL); + + status = ux_host_stack_configuration_interface_get(configuration, 2, 0, &interface_ptr); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_CHECK_SUCCESS(status); + status = ux_host_stack_interface_endpoint_get(interface_ptr, 0, &endpoint); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(endpoint -> ux_endpoint_ed != UX_NULL); + +#elif UX_HOST_STACK_CONFIGURATION_INSTANCE_CREATE_CONTROL == UX_HOST_STACK_CONFIGURATION_INSTANCE_CREATE_OWNED + stepinfo(">>>> Check physical endpoints (create owned)\n"); + status = ux_host_stack_configuration_interface_get(configuration, 0, 0, &interface_ptr); + UX_TEST_CHECK_SUCCESS(status); + status = ux_host_stack_interface_endpoint_get(interface_ptr, 0, &endpoint); + UX_TEST_ASSERT(endpoint -> ux_endpoint_ed == UX_NULL); + + status = ux_host_stack_configuration_interface_get(configuration, 1, 0, &interface_ptr); + UX_TEST_CHECK_SUCCESS(status); + status = ux_host_stack_interface_endpoint_get(interface_ptr, 0, &endpoint); + UX_TEST_ASSERT(endpoint -> ux_endpoint_ed != UX_NULL); + status = ux_host_stack_interface_endpoint_get(interface_ptr, 1, &endpoint); + UX_TEST_ASSERT(endpoint -> ux_endpoint_ed != UX_NULL); + + status = ux_host_stack_configuration_interface_get(configuration, 2, 0, &interface_ptr); + UX_TEST_CHECK_SUCCESS(status); + status = ux_host_stack_interface_endpoint_get(interface_ptr, 0, &endpoint); + UX_TEST_ASSERT(endpoint -> ux_endpoint_ed == UX_NULL); + +#endif + + expected_error = 0; + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* DPUMP error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + + +static void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG actual_length; + + + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + + /* Run device tasks. */ + ux_system_tasks_run(); +#endif + /* Increment thread counter. */ + thread_1_counter++; + + /* Relinquish to other thread. */ + tx_thread_relinquish(); + } +} + +static VOID tx_demo_instance_activate(VOID *inst) +{ + dummy_slave = (UX_DEVICE_CLASS_DUMMY *)inst; +} + +static VOID tx_demo_instance_deactivate(VOID *inst) +{ + dummy_slave = UX_NULL; +} + +static VOID tx_demo_instance_change(UX_DEVICE_CLASS_DUMMY *dummy) +{ + UX_PARAMETER_NOT_USED(dummy); +} + +#if defined(UX_HOST_STANDALONE) +static UINT tx_demo_host_change_function(ULONG e, UX_HOST_CLASS *c, VOID *p) +{ + if (e == UX_STANDALONE_WAIT_BACKGROUND_TASK) + { + tx_thread_relinquish(); + } +} +#endif diff --git a/test/regression/usbx_class_printer_basic_tests.c b/test/regression/usbx_class_printer_basic_tests.c new file mode 100644 index 00000000..a2538244 --- /dev/null +++ b/test/regression/usbx_class_printer_basic_tests.c @@ -0,0 +1,852 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_printer.h" +#include "ux_device_stack.h" +#include "ux_host_class_printer.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); + +static TX_THREAD tx_test_thread_printer_read; +static TX_THREAD tx_test_thread_printer_write; +static TX_SEMAPHORE tx_test_semaphore_printer_trigger; +static VOID tx_test_printer_read_entry(ULONG); +static VOID tx_test_printer_write_entry(ULONG); + +static VOID ux_test_hcd_entry_should_not_be_called(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_disconnect(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +static UX_DEVICE *device = UX_NULL; +static UX_HOST_CLASS_PRINTER *host_printer = UX_NULL; +static UCHAR host_buffer[UX_DEMO_BUFFER_SIZE * 8]; + +static ULONG enum_counter; + +static ULONG error_counter; +static ULONG error_callback_counter; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_on_set_cfg; +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_enum_mem_alloc_count; + +static ULONG rsc_test_sem_usage; +static ULONG rsc_test_sem_get_count; +static ULONG rsc_test_mutex_usage; +static ULONG rsc_test_mem_alloc_count; + +static UX_DEVICE_CLASS_PRINTER *device_printer = UX_NULL; +static UX_DEVICE_CLASS_PRINTER_PARAMETER device_printer_parameter; +static UCHAR device_buffer[UX_DEMO_BUFFER_SIZE * 8]; +static ULONG device_buffer_length = 0; +static UCHAR device_printer_soft_reset_count = 0; + +/* Device printer device ID. */ +static UCHAR printer_device_id[] = + { + " " // Will be replaced by length (big endian) + "MFG:Generic;" // manufacturer (case sensitive) + "MDL:Generic_/_Text_Only;" // model (case sensitive) + "CMD:1284.4;" // PDL command set + "CLS:PRINTER;" // class + "DES:Generic text only printer;" // description + }; + +/* Define device framework. */ + +#define _W0(w) ( (w) & 0xFF) +#define _W1(w) (((w) >> 8) & 0xFF) + +#define _CONFIGURATION_DESCRIPTOR(total_len, n_ifc, cfg_val) \ + 0x09, 0x02, _W0(total_len), _W1(total_len), (n_ifc), (cfg_val), \ + 0x00, 0xc0, 0x32, + +#define _INTERFACE_DESCRIPTOR(ifc_n, alt, n_ep, cls, sub, protocol) \ + 0x09, 0x04, (ifc_n), (alt), (n_ep), (cls), (sub), (protocol), 0x00, + +#define _ENDPOINT_DESCRIPTOR(addr, attr, pktsize, interval) \ + 0x07, 0x05, (addr), (attr), _W0(pktsize), _W1(pktsize), (interval), + +#define _CFG_TOTAL_LEN (9+9+7+7) + +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0xEF bDeviceClass: Composite class code + 0x02 bDeviceSubclass: class sub code + 0x00 bDeviceProtocol: Device protocol + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0x00, 0x00, 0x00, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 0x03, + 0x01, + + _CONFIGURATION_DESCRIPTOR(_CFG_TOTAL_LEN, 1, 1) + _INTERFACE_DESCRIPTOR(0, 0, 2, 0x07, 0x01, 0x02) + _ENDPOINT_DESCRIPTOR(0x01, 0x02, 64, 0x00) + _ENDPOINT_DESCRIPTOR(0x82, 0x02, 64, 0x00) +}; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_full_speed) +#define device_framework_high_speed device_framework_full_speed + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "AzureRTOS" */ + 0x09, 0x04, 0x01, 9, + 'A','z','u','r','e','R','T','O','S', + + /* Product string descriptor : Index 2 - "Printer device" */ + 0x09, 0x04, 0x02, 14, + 'P','r','i','n','t','e','r',' ','d','e','v','i','c','e', + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +/* Test interactions */ + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT test_slave_change_function(ULONG change) +{ + return 0; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_PRINTER *printer_inst = (UX_HOST_CLASS_PRINTER *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + host_printer = printer_inst; + break; + + case UX_DEVICE_REMOVAL: + if (host_printer == printer_inst) + host_printer = UX_NULL; + break; + + case UX_DEVICE_CONNECTION: + device = (UX_DEVICE *)inst; + break; + + case UX_DEVICE_DISCONNECTION: + if ((VOID *)device == inst) + device = UX_NULL; + break; + +#if defined(UX_HOST_STANDALONE) + case UX_STANDALONE_WAIT_BACKGROUND_TASK: + tx_thread_relinquish(); + break; +#endif + + default: + break; + } + return 0; +} + +static VOID test_printer_instance_activate(VOID *dummy_instance) +{ + if (device_printer == UX_NULL) + device_printer = (UX_DEVICE_CLASS_PRINTER *)dummy_instance; +} +static VOID test_printer_instance_deactivate(VOID *dummy_instance) +{ + if ((VOID*)device_printer == dummy_instance) + device_printer = UX_NULL; +} +static VOID test_printer_soft_reset(VOID *dummy_instance) +{ + device_printer_soft_reset_count ++; +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + error_callback_counter ++; +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_enum_sem_get_count = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_host_class_printer_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + printf("Running Printer Basic Functionality Test............................ "); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* Initialize the free memory pointer */ + stack_pointer = (CHAR *) usbx_memory; + memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 4); + + /* 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 #1\n"); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + if (status != UX_SUCCESS) + { + + printf(" ERROR #2\n"); + test_control_return(1); + } + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_printer_name, _ux_host_class_printer_entry); + if (status != UX_SUCCESS) + { + + printf(" ERROR #3\n"); + 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, + test_slave_change_function); + if(status!=UX_SUCCESS) + { + + printf(" ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a printer device. */ + _ux_utility_memory_set(&device_printer_parameter, 0, sizeof(device_printer_parameter)); + _ux_utility_short_put_big_endian(printer_device_id, sizeof(printer_device_id)); + device_printer_parameter.ux_device_class_printer_device_id = printer_device_id; + device_printer_parameter.ux_device_class_printer_instance_activate = test_printer_instance_activate; + device_printer_parameter.ux_device_class_printer_instance_deactivate = test_printer_instance_deactivate; + device_printer_parameter.ux_device_class_printer_soft_reset = test_printer_soft_reset; + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_device_class_printer_name, + ux_device_class_printer_entry, + 1, 0, &device_printer_parameter); + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #8\n"); + 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 #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #9\n"); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + stack_pointer += UX_DEMO_STACK_SIZE; + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #10\n"); + test_control_return(1); + } + + /* Create the device printer read thread. */ + stack_pointer += UX_DEMO_STACK_SIZE; + status = tx_thread_create(&tx_test_thread_printer_read, "tx test printer read", + tx_test_printer_read_entry, UX_TRUE, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the device printer write thread. */ + stack_pointer += UX_DEMO_STACK_SIZE; + status = tx_thread_create(&tx_test_thread_printer_write, "tx test printer write", + tx_test_printer_write_entry, UX_FALSE, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the device printer write trigger. */ + status = tx_semaphore_create(&tx_test_semaphore_printer_trigger, + "tx test printer trigger", + 0); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +static UINT _test_check_host_connection_error(VOID) +{ + if (device_printer && host_printer) + return(UX_SUCCESS); + if (error_callback_counter >= 3) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_connection_success(VOID) +{ + if (device_printer && host_printer) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_disconnection_success(VOID) +{ + if (device_printer == UX_NULL && host_printer == UX_NULL) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static VOID _printer_enumeration_test(VOID) +{ +UINT status; +ULONG mem_free; +ULONG test_n; + + stepinfo(">>>>>>>>>>>> Enumeration information collection\n"); + { + + /* Test disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check connection. */ + status = ux_test_sleep_break_on_success(100, _test_check_host_disconnection_success); + UX_TEST_ASSERT(status == UX_SUCCESS); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_count_reset(); + ux_test_utility_sim_mutex_create_count_reset(); + ux_test_utility_sim_sem_create_count_reset(); + ux_test_utility_sim_sem_get_count_reset(); + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + + /* Save free memory usage. */ + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Check connection. */ + status = ux_test_sleep_break_on_success(100, _test_check_host_connection_success); + UX_TEST_ASSERT(status == UX_SUCCESS); + + /* Log create counts for further tests. */ + rsc_enum_mutex_usage = rsc_mutex_on_set_cfg; + rsc_enum_sem_usage = rsc_sem_on_set_cfg; + rsc_enum_mem_alloc_count = rsc_mem_alloc_cnt_on_set_cfg; + /* Log create counts when instances active for further tests. */ + rsc_test_mutex_usage = ux_test_utility_sim_mutex_create_count() - rsc_enum_mutex_usage; + rsc_test_sem_usage = ux_test_utility_sim_sem_create_count() - rsc_enum_sem_usage; + rsc_test_mem_alloc_count = ux_test_utility_sim_mem_alloc_count() - rsc_enum_mem_alloc_count; + + /* Lock log base for tests. */ + ux_test_utility_sim_mem_alloc_log_lock(); + + stepinfo("enum mem: %ld\n", rsc_enum_mem_alloc_count); + stepinfo("test mem : %ld\n", rsc_test_mem_alloc_count); + stepinfo("mem free: %ld, %ld\n", _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); + } + + stepinfo(">>>>>>>>>>>> Enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < 3; test_n++) + { + stepinfo("%4ld / 2\n", test_n); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check */ + status = ux_test_sleep_break_on_success(100, _test_check_host_disconnection_success); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d.%ld: Disconnect fail\n", __LINE__, test_n); + test_control_return(1); + } + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Wait and break on error. */ + error_callback_counter = 0; + status = ux_test_sleep_break_on_success(100, _test_check_host_connection_error); + + /* Check */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d.%ld: Enumeration fail\n", __LINE__, test_n); + test_control_return(1); + } + } + stepinfo("\n"); + + if (rsc_test_mem_alloc_count) stepinfo(">>>>>>>>>>>> Memory errors enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_test_mem_alloc_count; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_test_mem_alloc_count - 1); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check */ + status = ux_test_sleep_break_on_success(100, _test_check_host_disconnection_success); + if (status != UX_SUCCESS) + { + + stepinfo("ERROR #%d.%ld: Disconnect fail\n", __LINE__, test_n); + test_control_return(1); + } + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + stepinfo("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Set memory error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n + rsc_enum_mem_alloc_count); + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on errors. */ + status = ux_test_sleep_break_on_success(100, _test_check_host_connection_error); + + /* Check error */ + if (status != UX_SUCCESS) + { + + /* Check error trap. */ + if (error_callback_counter == 0) + { + stepinfo("ERROR #%d.%ld: device detected when there is memory error\n", __LINE__, test_n); + test_control_return(1); + } + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + } + ux_test_utility_sim_mem_alloc_error_generation_stop(); + if (rsc_test_mem_alloc_count) stepinfo("\n"); + + /* If device disconnected, re-connect. */ + if (_test_check_host_connection_success() != UX_SUCCESS) + { + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Check */ + status = ux_test_sleep_break_on_success(100, _test_check_host_connection_success); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: Enumeration fail\n", __LINE__); + test_control_return(1); + } + } +} +static VOID _printer_requests_test(VOID) +{ +UINT status; +ULONG printer_port_status; + + stepinfo(">>>>>>>>>>>>>>>> Test GET_DEVICE_ID\n"); + status = ux_host_class_printer_device_id_get(host_printer, host_buffer, sizeof(host_buffer)); + UX_TEST_ASSERT(status == UX_SUCCESS); + + stepinfo(">>>>>>>>>>>>>>>> Test GET_PORT_STATUS\n"); + ux_device_class_printer_ioctl(device_printer, UX_DEVICE_CLASS_PRINTER_IOCTL_PORT_STATUS_SET, (VOID *)0x73); + status = ux_host_class_printer_status_get(host_printer, &printer_port_status); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(printer_port_status == 0x73); + + stepinfo(">>>>>>>>>>>>>>>> Test SOFT_RESET\n"); + device_printer_soft_reset_count = 0; + status = ux_host_class_printer_soft_reset(host_printer); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(device_printer_soft_reset_count == 1); +} + +void tx_test_printer_read_entry(ULONG arg) +{ +UINT status; +ULONG actual_length; + while(1) + { + if (device_printer == UX_NULL) + { + tx_thread_sleep(10); + continue; + } + status = ux_device_class_printer_read(device_printer, device_buffer, sizeof(device_buffer), &actual_length); + /* Endpoint not ready. */ + if (status == UX_TRANSFER_BUS_RESET || + status == UX_TRANSFER_NO_ANSWER) + { + tx_thread_sleep(10); + continue; + } + device_buffer_length = actual_length; + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "#%d status 0x%x\n", __LINE__, status); + } +} + +void tx_test_printer_write_entry(ULONG arg) +{ +UINT status; +ULONG send_total; + while(1) + { + /* Wait a trigger. */ + status = tx_semaphore_get(&tx_test_semaphore_printer_trigger, TX_WAIT_FOREVER); + if (status != TX_SUCCESS || device_printer == UX_NULL) + { + tx_thread_sleep(10); + continue; + } + /* Send device_buffer_length. */ + status = ux_device_class_printer_write(device_printer, device_buffer, device_buffer_length, &send_total); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(device_buffer_length == send_total); + } +} + +static VOID _printer_read_write_test(VOID) +{ +struct _TEST_DEF { + ULONG fill; + ULONG length; + ULONG zlp; +} tests[] = { + {0x5A, 1, 0}, + {0x7E, 512, 1}, + {0xC2, 513, 0}, + {0x4C, UX_SLAVE_REQUEST_DATA_MAX_LENGTH, 1}, + {0xA5, UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1, 0}, + {0x3C, sizeof(device_buffer), 0}, + {0xC4, sizeof(device_buffer) - 1, 0}, +}; +#define _TEST_N (sizeof(tests)/sizeof(struct _TEST_DEF)) +INT i; +ULONG actual_length; +UINT status; + for(i = 0; i < _TEST_N; i ++) + { + stepinfo(">>>>>>>>>>>>>>>> Test Write %ld\n", tests[i].length); + device_buffer_length = 0; + ux_utility_memory_set(device_buffer, ~tests[i].fill, tests[i].length); + ux_utility_memory_set(host_buffer, tests[i].fill, tests[i].length); + status = ux_host_class_printer_write(host_printer, host_buffer, tests[i].length, &actual_length); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(tests[i].length == actual_length); + if (tests[i].zlp) + { + status = ux_host_class_printer_write(host_printer, host_buffer, 0, &actual_length); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(0 == actual_length); + } + UX_TEST_ASSERT(device_buffer_length == tests[i].length); + status = ux_utility_memory_compare(device_buffer, host_buffer, tests[i].length); + UX_TEST_ASSERT(status == UX_SUCCESS); + + stepinfo(">>>>>>>>>>>>>>>> Test Read %ld\n", tests[i].length); + status = tx_semaphore_put(&tx_test_semaphore_printer_trigger); + UX_TEST_ASSERT(status == TX_SUCCESS); + ux_utility_memory_set(host_buffer, ~tests[i].fill, tests[i].length); + status = ux_host_class_printer_read(host_printer, host_buffer, tests[i].length, &actual_length); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(tests[i].length == actual_length); + UX_TEST_ASSERT(host_buffer[0] == tests[i].fill); + UX_TEST_ASSERT(host_buffer[tests[i].length - 1] == tests[i].fill); + +#if defined(UX_DEVICE_CLASS_PRINTER_WRITE_AUTO_ZLP) + stepinfo(">>>>>>>>>>>>>>>> Test Read (Device Write) with auto ZLP %ld\n", tests[i].length); + status = tx_semaphore_put(&tx_test_semaphore_printer_trigger); + UX_TEST_CHECK_SUCCESS(status); + ux_utility_memory_set(host_buffer, ~tests[i].fill, tests[i].length); + status = ux_host_class_printer_read(host_printer, host_buffer, sizeof(host_buffer), &actual_length); + if (actual_length == 0) /* There could be ZLP. */ + status = ux_host_class_printer_read(host_printer, host_buffer, sizeof(host_buffer), &actual_length); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(tests[i].length == actual_length); + UX_TEST_ASSERT(host_buffer[0] == tests[i].fill); + UX_TEST_ASSERT(host_buffer[tests[i].length - 1] == tests[i].fill); +#endif + + } +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +ULONG mem_free; +ULONG loop; +ULONG parameter_u32[64/4]; +USHORT *parameter_u16 = (USHORT*)parameter_u32; +UCHAR *parameter_u8 = (UCHAR*)parameter_u32; + + + stepinfo("\n"); + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + status = ux_test_sleep_break_on_success(100, _test_check_host_connection_success); + UX_TEST_ASSERT(status == UX_SUCCESS); + + _printer_enumeration_test(); + _printer_requests_test(); + _printer_read_write_test(); + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + if (host_printer != UX_NULL) + { + + printf("ERROR #13: instance not removed when disconnect"); + test_control_return(1); + } + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_device_class_printer_name, _ux_device_class_printer_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); + tx_thread_relinquish(); +#else + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); +#endif + } +} diff --git a/test/regression/usbx_class_printer_device_standalone_basic_tests.c b/test/regression/usbx_class_printer_device_standalone_basic_tests.c new file mode 100644 index 00000000..0a439910 --- /dev/null +++ b/test/regression/usbx_class_printer_device_standalone_basic_tests.c @@ -0,0 +1,837 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_printer.h" +#include "ux_device_stack.h" +#include "ux_host_class_printer.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); + +static VOID ux_test_hcd_entry_should_not_be_called(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_disconnect(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +static UX_DEVICE *device = UX_NULL; +static UX_HOST_CLASS_PRINTER *host_printer = UX_NULL; +static UCHAR host_buffer[UX_DEMO_BUFFER_SIZE * 8]; + +static ULONG enum_counter; + +static ULONG error_counter; +static ULONG error_callback_counter; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_on_set_cfg; +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_enum_mem_alloc_count; + +static ULONG rsc_test_sem_usage; +static ULONG rsc_test_sem_get_count; +static ULONG rsc_test_mutex_usage; +static ULONG rsc_test_mem_alloc_count; + +static UX_DEVICE_CLASS_PRINTER *device_printer = UX_NULL; +static UX_DEVICE_CLASS_PRINTER_PARAMETER device_printer_parameter; +static UCHAR device_buffer[UX_DEMO_BUFFER_SIZE * 8]; +static ULONG device_buffer_length = 0; +static UCHAR device_printer_soft_reset_count = 0; +static ULONG device_read_length = UX_SLAVE_REQUEST_DATA_MAX_LENGTH; +UCHAR _ux_device_class_printer_name[] = "_ux_device_class_printer"; + +/* Device printer device ID. */ +static UCHAR printer_device_id[] = + { + " " // Will be replaced by length (big endian) + "MFG:Generic;" // manufacturer (case sensitive) + "MDL:Generic_/_Text_Only;" // model (case sensitive) + "CMD:1284.4;" // PDL command set + "CLS:PRINTER;" // class + "DES:Generic text only printer;" // description + }; + +/* Define device framework. */ + +#define _W0(w) ( (w) & 0xFF) +#define _W1(w) (((w) >> 8) & 0xFF) + +#define _CONFIGURATION_DESCRIPTOR(total_len, n_ifc, cfg_val) \ + 0x09, 0x02, _W0(total_len), _W1(total_len), (n_ifc), (cfg_val), \ + 0x00, 0xc0, 0x32, + +#define _INTERFACE_DESCRIPTOR(ifc_n, alt, n_ep, cls, sub, protocol) \ + 0x09, 0x04, (ifc_n), (alt), (n_ep), (cls), (sub), (protocol), 0x00, + +#define _ENDPOINT_DESCRIPTOR(addr, attr, pktsize, interval) \ + 0x07, 0x05, (addr), (attr), _W0(pktsize), _W1(pktsize), (interval), + +#define _CFG_TOTAL_LEN (9+9+7+7) + +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0xEF bDeviceClass: Composite class code + 0x02 bDeviceSubclass: class sub code + 0x00 bDeviceProtocol: Device protocol + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0x00, 0x00, 0x00, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 0x03, + 0x01, + + _CONFIGURATION_DESCRIPTOR(_CFG_TOTAL_LEN, 1, 1) + _INTERFACE_DESCRIPTOR(0, 0, 2, 0x07, 0x01, 0x02) + _ENDPOINT_DESCRIPTOR(0x01, 0x02, 64, 0x00) + _ENDPOINT_DESCRIPTOR(0x82, 0x02, 64, 0x00) +}; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_full_speed) +#define device_framework_high_speed device_framework_full_speed + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "AzureRTOS" */ + 0x09, 0x04, 0x01, 9, + 'A','z','u','r','e','R','T','O','S', + + /* Product string descriptor : Index 2 - "Printer device" */ + 0x09, 0x04, 0x02, 14, + 'P','r','i','n','t','e','r',' ','d','e','v','i','c','e', + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +/* Test interactions */ + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT test_slave_change_function(ULONG change) +{ + return 0; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_PRINTER *printer_inst = (UX_HOST_CLASS_PRINTER *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + host_printer = printer_inst; + break; + + case UX_DEVICE_REMOVAL: + if (host_printer == printer_inst) + host_printer = UX_NULL; + break; + + case UX_DEVICE_CONNECTION: + device = (UX_DEVICE *)inst; + break; + + case UX_DEVICE_DISCONNECTION: + if ((VOID *)device == inst) + device = UX_NULL; + break; + +#if defined(UX_HOST_STANDALONE) + case UX_STANDALONE_WAIT_BACKGROUND_TASK: + tx_thread_relinquish(); + break; +#endif + + default: + break; + } + return 0; +} + +static VOID test_printer_instance_activate(VOID *dummy_instance) +{ + if (device_printer == UX_NULL) + device_printer = (UX_DEVICE_CLASS_PRINTER *)dummy_instance; +} +static VOID test_printer_instance_deactivate(VOID *dummy_instance) +{ + if ((VOID*)device_printer == dummy_instance) + device_printer = UX_NULL; +} +static VOID test_printer_soft_reset(VOID *dummy_instance) +{ + device_printer_soft_reset_count ++; +} +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + error_callback_counter ++; +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_enum_sem_get_count = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_class_printer_device_standalone_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + printf("Running Host Class Printer Basic Functionality Test................. \n"); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* Initialize the free memory pointer */ + stack_pointer = (CHAR *) usbx_memory; + memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 4); + + /* 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 #1\n"); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + if (status != UX_SUCCESS) + { + + printf(" ERROR #2\n"); + test_control_return(1); + } + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_printer_name, ux_host_class_printer_entry); + if (status != UX_SUCCESS) + { + + printf(" ERROR #3\n"); + 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, + test_slave_change_function); + if(status!=UX_SUCCESS) + { + + printf(" ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a printer device. */ + _ux_utility_memory_set(&device_printer_parameter, 0, sizeof(device_printer_parameter)); + _ux_utility_short_put_big_endian(printer_device_id, sizeof(printer_device_id)); + device_printer_parameter.ux_device_class_printer_device_id = printer_device_id; + device_printer_parameter.ux_device_class_printer_instance_activate = test_printer_instance_activate; + device_printer_parameter.ux_device_class_printer_instance_deactivate = test_printer_instance_deactivate; + device_printer_parameter.ux_device_class_printer_soft_reset = test_printer_soft_reset; + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_device_class_printer_name, + _ux_device_class_printer_entry, + 1, 0, &device_printer_parameter); + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #8\n"); + 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 #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #9\n"); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + stack_pointer += UX_DEMO_STACK_SIZE; + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #10\n"); + test_control_return(1); + } +} + +static UINT _test_check_host_connection_error(VOID) +{ + if (device_printer && host_printer) + return(UX_SUCCESS); + if (error_callback_counter >= 3) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_connection_success(VOID) +{ + if (device_printer && host_printer) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_disconnection_success(VOID) +{ + if (device_printer == UX_NULL && host_printer == UX_NULL) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static VOID _printer_enumeration_test(VOID) +{ +UINT status; +ULONG mem_free; +ULONG test_n; + + stepinfo(">>>>>>>>>>>> Enumeration information collection\n"); + { + + /* Test disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check connection. */ + status = ux_test_sleep_break_on_success(100, _test_check_host_disconnection_success); + UX_TEST_ASSERT(status == UX_SUCCESS); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_count_reset(); + ux_test_utility_sim_mutex_create_count_reset(); + ux_test_utility_sim_sem_create_count_reset(); + ux_test_utility_sim_sem_get_count_reset(); + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + + /* Save free memory usage. */ + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Check connection. */ + status = ux_test_sleep_break_on_success(100, _test_check_host_connection_success); + UX_TEST_ASSERT(status == UX_SUCCESS); + + /* Log create counts for further tests. */ + rsc_enum_mutex_usage = rsc_mutex_on_set_cfg; + rsc_enum_sem_usage = rsc_sem_on_set_cfg; + rsc_enum_mem_alloc_count = rsc_mem_alloc_cnt_on_set_cfg; + /* Log create counts when instances active for further tests. */ + rsc_test_mutex_usage = ux_test_utility_sim_mutex_create_count() - rsc_enum_mutex_usage; + rsc_test_sem_usage = ux_test_utility_sim_sem_create_count() - rsc_enum_sem_usage; + rsc_test_mem_alloc_count = ux_test_utility_sim_mem_alloc_count() - rsc_enum_mem_alloc_count; + + /* Lock log base for tests. */ + ux_test_utility_sim_mem_alloc_log_lock(); + + stepinfo("enum mem: %ld\n", rsc_enum_mem_alloc_count); + stepinfo("test mem : %ld\n", rsc_test_mem_alloc_count); + stepinfo("mem free: %ld, %ld\n", _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); + } + + stepinfo(">>>>>>>>>>>> Enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < 3; test_n++) + { + stepinfo("%4ld / 2\n", test_n); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check */ + status = ux_test_sleep_break_on_success(100, _test_check_host_disconnection_success); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d.%ld: Disconnect fail\n", __LINE__, test_n); + test_control_return(1); + } + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Wait and break on error. */ + error_callback_counter = 0; + status = ux_test_sleep_break_on_success(100, _test_check_host_connection_error); + + /* Check */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d.%ld: Enumeration fail\n", __LINE__, test_n); + test_control_return(1); + } + } + stepinfo("\n"); + + if (rsc_test_mem_alloc_count) stepinfo(">>>>>>>>>>>> Memory errors enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_test_mem_alloc_count; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_test_mem_alloc_count - 1); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check */ + status = ux_test_sleep_break_on_success(100, _test_check_host_disconnection_success); + if (status != UX_SUCCESS) + { + + stepinfo("ERROR #%d.%ld: Disconnect fail\n", __LINE__, test_n); + test_control_return(1); + } + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + stepinfo("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Set memory error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n + rsc_enum_mem_alloc_count); + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on errors. */ + status = ux_test_sleep_break_on_success(100, _test_check_host_connection_error); + + /* Check error */ + if (status != UX_SUCCESS) + { + + /* Check error trap. */ + if (error_callback_counter == 0) + { + stepinfo("ERROR #%d.%ld: device detected when there is memory error\n", __LINE__, test_n); + test_control_return(1); + } + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + } + ux_test_utility_sim_mem_alloc_error_generation_stop(); + if (rsc_test_mem_alloc_count) stepinfo("\n"); + + /* If device disconnected, re-connect. */ + if (_test_check_host_connection_success() != UX_SUCCESS) + { + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Check */ + status = ux_test_sleep_break_on_success(100, _test_check_host_connection_success); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: Enumeration fail\n", __LINE__); + test_control_return(1); + } + } +} +static VOID _printer_requests_test(VOID) +{ +UINT status; +ULONG printer_port_status; + + stepinfo(">>>>>>>>>>>>>>>> Test GET_DEVICE_ID\n"); + status = ux_host_class_printer_device_id_get(host_printer, host_buffer, sizeof(host_buffer)); + UX_TEST_ASSERT(status == UX_SUCCESS); + + stepinfo(">>>>>>>>>>>>>>>> Test GET_PORT_STATUS\n"); + ux_device_class_printer_ioctl(device_printer, UX_DEVICE_CLASS_PRINTER_IOCTL_PORT_STATUS_SET, (VOID *)0x73); + status = ux_host_class_printer_status_get(host_printer, &printer_port_status); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(printer_port_status == 0x73); + + stepinfo(">>>>>>>>>>>>>>>> Test SOFT_RESET\n"); + device_printer_soft_reset_count = 0; + status = ux_host_class_printer_soft_reset(host_printer); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(device_printer_soft_reset_count == 1); +} + +static VOID _printer_read_write_test(VOID) +{ +struct _TEST_DEF { + ULONG fill; + ULONG length; + ULONG zlp; +} tests[] = { + {0x5A, 1, 0}, + {0x7E, 512, 1}, + {0xC2, 513, 0}, + {0x4C, UX_SLAVE_REQUEST_DATA_MAX_LENGTH, 1}, + {0xA5, UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1, 0}, + {0x3C, sizeof(device_buffer), 0}, + {0xC4, sizeof(device_buffer) - 1, 0}, +}; +#define _TEST_N (sizeof(tests)/sizeof(struct _TEST_DEF)) +INT i; +ULONG actual_length; +UINT status; + for(i = 0; i < _TEST_N; i ++) + { + + stepinfo(">>>>>>>>>>>>>>>> Test Write %ld\n", tests[i].length); + device_buffer_length = 0; + device_read_length = tests[i].length; + ux_utility_memory_set(device_buffer, ~tests[i].fill, tests[i].length); + ux_utility_memory_set(host_buffer, tests[i].fill, tests[i].length); + status = ux_host_class_printer_write(host_printer, host_buffer, tests[i].length, &actual_length); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(tests[i].length == actual_length); + if (tests[i].zlp) + { + status = ux_host_class_printer_write(host_printer, host_buffer, 0, &actual_length); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(0 == actual_length); + } + + /* Wait a while for background reception. */ + tx_thread_sleep(tests[i].length/64 + 1); + + UX_TEST_ASSERT(device_buffer_length == tests[i].length); + status = ux_utility_memory_compare(device_buffer, host_buffer, tests[i].length); + UX_TEST_ASSERT(status == UX_SUCCESS); + + stepinfo(">>>>>>>>>>>>>>>> Test Read %ld\n", tests[i].length); + UX_TEST_ASSERT(status == TX_SUCCESS); + ux_utility_memory_set(host_buffer, ~tests[i].fill, tests[i].length); + status = ux_host_class_printer_read(host_printer, host_buffer, tests[i].length, &actual_length); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(tests[i].length == actual_length); + UX_TEST_ASSERT(host_buffer[0] == tests[i].fill); + UX_TEST_ASSERT(host_buffer[tests[i].length - 1] == tests[i].fill); + } +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +ULONG mem_free; +ULONG loop; +ULONG parameter_u32[64/4]; +USHORT *parameter_u16 = (USHORT*)parameter_u32; +UCHAR *parameter_u8 = (UCHAR*)parameter_u32; + + + stepinfo("\n"); + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + status = ux_test_sleep_break_on_success(100, _test_check_host_connection_success); + UX_TEST_ASSERT(status == UX_SUCCESS); + +// _printer_enumeration_test(); + _printer_requests_test(); + + + _printer_read_write_test(); + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + if (host_printer != UX_NULL) + { + + printf("ERROR #13: instance not removed when disconnect"); + test_control_return(1); + } + + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_device_class_printer_name, _ux_device_class_printer_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ +UINT status; +ULONG actual_length; +ULONG read_length = device_read_length; +ULONG write_length, write_zlp = UX_FALSE; +#define PRINTER_DEVICE_STATE_READ UX_STATE_STEP +#define PRINTER_DEVICE_STATE_WRITE UX_STATE_STEP + 1 +#define PRINTER_DEVICE_STATE_ZLP UX_STATE_STEP + 2 +UINT printer_device_state = UX_STATE_RESET; + + while(1) + { + ux_system_tasks_run(); + + /* Reset state if read length changed. */ + // if (read_length != device_read_length) + // { + // printer_device_state = UX_STATE_RESET; + // read_length = device_read_length; + // } + + switch(printer_device_state) + { + case UX_STATE_RESET: + if (device_printer != UX_NULL) + { + printer_device_state = PRINTER_DEVICE_STATE_READ; + } + break; + + case PRINTER_DEVICE_STATE_READ: + if (device_printer == UX_NULL) + { + printer_device_state = UX_STATE_RESET; + break; + } + status = ux_device_class_printer_read_run(device_printer, device_buffer, sizeof(device_buffer), &actual_length); + if (status < UX_STATE_NEXT) + { + printf("ERROR #%d: read status 0x%x\n", __LINE__, status); + return; + } + if (status == UX_STATE_NEXT) + { + if (actual_length == 0) + { + printer_device_state = UX_STATE_RESET; + break; + } + write_length = actual_length; + printer_device_state = PRINTER_DEVICE_STATE_WRITE; + device_buffer_length = actual_length; + } + break; + + case PRINTER_DEVICE_STATE_WRITE: + if (device_printer == UX_NULL) + { + printer_device_state = UX_STATE_RESET; + break; + } + status = ux_device_class_printer_write_run(device_printer, device_buffer, write_length, &actual_length); + if (status < UX_STATE_NEXT) + { + printf("ERROR #%d: write status 0x%x\n", __LINE__, status); + return; + } + if (status == UX_STATE_NEXT) + { + printer_device_state = PRINTER_DEVICE_STATE_READ; + break; + } + + case PRINTER_DEVICE_STATE_ZLP: + if (device_printer == UX_NULL) + { + printer_device_state = UX_STATE_RESET; + break; + } + status = ux_device_class_printer_write_run(device_printer, device_buffer, 0, &actual_length); + if (status < UX_STATE_NEXT) + { + printf("ERROR #%d: ZLP status 0x%x\n", __LINE__, status); + return; + } + if (status == UX_STATE_NEXT) + printer_device_state = PRINTER_DEVICE_STATE_READ; + + break; + + default: + printer_device_state = UX_STATE_RESET; + } + + /* Let other threads run. */ + tx_thread_relinquish(); + } +} diff --git a/test/regression/usbx_control_transfer_stall_test.c b/test/regression/usbx_control_transfer_stall_test.c new file mode 100644 index 00000000..a8901b9a --- /dev/null +++ b/test/regression/usbx_control_transfer_stall_test.c @@ -0,0 +1,377 @@ +/* This tests ensures that when the device stalls the default endpoint upon an invalid request, it is unstalled after sending a valid request. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_TRANSFER_STALLED) + { + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } +} + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_control_transfer_stall_test(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running Control Transfer Stall 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_KEYBOARD *keyboard; +UX_ENDPOINT *endpoint; +UX_TRANSFER *transfer_request; +UCHAR descriptor[1024]; + + /* 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); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the keyboard instance */ + keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)hid_client -> ux_host_class_hid_client_local_instance; + + /* Get default endpoint. */ + endpoint = &hid->ux_host_class_hid_device->ux_device_control_endpoint; + + /* Get the transfer request. */ + transfer_request = &endpoint->ux_endpoint_transfer_request; + + /* Stall the default endpoint by sending it an invalid request. */ + + /* Create a transfer request for an invalid request. */ + transfer_request -> ux_transfer_request_data_pointer = descriptor; + transfer_request -> ux_transfer_request_requested_length = 0x09; + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = 0xffff << 8; + transfer_request -> ux_transfer_request_index = 0x02; + + /* Send request to HCD layer. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Now send it a valid request. */ + + /* Create a transfer request for a valid request. */ + transfer_request -> ux_transfer_request_data_pointer = descriptor; + transfer_request -> ux_transfer_request_requested_length = UX_CONFIGURATION_DESCRIPTOR_LENGTH; + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = UX_CONFIGURATION_DESCRIPTOR_ITEM << 8; + transfer_request -> ux_transfer_request_index = 0x02; + + /* Send request to HCD layer. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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_device_class_ccid_basic_tests.c b/test/regression/usbx_device_class_ccid_basic_tests.c new file mode 100644 index 00000000..f9087c33 --- /dev/null +++ b/test/regression/usbx_device_class_ccid_basic_tests.c @@ -0,0 +1,1640 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_device_class_ccid.h" +#include "ux_device_stack.h" + +#include "ux_host_class_dummy.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +#define UX_DEMO_MAX_SLOT_INDEX (2) +#define UX_DEMO_MAX_BUSY_SLOTS (2) +#if UX_SLAVE_REQUEST_DATA_MAX_LENGTH >= 1024 +#define UX_DEMO_MAX_MESSAGE_LENGTH (1024) +#else +#define UX_DEMO_MAX_MESSAGE_LENGTH (UX_SLAVE_REQUEST_DATA_MAX_LENGTH) +#endif +#define UX_DEMO_N_CLOCKS (1) +#define UX_DEMO_N_DATA_RATES (1) +#define UX_DEMO_BULK_OUT_EP 0x02 +#define UX_DEMO_BULK_IN_EP 0x81 +#define UX_DEMO_INTERRUPT_IN_EP 0x83 +#define UX_DEMO_INTERRUPT_IN_SIZE (8) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); + +static VOID ux_test_hcd_entry_should_not_be_called(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_disconnect(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +static UINT ux_test_ccid_icc_power_on(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_icc_power_off(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_get_slot_status(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_xfr_block(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_get_parameters(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_reset_parameters(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_set_parameters(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_escape(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_icc_clock(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_t0_apdu(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_secure(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_mechanical(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_abort(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_set_data_rate_and_clock_frequency(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +static UX_DEVICE *host_device = UX_NULL; +static UCHAR host_bulk_out[UX_DEMO_MAX_MESSAGE_LENGTH]; +static UCHAR host_bulk_in[UX_DEMO_MAX_MESSAGE_LENGTH]; +static ULONG host_bulk_in_length; +static UCHAR host_interrupt_in[UX_DEMO_INTERRUPT_IN_SIZE]; +static ULONG host_interrupt_in_length; + +static UX_HOST_CLASS_DUMMY *host_ccid = UX_NULL; + +static ULONG enum_counter; + +static ULONG error_counter; +static ULONG error_callback_counter; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_on_set_cfg; +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_enum_mem_alloc_count; + +static ULONG rsc_test_sem_usage; +static ULONG rsc_test_sem_get_count; +static ULONG rsc_test_mutex_usage; +static ULONG rsc_test_mem_alloc_count; + +static UX_DEVICE_CLASS_CCID_HANDLES device_ccid_handles = +{ + ux_test_ccid_icc_power_on, + ux_test_ccid_icc_power_off, + ux_test_ccid_get_slot_status, + ux_test_ccid_xfr_block, + ux_test_ccid_get_parameters, + ux_test_ccid_reset_parameters, + ux_test_ccid_set_parameters, + ux_test_ccid_escape, + ux_test_ccid_icc_clock, + ux_test_ccid_t0_apdu, + ux_test_ccid_secure, + ux_test_ccid_mechanical, + ux_test_ccid_abort, + ux_test_ccid_set_data_rate_and_clock_frequency, +}; +static ULONG device_ccid_clocks[] = +{ + 1200, +}; +static ULONG device_ccid_data_rates[] = +{ + 115200, +}; +static UX_DEVICE_CLASS_CCID *device_ccid = UX_NULL; +static UX_DEVICE_CLASS_CCID_PARAMETER device_ccid_parameter; +static UCHAR device_ccid_soft_reset_count = 0; + +static struct _TEST_CCID_CALLBACK_LOG { + UX_DEVICE_CLASS_CCID_HANDLE handle; + ULONG buf_length; + UCHAR buf[UX_DEMO_MAX_MESSAGE_LENGTH + 4]; +} device_ccid_callback_log; +static inline void ux_test_callback_log(UX_DEVICE_CLASS_CCID_HANDLE handle, UCHAR *ccid_msg) +{ +ULONG buf_length; + device_ccid_callback_log.handle = handle; + if (ccid_msg == UX_NULL) + { + device_ccid_callback_log.buf[0] = 0; + device_ccid_callback_log.buf_length = 0; + return; + } + buf_length = UX_DEVICE_CLASS_CCID_MESSAGE_LENGTH_GET(ccid_msg) + UX_DEVICE_CLASS_CCID_MESSAGE_HEADER_LENGTH; + UX_TEST_ASSERT(buf_length <= UX_DEMO_MAX_MESSAGE_LENGTH); + _ux_utility_memory_copy(device_ccid_callback_log.buf, ccid_msg, buf_length); + device_ccid_callback_log.buf_length = buf_length; +} + +/* Define device framework. */ + +#define _W(w) UX_W0(w),UX_W1(w) +#define _DW(dw) UX_DW0(dw),UX_DW1(dw),UX_DW2(dw),UX_DW3(dw) + +#define _CONFIGURATION_DESCRIPTOR(total_len, n_ifc, cfg_val) \ + 0x09, 0x02, UX_W0(total_len), UX_W1(total_len), (n_ifc), (cfg_val), \ + 0x00, 0xc0, 0x32, + +#define _INTERFACE_DESCRIPTOR(ifc_n, alt, n_ep, cls, sub, protocol) \ + 0x09, 0x04, (ifc_n), (alt), (n_ep), (cls), (sub), (protocol), 0x00, + +#define _SMART_CARD_DESCRIPTORS \ + 0x36, /* bLength. */ \ + 0x21, /* bDescriptorType. */ \ + 0x10, 0x01, /* bcdCCID. */ \ + UX_DEMO_MAX_SLOT_INDEX, /* bMaxSlotIndex. */ \ + 0x01, /* bVoltageSupport (1-5V,2-3.0V,4-1.8V). */ \ + 0x00, 0x00, 0x00, 0x00, /* dwProtocols PPPP, RRRR. */ \ + _DW(14320), /* dwDefaultClock (KHz). */ \ + _DW(14320), /* dwMaximumClock (KHz). */ \ + UX_DEMO_N_CLOCKS, /* bNumClockSupported. */ \ + _DW(115200), /* dwDataRate (bps). */ \ + _DW(115200), /* dwMaxDataRate (bps). */ \ + UX_DEMO_N_DATA_RATES, /* bNumDataRatesSupported. */ \ + 0x00, 0x00, 0x00, 0x00, /* dwMaxIFSD. */ \ + 0x00, 0x00, 0x00, 0x00, /* dwSynchProtocols PPPP, RRRR. */ \ + 0x00, 0x00, 0x00, 0x00, /* dwMechanical (1-accept,2-eject,4-capture,8-lock/unlock). */\ + 0x00, 0x00, 0x00, 0x00, /* dwFeatures. */ \ + _DW(1024), /* dwMaxCCIDMessageLength. */ \ + 0, /* bClassGetResponse. */ \ + 0, /* bClassEnvelope. */ \ + _W(0x0000), /* wLcdLayout, XXYY. */ \ + 0x3, /* bPINSupport, 1-Verification, 2-Modification. */ \ + UX_DEMO_MAX_BUSY_SLOTS, /* bMaxCCIDBusySlots. */ + + +#define _ENDPOINT_DESCRIPTOR(addr, attr, pktsize, interval) \ + 0x07, 0x05, (addr), (attr), UX_W0(pktsize), UX_W1(pktsize), (interval), + +#define _CFG_TOTAL_LEN (9+9+0x36+7+7+7) + +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0xEF bDeviceClass: Composite class code + 0x02 bDeviceSubclass: class sub code + 0x00 bDeviceProtocol: Device protocol + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0x00, 0x00, 0x00, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 0x03, + 0x01, + + _CONFIGURATION_DESCRIPTOR(_CFG_TOTAL_LEN, 1, 1) + _INTERFACE_DESCRIPTOR(0, 0, 3, 0x0B, 0x00, 0x00) + _SMART_CARD_DESCRIPTORS + _ENDPOINT_DESCRIPTOR(UX_DEMO_BULK_OUT_EP, 0x02, 64, 0x00) + _ENDPOINT_DESCRIPTOR(UX_DEMO_BULK_IN_EP, 0x02, 64, 0x00) + _ENDPOINT_DESCRIPTOR(UX_DEMO_INTERRUPT_IN_EP, 0x03, UX_DEMO_INTERRUPT_IN_SIZE, 0x04) +}; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_full_speed) +#define device_framework_high_speed device_framework_full_speed + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "AzureRTOS" */ + 0x09, 0x04, 0x01, 9, + 'A','z','u','r','e','R','T','O','S', + + /* Product string descriptor : Index 2 - "ccid device" */ + 0x09, 0x04, 0x02, 11, + 'C','C','I','D',' ','d','e','v','i','c','e', + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +/* Test interactions */ + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT test_slave_change_function(ULONG change) +{ + return 0; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + // printf("hCbChange: %lx %p %p\n", event, (VOID*)cls, inst); + switch(event) + { + + case UX_DEVICE_INSERTION: + host_ccid = inst; + break; + + case UX_DEVICE_REMOVAL: + if (host_ccid == inst) + host_ccid = UX_NULL; + break; + + case UX_DEVICE_CONNECTION: + host_device = (UX_DEVICE *)inst; + break; + + case UX_DEVICE_DISCONNECTION: + if ((VOID *)host_device == inst) + host_device = UX_NULL; + break; + +#if defined(UX_HOST_STANDALONE) + case UX_STANDALONE_WAIT_BACKGROUND_TASK: + tx_thread_relinquish(); + break; +#endif + + default: + break; + } + return 0; +} + +static VOID test_ccid_instance_activate(VOID *dummy_instance) +{ + if (device_ccid == UX_NULL) + device_ccid = (UX_DEVICE_CLASS_CCID *)dummy_instance; +} +static VOID test_ccid_instance_deactivate(VOID *dummy_instance) +{ + if ((VOID*)device_ccid == dummy_instance) + device_ccid = UX_NULL; +} +static VOID test_ccid_soft_reset(VOID *dummy_instance) +{ + device_ccid_soft_reset_count ++; +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + error_callback_counter ++; +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_enum_sem_get_count = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_host_class_ccid_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + printf("Running CCID Basic Functionality Test............................... "); +#if !UX_TEST_MULTI_EP_OVER(2) + printf("Skip\n"); + test_control_return(0); + return; +#endif + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* Initialize the free memory pointer */ + stack_pointer = (CHAR *) usbx_memory; + memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 4); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + if (status != UX_SUCCESS) + { + + printf(" ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register Host DUMMY class. */ + status = ux_host_stack_class_register(_ux_host_class_dummy_name, _ux_host_class_dummy_entry); + if (status != UX_SUCCESS) + { + + printf(" ERROR #3\n"); + 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, + test_slave_change_function); + if(status!=UX_SUCCESS) + { + + printf(" ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a ccid device. */ + _ux_utility_memory_set(&device_ccid_parameter, 0, sizeof(device_ccid_parameter)); + device_ccid_parameter.ux_device_class_ccid_handles = &device_ccid_handles; + device_ccid_parameter.ux_device_class_ccid_instance_activate = test_ccid_instance_activate; + device_ccid_parameter.ux_device_class_ccid_instance_deactivate = test_ccid_instance_deactivate; + device_ccid_parameter.ux_device_class_ccid_max_n_slots = UX_DEMO_MAX_SLOT_INDEX + 1; + device_ccid_parameter.ux_device_class_ccid_max_n_busy_slots = UX_DEMO_MAX_BUSY_SLOTS; + device_ccid_parameter.ux_device_class_ccid_max_transfer_length = UX_DEMO_MAX_MESSAGE_LENGTH; + device_ccid_parameter.ux_device_class_ccid_n_clocks = UX_DEMO_N_CLOCKS; + device_ccid_parameter.ux_device_class_ccid_n_data_rates = UX_DEMO_N_DATA_RATES; + device_ccid_parameter.ux_device_class_ccid_clocks = device_ccid_clocks; + device_ccid_parameter.ux_device_class_ccid_data_rates = device_ccid_data_rates; + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_device_class_ccid_name, + ux_device_class_ccid_entry, + 1, 0, &device_ccid_parameter); + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_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(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #9\n"); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + stack_pointer += UX_DEMO_STACK_SIZE; + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #10\n"); + test_control_return(1); + } +} + +static UINT _test_check_host_connection_error(VOID) +{ + if (device_ccid && host_ccid) + return(UX_SUCCESS); + if (error_callback_counter >= 3) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_connection_success(VOID) +{ + if (device_ccid && host_ccid) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_disconnection_success(VOID) +{ + if (device_ccid == UX_NULL && host_ccid == UX_NULL) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static VOID _ccid_enumeration_test(VOID) +{ +UINT status; +ULONG mem_free; +ULONG test_n; + + stepinfo(">>>>>>>>>>>> Enumeration information collection\n"); + { + + /* Test disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check connection. */ + status = ux_test_sleep_break_on_success(200, _test_check_host_disconnection_success); + UX_TEST_ASSERT(status == UX_SUCCESS); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_count_reset(); + ux_test_utility_sim_mutex_create_count_reset(); + ux_test_utility_sim_sem_create_count_reset(); + ux_test_utility_sim_sem_get_count_reset(); + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + + /* Save free memory usage. */ + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Check connection. */ + status = ux_test_sleep_break_on_success(100, _test_check_host_connection_success); + UX_TEST_ASSERT(status == UX_SUCCESS); + + /* Log create counts for further tests. */ + rsc_enum_mutex_usage = rsc_mutex_on_set_cfg; + rsc_enum_sem_usage = rsc_sem_on_set_cfg; + rsc_enum_mem_alloc_count = rsc_mem_alloc_cnt_on_set_cfg; + /* Log create counts when instances active for further tests. */ + rsc_test_mutex_usage = ux_test_utility_sim_mutex_create_count() - rsc_enum_mutex_usage; + rsc_test_sem_usage = ux_test_utility_sim_sem_create_count() - rsc_enum_sem_usage; + rsc_test_mem_alloc_count = ux_test_utility_sim_mem_alloc_count() - rsc_enum_mem_alloc_count; + + /* Lock log base for tests. */ + ux_test_utility_sim_mem_alloc_log_lock(); + + stepinfo("enum mem: %ld\n", rsc_enum_mem_alloc_count); + stepinfo("test mem : %ld\n", rsc_test_mem_alloc_count); + stepinfo("mem free: %ld, %ld\n", _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); + } + + stepinfo(">>>>>>>>>>>> Enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < 3; test_n++) + { + stepinfo("%4ld / 2\n", test_n); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check */ + status = ux_test_sleep_break_on_success(100, _test_check_host_disconnection_success); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d.%ld: Disconnect fail\n", __LINE__, test_n); + test_control_return(1); + } + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Wait and break on error. */ + error_callback_counter = 0; + status = ux_test_sleep_break_on_success(100, _test_check_host_connection_error); + + /* Check */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d.%ld: Enumeration fail\n", __LINE__, test_n); + test_control_return(1); + } + } + stepinfo("\n"); + + if (rsc_test_mem_alloc_count) stepinfo(">>>>>>>>>>>> Memory errors enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_test_mem_alloc_count; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_test_mem_alloc_count - 1); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check */ + status = ux_test_sleep_break_on_success(100, _test_check_host_disconnection_success); + if (status != UX_SUCCESS) + { + + stepinfo("ERROR #%d.%ld: Disconnect fail\n", __LINE__, test_n); + test_control_return(1); + } + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + stepinfo("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Set memory error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n + rsc_enum_mem_alloc_count); + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on errors. */ + status = ux_test_sleep_break_on_success(100, _test_check_host_connection_error); + + /* Check error */ + if (status != UX_SUCCESS) + { + + /* Check error trap. */ + if (error_callback_counter == 0) + { + stepinfo("ERROR #%d.%ld: device detected when there is memory error\n", __LINE__, test_n); + test_control_return(1); + } + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + } + ux_test_utility_sim_mem_alloc_error_generation_stop(); + if (rsc_test_mem_alloc_count) stepinfo("\n"); + + /* If device disconnected, re-connect. */ + if (_test_check_host_connection_success() != UX_SUCCESS) + { + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Check */ + status = ux_test_sleep_break_on_success(100, _test_check_host_connection_success); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: Enumeration fail\n", __LINE__); + test_control_return(1); + } + } +} + +static UINT _ccid_message_bulk_out_in(UCHAR *out, ULONG out_length, UCHAR *in, ULONG *in_length) +{ +ULONG payload_size; +ULONG total_length, actual_length; +UINT status = UX_FUNCTION_NOT_SUPPORTED; + if (out) + { + total_length = out_length; + status = _ux_host_class_dummy_transfer(host_ccid, UX_DEMO_BULK_OUT_EP, 0, out, total_length, &actual_length); + if (status != UX_SUCCESS) + { + printf("BulkOUT fail: 0x%x\n", status); + return(status); + } + } + if (in) + { + payload_size = _ux_host_class_dummy_get_max_payload_size(host_ccid, UX_DEMO_BULK_IN_EP, 0); + while(1) + { + status = _ux_host_class_dummy_transfer(host_ccid, UX_DEMO_BULK_IN_EP, 0, in, payload_size, &actual_length); + *in_length = actual_length; + if (status != UX_SUCCESS) + { + printf("BulkIN fail: 0x%x\n", status); + return(status); + } + /* Check time extension. */ + if (((in[7] >> 6) & 0x3u) == 0x2) + { + /* Try to read another packet. */ + // printf("TimeExtension\n"); + continue; + } + /* Check short packet. */ + if (actual_length < payload_size) + return(status); + else + break; + } + /* Read remaining message. */ + total_length = UX_DEVICE_CLASS_CCID_MESSAGE_LENGTH_GET(in); + total_length += UX_DEVICE_CLASS_CCID_MESSAGE_HEADER_LENGTH; + //printf("FirstPacket, total %ld\n", total_length); + in += payload_size; + total_length -= payload_size; + if (total_length) + { + status = _ux_host_class_dummy_transfer(host_ccid, UX_DEMO_BULK_IN_EP, 0, in, total_length, &actual_length); + *in_length += actual_length; + } + } + else + { + /* Let other threads run. */ + tx_thread_sleep(1); + } + return(status); +} + +static UINT _ccid_message_interrupt_in(UCHAR *in, ULONG *in_length) +{ +ULONG payload_size = _ux_host_class_dummy_get_max_payload_size(host_ccid, UX_DEMO_INTERRUPT_IN_EP, 0); +UINT status; + status = _ux_host_class_dummy_transfer(host_ccid, UX_DEMO_INTERRUPT_IN_EP, 0, in, payload_size, in_length); + return(status); +} + + +#define _TEST_CCID_BULK_OUT_CHECK(h, l) \ + UX_TEST_ASSERT(status == UX_SUCCESS); \ + UX_TEST_ASSERT(device_ccid_callback_log.handle == (h)); \ + if ((h) != UX_NULL) { \ + UX_TEST_ASSERT(device_ccid_callback_log.buf_length == (l)); \ + UX_TEST_ASSERT(_ux_utility_memory_compare(device_ccid_callback_log.buf, host_bulk_out, (l)) == UX_SUCCESS); \ + } + +#define _TEST_CCID_BULK_IN_HEADER_CHECK(type,len,slot,seq,stat,err) \ + UX_TEST_ASSERT(host_bulk_in[0] == (type));\ + UX_TEST_ASSERT((len) == _ux_utility_long_get(host_bulk_in + 1));\ + UX_TEST_ASSERT(host_bulk_in[5] == (slot));\ + UX_TEST_ASSERT(host_bulk_in[6] == (seq));\ + UX_TEST_ASSERT(host_bulk_in[7] == (stat)); /* bStatus: not present. */\ + UX_TEST_ASSERT(host_bulk_in[8] == (err)); + +static VOID _buffer_dump(VOID *buf, ULONG len) +{ +ULONG i; + for(i = 0; i < len; i ++) + printf(" %02x", ((UCHAR *)buf)[i]); + printf("\n"); +} + +static VOID _ccid_icc_insert_test(VOID) +{ +UINT status; + + stepinfo(">>>>>>>>>> Test Insert\n"); + ux_device_class_ccid_icc_insert(device_ccid, 0, 0); + ux_device_class_ccid_icc_insert(device_ccid, 1, 0); + status = _ccid_message_interrupt_in(host_interrupt_in, &host_interrupt_in_length); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(host_interrupt_in_length == 2); + UX_TEST_ASSERT(host_interrupt_in[0] == 0x50); + +#if UX_DEVICE_CLASS_CCID_MAX_N_SLOTS > 1 + if (host_interrupt_in[1] == 0x03) + { + status = _ccid_message_interrupt_in(host_interrupt_in, &host_interrupt_in_length); + UX_TEST_ASSERT(host_interrupt_in_length == 2); + UX_TEST_ASSERT(host_interrupt_in[0] == 0x50); + UX_TEST_ASSERT(host_interrupt_in[1] == 0x0D); /* Slot0: exist, Slot1: insert. */ + } + else + UX_TEST_ASSERT(host_interrupt_in[1] == 0x0F); +#else + UX_TEST_ASSERT(host_interrupt_in[1] == 0x03); /* Slot0: exist. */ +#endif + +#if UX_DEVICE_CLASS_CCID_MAX_N_SLOTS > 1 + #define _RM_SLOT 1 + #define _RM_CHECK 0x09 /* Slot0: exist, Slot1: remove. */ +#else + #define _RM_SLOT 0 + #define _RM_CHECK 0x02 /* Slot0: remove, Slot1: remove. */ +#endif + stepinfo(">>>>>>>>>> Test Remove\n"); + ux_device_class_ccid_icc_remove(device_ccid, _RM_SLOT); + status = _ccid_message_interrupt_in(host_interrupt_in, &host_interrupt_in_length); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(host_interrupt_in_length == 2); + UX_TEST_ASSERT(host_interrupt_in[0] == 0x50); + UX_TEST_ASSERT(host_interrupt_in[1] == _RM_CHECK); + +#if UX_DEVICE_CLASS_CCID_MAX_N_SLOTS > 1 + #define _INS_SLOT 1 + #define _INS_CHECK 0x0D /* Slot0: exist, Slot1: insert. */ +#else + #define _INS_SLOT 0 + #define _INS_CHECK 0x03 /* Slot0: insert, Slot1: remove. */ +#endif + stepinfo(">>>>>>>>>> Test Insert (auto)\n"); + ux_device_class_ccid_icc_insert(device_ccid, _INS_SLOT, 1); + status = _ccid_message_interrupt_in(host_interrupt_in, &host_interrupt_in_length); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(host_interrupt_in_length == 2); + UX_TEST_ASSERT(host_interrupt_in[0] == 0x50); + UX_TEST_ASSERT(host_interrupt_in[1] == _INS_CHECK); /* Slot0: exist, Slot1: insert. */ +} + +static VOID _ccid_icc_power_on_off_test(VOID) +{ +UINT status; + /* PC_to_RDR_IccPowerOn, RDR_to_PC_DataBlock */ + + /* Message(IccPowerOn). */ + stepinfo(">>>>>>>>>> Test IccPowerOn\n"); + _ux_utility_memory_set(host_bulk_out, 0, 10); + host_bulk_out[0] = 0x62; + host_bulk_out[5] = 0; /* bSlot. */ + host_bulk_out[6] = 0; /* bSeq. */ + _ux_utility_long_put(host_bulk_out+1, 0); + host_bulk_out[7] = 2; + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_icc_power_on, 10) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x80, 0, 0, 0, 0, 0) + +#if UX_DEVICE_CLASS_CCID_MAX_N_SLOTS > 1 + + /* Message(IccPowerOff). */ + stepinfo(">>>>>>>>>> Test IccPowerOff\n"); + host_bulk_out[0] = 0x63; + host_bulk_out[5] = 0; /* bSlot. */ + host_bulk_out[6] = 1; /* bSeq. */ + host_bulk_out[7] = 0; + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_icc_power_off, 10) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x81, 0, 0, 1, 1, 0) + + /* Message(IccPowerOff) -> BUSY_WITH_AUTO_SEQUENCE. */ + stepinfo(">>>>>>>>>> Test IccPowerOff -> BUSY_WITH_AUTO_SEQUENCE\n"); + host_bulk_out[0] = 0x63; + host_bulk_out[5] = 1; /* bSlot. */ + host_bulk_out[6] = 0; /* bSeq. */ + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(UX_NULL, 10) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x81, 0, 1, 0, 0x41, 0xF2) + + /* Message(IccPowerOff). */ + stepinfo(">>>>>>>>>> Test seq done - IccPowerOff\n"); + ux_device_class_ccid_auto_seq_done(device_ccid, 1, UX_DEVICE_CLASS_CCID_ICC_ACTIVE); + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_icc_power_off, 10) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x81, 0, 1, 0, 1, 0) +#else + + /* Message(IccPowerOff) -> BUSY_WITH_AUTO_SEQUENCE. */ + stepinfo(">>>>>>>>>> Test IccPowerOff -> BUSY_WITH_AUTO_SEQUENCE\n"); + host_bulk_out[0] = 0x63; + host_bulk_out[5] = 0; /* bSlot. */ + host_bulk_out[6] = 1; /* bSeq. */ + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(UX_NULL, 10) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x81, 0, 0, 1, 0x41, 0xF2) + + /* Message(IccPowerOff). */ + stepinfo(">>>>>>>>>> Test seq done - IccPowerOff\n"); + ux_device_class_ccid_auto_seq_done(device_ccid, 0, UX_DEVICE_CLASS_CCID_ICC_ACTIVE); + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_icc_power_off, 10) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x81, 0, 0, 1, 1, 0) +#endif + + /* Message(IccPowerOn). */ + host_bulk_out[0] = 0x62; + host_bulk_out[5] = 0; /* bSlot. */ + host_bulk_out[6] = 3; /* bSeq. */ + host_bulk_out[7] = 1; + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_icc_power_on, 10) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x80, 0, 0, 3, 0, 0) +} + +static VOID _ccid_get_slot_status_test(VOID) +{ +UINT status; + /* PC_to_RDR_GetSlotStatus, RDR_to_PC_SlotStatus */ + _ux_utility_memory_set(host_bulk_out, 0, 10); + host_bulk_out[0] = 0x65; + host_bulk_out[5] = 0; /* bSlot. */ + host_bulk_out[6] = 0; /* bSeq. */ + _ux_utility_long_put(host_bulk_out+1, 0); + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_get_slot_status, 10) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x81, 0, 0, 0, 0, 0) +} + +static VOID _ccid_xfr_block_test(VOID) +{ +UINT status; + /* PC_to_RDR_XfrBlock, RDR_to_PC_DataBlock. */ + _ux_utility_memory_set(host_bulk_out, 0, 10); + host_bulk_out[0] = 0x6F; + host_bulk_out[5] = 0; /* bSlot. */ + host_bulk_out[6] = 8; /* bSeq. */ + _ux_utility_long_put(host_bulk_out+1, 0); + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_xfr_block, 10) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x80, 64-10, 0, 8, 0, 0) +} + +static VOID _ccid_parameters_test(VOID) +{ +UINT status; + /* PC_to_RDR_[Get/Reset/Set]Parameters, RDR_to_PC_Parameters. */ + _ux_utility_memory_set(host_bulk_out, 0, 10); + + /* GetParameters. */ + host_bulk_out[0] = 0x6C; + host_bulk_out[5] = 0; /* bSlot. */ + host_bulk_out[6] = 9; /* bSeq. */ + _ux_utility_long_put(host_bulk_out+1, 0); + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_get_parameters, 10) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x82, 5, 0, 9, 0, 0) + + /* ResetParameters. */ + host_bulk_out[0] = 0x6D; + host_bulk_out[5] = 0; /* bSlot. */ + host_bulk_out[6] = 10; /* bSeq. */ + _ux_utility_long_put(host_bulk_out+1, 0); + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_reset_parameters, 10) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x82, 5, 0, 10, 0, 0) + + /* SetParameters. */ + host_bulk_out[0] = 0x61; + host_bulk_out[5] = 0; /* bSlot. */ + host_bulk_out[6] = 11; /* bSeq. */ + _ux_utility_long_put(host_bulk_out+1, 0); + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_set_parameters, 10) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x82, 5, 0, 11, 0, 0) + +} + +static VOID _ccid_escape_test(VOID) +{ +UINT status; + /* PC_to_RDR_Escape, RDR_to_PC_Escape. */ + _ux_utility_memory_set(host_bulk_out, 0, 10); + + /* GetParameters. */ + host_bulk_out[0] = 0x6B; + host_bulk_out[5] = 0; /* bSlot. */ + host_bulk_out[6] = 11; /* bSeq. */ + _ux_utility_long_put(host_bulk_out+1, 4); + host_bulk_out[10] = 1; + host_bulk_out[10] = 2; + host_bulk_out[10] = 3; + host_bulk_out[10] = 4; + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10+4, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_escape, 14) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x83, 128, 0, 11, 0, 0) +} + +static VOID _ccid_icc_clock_test(VOID) +{ +UINT status; + /* PC_to_RDR_IccClock, RDR_to_PC_SlotStatus. */ + _ux_utility_memory_set(host_bulk_out, 0, 10); + + /* GetParameters. */ + host_bulk_out[0] = 0x6E; + host_bulk_out[5] = 0; /* bSlot. */ + host_bulk_out[6] = 88; /* bSeq. */ + _ux_utility_long_put(host_bulk_out+1, 0); + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_icc_clock, 10) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x81, 0, 0, 88, 0, 0) +} + +static VOID _ccid_t0_apdu_test(VOID) +{ +UINT status; + /* PC_to_RDR_T0APDU, RDR_to_PC_SlotStatus. */ + _ux_utility_memory_set(host_bulk_out, 0, 10); + + /* GetParameters. */ + host_bulk_out[0] = 0x6A; + host_bulk_out[5] = 0; /* bSlot. */ + host_bulk_out[6] = 1; /* bSeq. */ + _ux_utility_long_put(host_bulk_out+1, 0); + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_t0_apdu, 10) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x81, 0, 0, 1, 0, 0) +} + +static VOID _ccid_secure_test(VOID) +{ +UINT status; + /* PC_to_RDR_Secure, RDR_to_PC_DataBlock. */ + _ux_utility_memory_set(host_bulk_out, 0, 10); + + /* GetParameters. */ + host_bulk_out[0] = 0x69; + host_bulk_out[5] = 0; /* bSlot. */ + host_bulk_out[6] = 5; /* bSeq. */ + _ux_utility_long_put(host_bulk_out+1, 63-10); + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 63, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_secure, 63) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x80, 128/8, 0, 5, 0, 0) +} + +static VOID _ccid_mechanical_test(VOID) +{ +UINT status; + /* PC_to_RDR_Mechanical, RDR_to_PC_SlotStatus. */ + _ux_utility_memory_set(host_bulk_out, 0, 10); + + /* GetParameters. */ + host_bulk_out[0] = 0x71; + host_bulk_out[5] = 0; /* bSlot. */ + host_bulk_out[6] = 50; /* bSeq. */ + host_bulk_out[7] = 0x4; /* bFunction. */ + _ux_utility_long_put(host_bulk_out+1, 0); + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_mechanical, 10) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x81, 0, 0, 50, 0, 0) +} + +static VOID _ccid_abort_test(VOID) +{ +UINT status; + /* PC_to_RDR_Abort, RDR_to_PC_SlotStatus. */ + _ux_utility_memory_set(host_bulk_out, 0, 10); + + /* Abort. */ + host_bulk_out[0] = 0x72; + host_bulk_out[5] = 0; /* bSlot. */ + host_bulk_out[6] = 20; /* bSeq. */ + _ux_utility_long_put(host_bulk_out+1, 0); + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_abort, 10) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x81, 0, 0, 20, 0, 0) +} + +static VOID _ccid_data_rate_and_clock_test(VOID) +{ +UINT status; + /* PC_to_RDR_SetDatarateAndClockFrequency, RDR_to_PC_DataRateAndClockFrequency. */ + _ux_utility_memory_set(host_bulk_out, 0, 10); + + /* GetParameters. */ + host_bulk_out[0] = 0x73; + host_bulk_out[5] = 0; /* bSlot. */ + host_bulk_out[6] = 40; /* bSeq. */ + _ux_utility_long_put(host_bulk_out+1, 8); + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 18, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_set_data_rate_and_clock_frequency, 18) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x84, 8, 0, 40, 0, 0) +} + +static VOID _ccid_control_requests_test(VOID) +{ +UX_ENDPOINT *endpoint = _ux_host_class_dummy_get_endpoint(host_ccid, 0, 0); +UX_TRANSFER *transfer = &endpoint->ux_endpoint_transfer_request; +UX_INTERFACE *interface = host_ccid->ux_host_class_dummy_interface; +ULONG buffer[8]; +UINT status; + /* Issue GET_CLOCK_FREQUENCIES request. */ + transfer->ux_transfer_request_type = 0xA1; + transfer->ux_transfer_request_function = 0x02; + transfer->ux_transfer_request_index = interface->ux_interface_descriptor.bInterfaceNumber; + transfer->ux_transfer_request_value = 0; + transfer->ux_transfer_request_requested_length = sizeof(buffer); + transfer->ux_transfer_request_data_pointer = (UCHAR*)buffer; + status = ux_host_stack_transfer_request(transfer); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(transfer->ux_transfer_request_actual_length == 4); + UX_TEST_ASSERT(buffer[0] == device_ccid_clocks[0]); + + /* Issue GET_DATA_RATES request. */ + transfer->ux_transfer_request_type = 0xA1; + transfer->ux_transfer_request_function = 0x03; + transfer->ux_transfer_request_index = interface->ux_interface_descriptor.bInterfaceNumber; + transfer->ux_transfer_request_value = 0; + transfer->ux_transfer_request_requested_length = sizeof(buffer); + transfer->ux_transfer_request_data_pointer = (UCHAR*)buffer; + status = ux_host_stack_transfer_request(transfer); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(transfer->ux_transfer_request_actual_length == 4); + UX_TEST_ASSERT(buffer[0] == device_ccid_data_rates[0]); +} + + + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +ULONG mem_free; +ULONG loop; +ULONG parameter_u32[64/4]; +USHORT *parameter_u16 = (USHORT*)parameter_u32; +UCHAR *parameter_u8 = (UCHAR*)parameter_u32; + + + stepinfo("\n"); + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + status = ux_test_sleep_break_on_success(100, _test_check_host_connection_success); + UX_TEST_ASSERT(status == UX_SUCCESS); + + _ccid_enumeration_test(); + + _ccid_icc_insert_test(); + _ccid_icc_power_on_off_test(); + _ccid_get_slot_status_test(); + _ccid_xfr_block_test(); + _ccid_parameters_test(); + _ccid_escape_test(); + _ccid_icc_clock_test(); + _ccid_t0_apdu_test(); + _ccid_secure_test(); + _ccid_mechanical_test(); + _ccid_abort_test(); + _ccid_data_rate_and_clock_test(); + + _ccid_control_requests_test(); + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + status = ux_test_sleep_break_on_success(100, _test_check_host_disconnection_success); + UX_TEST_ASSERT(status == UX_SUCCESS); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_device_class_ccid_name, _ux_device_class_ccid_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); + tx_thread_relinquish(); +#else + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); +#endif + } +} + + +static UINT ux_test_ccid_icc_power_on(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ +UX_DEVICE_CLASS_CCID_PC_TO_RDR_ICC_POWER_ON_HEADER *icc_power_on; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_DATA_BLOCK_HEADER *data_block; + ux_test_callback_log(ux_test_ccid_icc_power_on, io_msg->ux_device_class_ccid_messages_pc_to_rdr); + /* Access to command. */ + icc_power_on = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_ICC_POWER_ON_HEADER*)io_msg->ux_device_class_ccid_messages_pc_to_rdr; + /* Access to data. */ + data_block = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_DATA_BLOCK_HEADER*)io_msg->ux_device_class_ccid_messages_rdr_to_pc; + /* bPowerSelect. */ + icc_power_on->bPowerSelect; + /* Update bStatus,bError. */ + data_block->bStatus = UX_DEVICE_CLASS_CCID_ICC_ACTIVE; + // data_block->bError = 0; + /* Update data length (reply message header only). */ + io_msg->ux_device_class_ccid_messages_rdr_to_pc_length = 10; +#if defined(UX_DEVICE_STANDALONE) + return(UX_STATE_NEXT); +#else + return(UX_SUCCESS); +#endif +} +static UINT ux_test_ccid_icc_power_off(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ +UX_DEVICE_CLASS_CCID_PC_TO_RDR_ICC_POWER_OFF_HEADER *cmd; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS_HEADER *rsp; + ux_test_callback_log(ux_test_ccid_icc_power_off, io_msg->ux_device_class_ccid_messages_pc_to_rdr); + /* Access to command. */ + cmd = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_ICC_POWER_OFF_HEADER*)io_msg->ux_device_class_ccid_messages_pc_to_rdr; + /* Access to data. */ + rsp = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS_HEADER*)io_msg->ux_device_class_ccid_messages_rdr_to_pc; + /* Update bStatus,bError. */ + rsp->bStatus = UX_DEVICE_CLASS_CCID_ICC_INACTIVE; + // rsp->bError = 0; +#if defined(UX_DEVICE_STANDALONE) + return(UX_STATE_NEXT); +#else + return(UX_SUCCESS); +#endif +} +static UINT ux_test_ccid_get_slot_status(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ +UX_DEVICE_CLASS_CCID_PC_TO_RDR_GET_SLOT_STATUS_HEADER *cmd; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS_HEADER *rsp; + ux_test_callback_log(ux_test_ccid_get_slot_status, io_msg->ux_device_class_ccid_messages_pc_to_rdr); + /* Access to command. */ + cmd = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_GET_SLOT_STATUS_HEADER*)io_msg->ux_device_class_ccid_messages_pc_to_rdr; + /* Access to data. */ + rsp = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS_HEADER*)io_msg->ux_device_class_ccid_messages_rdr_to_pc; + /* Update bStatus,bError. */ + // rsp->bStatus = 0; + // rsp->bError = 0; + // rsp->bClockStatus = 0; +#if defined(UX_DEVICE_STANDALONE) + return(UX_STATE_NEXT); +#else + return(UX_SUCCESS); +#endif +} +#if defined(UX_DEVICE_STANDALONE) +static UINT _xfr_block_state = 0; +#endif +static UINT ux_test_ccid_xfr_block(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ +UX_DEVICE_CLASS_CCID_PC_TO_RDR_XFR_BLOCK_HEADER *cmd; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_DATA_BLOCK_HEADER *rsp; +UCHAR *cmd_data; +UCHAR *rsp_data; +UCHAR i; + ux_test_callback_log(ux_test_ccid_xfr_block, io_msg->ux_device_class_ccid_messages_pc_to_rdr); + /* Access to command. */ + cmd = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_XFR_BLOCK_HEADER*)io_msg->ux_device_class_ccid_messages_pc_to_rdr; + /* Access to data. */ + rsp = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_DATA_BLOCK_HEADER*)io_msg->ux_device_class_ccid_messages_rdr_to_pc; + /* Access to data buffers. */ + cmd_data = (UCHAR*)io_msg->ux_device_class_ccid_messages_pc_to_rdr + UX_DEVICE_CLASS_CCID_MESSAGE_HEADER_LENGTH; + rsp_data = (UCHAR*)io_msg->ux_device_class_ccid_messages_rdr_to_pc + UX_DEVICE_CLASS_CCID_MESSAGE_HEADER_LENGTH; + +#if defined(UX_DEVICE_STANDALONE) + + switch(_xfr_block_state) + { + case 0: + /* Time extension. */ + ux_device_class_ccid_time_extension(device_ccid, slot, 10); + _xfr_block_state = 1; + return(UX_STATE_WAIT); + case 1: + _xfr_block_state = 2; + return(UX_STATE_WAIT); + default: + _xfr_block_state = 0; + } +#else + + /* Time extension. */ + ux_device_class_ccid_time_extension(device_ccid, slot, 10); +#endif + + /* Update bStatus,bError. */ + // rsp->bStatus = 0; + // rsp->bError = 0; + + /* Update data. */ + for (i = 10; i < 64; i ++) + rsp_data[i] = i; + + /* Update data length. */ + UX_DEVICE_CLASS_CCID_MESSAGE_LENGTH_SET(rsp, 64-10); + io_msg->ux_device_class_ccid_messages_rdr_to_pc_length = 64; + +#if defined(UX_DEVICE_STANDALONE) + return(UX_STATE_NEXT); +#else + return(UX_SUCCESS); +#endif +} +static UINT ux_test_ccid_get_parameters(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ +UX_DEVICE_CLASS_CCID_PC_TO_RDR_GET_PARAMETERS_HEADER *cmd; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_HEADER *rsp; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_T0 *t0; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_T1 *t1; + ux_test_callback_log(ux_test_ccid_get_parameters, io_msg->ux_device_class_ccid_messages_pc_to_rdr); + /* Access to command. */ + cmd = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_GET_PARAMETERS_HEADER*)io_msg->ux_device_class_ccid_messages_pc_to_rdr; + /* Access to data. */ + rsp = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_HEADER*)io_msg->ux_device_class_ccid_messages_rdr_to_pc; + /* Parameters protocol. */ + rsp->bProtocolNum = 0; + if (rsp->bProtocolNum == 0) + { + t0 = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_T0 *)rsp; + t0->bmFindexDindex = 0; + /* ... */ + } + else if (rsp->bProtocolNum == 1) + { + t1 = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_T1 *)rsp; + t1->bmFindexDindex = 0; + /* ... */ + } + /* Update bStatus,bError. */ + // rsp->bStatus = 0; + // rsp->bError = 0; + /* Update data length. */ + UX_DEVICE_CLASS_CCID_MESSAGE_LENGTH_SET(rsp, 5); + io_msg->ux_device_class_ccid_messages_rdr_to_pc_length = 5+10; +#if defined(UX_DEVICE_STANDALONE) + return(UX_STATE_NEXT); +#else + return(UX_SUCCESS); +#endif +} +static UINT ux_test_ccid_reset_parameters(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ +UX_DEVICE_CLASS_CCID_PC_TO_RDR_RESET_PARAMETERS_HEADER *cmd; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_HEADER *rsp; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_T0 *t0; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_T1 *t1; + ux_test_callback_log(ux_test_ccid_reset_parameters, io_msg->ux_device_class_ccid_messages_pc_to_rdr); + /* Access to command. */ + cmd = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_RESET_PARAMETERS_HEADER*)io_msg->ux_device_class_ccid_messages_pc_to_rdr; + /* Access to response. */ + rsp = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_HEADER*)io_msg->ux_device_class_ccid_messages_rdr_to_pc; + /* Parameters protocol. */ + rsp->bProtocolNum = 0; + if (rsp->bProtocolNum == 0) + { + t0 = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_T0 *)rsp; + t0->bmFindexDindex = 0; + /* ... */ + } + else if (rsp->bProtocolNum == 1) + { + t1 = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_T1 *)rsp; + t1->bmFindexDindex = 0; + /* ... */ + } + /* Update bStatus,bError. */ + // rsp->bStatus = 0; + // rsp->bError = 0; + /* Update data length. */ + UX_DEVICE_CLASS_CCID_MESSAGE_LENGTH_SET(rsp, 5); + io_msg->ux_device_class_ccid_messages_rdr_to_pc_length = 5+10; +#if defined(UX_DEVICE_STANDALONE) + return(UX_STATE_NEXT); +#else + return(UX_SUCCESS); +#endif +} +static UINT ux_test_ccid_set_parameters(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ +UX_DEVICE_CLASS_CCID_PC_TO_RDR_SET_PARAMETERS_HEADER *cmd; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_HEADER *rsp; +UX_DEVICE_CLASS_CCID_PC_TO_RDR_SET_PARAMETERS_T0 *cmd_t0; +UX_DEVICE_CLASS_CCID_PC_TO_RDR_SET_PARAMETERS_T1 *cmd_t1; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_T0 *rsp_t0; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_T1 *rsp_t1; + ux_test_callback_log(ux_test_ccid_set_parameters, io_msg->ux_device_class_ccid_messages_pc_to_rdr); + /* Access to command. */ + cmd = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_SET_PARAMETERS_HEADER*)io_msg->ux_device_class_ccid_messages_pc_to_rdr; + /* Access to response. */ + rsp = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_HEADER*)io_msg->ux_device_class_ccid_messages_rdr_to_pc; + if (rsp->bProtocolNum == 0) + { + cmd_t0 = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_SET_PARAMETERS_T0 *)cmd; + rsp_t0 = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_T0 *)rsp; + /* ... */ + } + else + { + cmd_t1 = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_SET_PARAMETERS_T1 *)cmd; + rsp_t1 = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_T1 *)rsp; + } + /* Update bStatus,bError. */ + // rsp->bStatus = 0; + // rsp->bError = 0; + /* Update data length. */ + UX_DEVICE_CLASS_CCID_MESSAGE_LENGTH_SET(rsp, 5); + io_msg->ux_device_class_ccid_messages_rdr_to_pc_length = 5+10; +#if defined(UX_DEVICE_STANDALONE) + return(UX_STATE_NEXT); +#else + return(UX_SUCCESS); +#endif +} +static UINT ux_test_ccid_escape(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ +UX_DEVICE_CLASS_CCID_PC_TO_RDR_ESCAPE_HEADER *cmd; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_ESCAPE_HEADER *rsp; +UCHAR *cmd_data; +UCHAR *rsp_data; + ux_test_callback_log(ux_test_ccid_escape, io_msg->ux_device_class_ccid_messages_pc_to_rdr); + /* Access to command. */ + cmd = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_ESCAPE_HEADER*)io_msg->ux_device_class_ccid_messages_pc_to_rdr; + /* Access to data. */ + rsp = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_ESCAPE_HEADER*)io_msg->ux_device_class_ccid_messages_rdr_to_pc; + cmd_data = io_msg->ux_device_class_ccid_messages_pc_to_rdr + UX_DEVICE_CLASS_CCID_MESSAGE_HEADER_LENGTH; + rsp_data = io_msg->ux_device_class_ccid_messages_rdr_to_pc + UX_DEVICE_CLASS_CCID_MESSAGE_HEADER_LENGTH; + /* Update bStatus,bError. */ + // rsp->bStatus = 0; + // rsp->bError = 0; + /* Update data length. */ + UX_DEVICE_CLASS_CCID_MESSAGE_LENGTH_SET(rsp, 128); + io_msg->ux_device_class_ccid_messages_rdr_to_pc_length = 128+10; +#if defined(UX_DEVICE_STANDALONE) + return(UX_STATE_NEXT); +#else + return(UX_SUCCESS); +#endif +} +static UINT ux_test_ccid_icc_clock(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ +UX_DEVICE_CLASS_CCID_PC_TO_RDR_ICC_CLOCK_HEADER *cmd; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS_HEADER *rsp; + ux_test_callback_log(ux_test_ccid_icc_clock, io_msg->ux_device_class_ccid_messages_pc_to_rdr); + /* Access to command. */ + cmd = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_ICC_CLOCK_HEADER*)io_msg->ux_device_class_ccid_messages_pc_to_rdr; + /* Access to data. */ + rsp = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS_HEADER*)io_msg->ux_device_class_ccid_messages_rdr_to_pc; + /* Clock command. */ + cmd->bClockCommand; + /* Update bStatus,bError. */ + // rsp->bStatus = 0; + // rsp->bError = 0; +#if defined(UX_DEVICE_STANDALONE) + return(UX_STATE_NEXT); +#else + return(UX_SUCCESS); +#endif +} +static UINT ux_test_ccid_t0_apdu(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ +UX_DEVICE_CLASS_CCID_PC_TO_RDR_T0_APDU_HEADER *cmd; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS_HEADER *rsp; + ux_test_callback_log(ux_test_ccid_t0_apdu, io_msg->ux_device_class_ccid_messages_pc_to_rdr); + /* Access to command. */ + cmd = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_T0_APDU_HEADER*)io_msg->ux_device_class_ccid_messages_pc_to_rdr; + /* Access to data. */ + rsp = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS_HEADER*)io_msg->ux_device_class_ccid_messages_rdr_to_pc; + /* Changes. */ + if (cmd->bmChanges & UX_DEVICE_CLASS_CCID_CHANGE_CLASS_ENVELOPE) + { + cmd->bClassEnvelope; + } + if (cmd->bmChanges & UX_DEVICE_CLASS_CCID_CHANGE_CLASS_GET_RESPONSE) + { + cmd->bClassGetResponse; + } + /* Update bStatus,bError. */ + rsp->bStatus = 0; + rsp->bError = 0; + +#if defined(UX_DEVICE_STANDALONE) + return(UX_STATE_NEXT); +#else + return(UX_SUCCESS); +#endif +} +static UINT ux_test_ccid_secure(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ +UX_DEVICE_CLASS_CCID_PC_TO_RDR_SECURE_HEADER *cmd; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_DATA_BLOCK_HEADER *rsp; +UCHAR *cmd_data; +UCHAR *rsp_data; + ux_test_callback_log(ux_test_ccid_secure, io_msg->ux_device_class_ccid_messages_pc_to_rdr); + /* Access to command. */ + cmd = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_SECURE_HEADER*)io_msg->ux_device_class_ccid_messages_pc_to_rdr; + /* Access to data. */ + rsp = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_DATA_BLOCK_HEADER*)io_msg->ux_device_class_ccid_messages_rdr_to_pc; + + cmd->wLevelParameter; + rsp->bChainParameter; + + cmd_data = io_msg->ux_device_class_ccid_messages_pc_to_rdr + UX_DEVICE_CLASS_CCID_MESSAGE_HEADER_LENGTH; + rsp_data = io_msg->ux_device_class_ccid_messages_rdr_to_pc + UX_DEVICE_CLASS_CCID_MESSAGE_HEADER_LENGTH; + + /* Update bStatus,bError. */ + // rsp->bStatus = 0; + // rsp->bError = 0; + /* Update data length. */ + UX_DEVICE_CLASS_CCID_MESSAGE_LENGTH_SET(rsp, 128/8); + io_msg->ux_device_class_ccid_messages_rdr_to_pc_length = 128/8+10; +#if defined(UX_DEVICE_STANDALONE) + return(UX_STATE_NEXT); +#else + return(UX_SUCCESS); +#endif +} +static UINT ux_test_ccid_mechanical(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ +UX_DEVICE_CLASS_CCID_PC_TO_RDR_MECHANICAL_HEADER *cmd; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS_HEADER *rsp; + ux_test_callback_log(ux_test_ccid_mechanical, io_msg->ux_device_class_ccid_messages_pc_to_rdr); + /* Access to command. */ + cmd = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_MECHANICAL_HEADER*)io_msg->ux_device_class_ccid_messages_pc_to_rdr; + /* Access to data. */ + rsp = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS_HEADER*)io_msg->ux_device_class_ccid_messages_rdr_to_pc; + /* Update bStatus,bError. */ + // rsp->bStatus = 0; + // rsp->bError = 0; +#if defined(UX_DEVICE_STANDALONE) + return(UX_STATE_NEXT); +#else + return(UX_SUCCESS); +#endif +} +static UINT ux_test_ccid_abort(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ +UX_DEVICE_CLASS_CCID_PC_TO_RDR_ABORT_HEADER *cmd; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS_HEADER *rsp; + /* Control request Abort. */ + if (io_msg == UX_NULL) + { + ux_test_callback_log(ux_test_ccid_abort, UX_NULL); + return(UX_SUCCESS); + } + /* Bulk OUT Abort. */ + ux_test_callback_log(ux_test_ccid_abort, io_msg->ux_device_class_ccid_messages_pc_to_rdr); + /* Access to command. */ + cmd = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_ABORT_HEADER*)io_msg->ux_device_class_ccid_messages_pc_to_rdr; + /* Access to data. */ + rsp = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS_HEADER*)io_msg->ux_device_class_ccid_messages_rdr_to_pc; + /* Update bStatus,bError. */ + // rsp->bStatus = 0; + // rsp->bError = 0; +#if defined(UX_DEVICE_STANDALONE) + return(UX_STATE_NEXT); +#else + return(UX_SUCCESS); +#endif +} +static UINT ux_test_ccid_set_data_rate_and_clock_frequency(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ +UX_DEVICE_CLASS_CCID_PC_TO_RDR_SET_DATA_RATE_AND_CLOCK_FREQUENCY *cmd; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_DATA_RATE_AND_CLOCK_FREQUENCY *rsp; +ULONG data_rate; +ULONG clock; + ux_test_callback_log(ux_test_ccid_set_data_rate_and_clock_frequency, io_msg->ux_device_class_ccid_messages_pc_to_rdr); + /* Access to command. */ + cmd = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_SET_DATA_RATE_AND_CLOCK_FREQUENCY*)io_msg->ux_device_class_ccid_messages_pc_to_rdr; + /* Access to data. */ + rsp = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_DATA_RATE_AND_CLOCK_FREQUENCY*)io_msg->ux_device_class_ccid_messages_rdr_to_pc; + data_rate = UX_DEVICE_CLASS_CCID_PC_TO_RDR_CLOCK_FREQUENCY_GET(cmd); + clock = UX_DEVICE_CLASS_CCID_PC_TO_RDR_DATA_RATE_GET(cmd); + /* Update bStatus,bError. */ + // rsp->bStatus = 0; + // rsp->bError = 0; + /* Update response data rate and clock. */ + UX_DEVICE_CLASS_CCID_RDR_TO_PC_CLOCK_FREQUENCY_SET(rsp, clock); + UX_DEVICE_CLASS_CCID_RDR_TO_PC_DATA_RATE_SET(rsp, data_rate); +#if defined(UX_DEVICE_STANDALONE) + return(UX_STATE_NEXT); +#else + return(UX_SUCCESS); +#endif +} diff --git a/test/regression/usbx_device_class_ccid_busy_abort_tests.c b/test/regression/usbx_device_class_ccid_busy_abort_tests.c new file mode 100644 index 00000000..27a4583b --- /dev/null +++ b/test/regression/usbx_device_class_ccid_busy_abort_tests.c @@ -0,0 +1,1492 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_device_class_ccid.h" +#include "ux_device_stack.h" + +#include "ux_host_class_dummy.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +#define UX_DEMO_MAX_SLOT_INDEX (2) +#define UX_DEMO_MAX_BUSY_SLOTS (2) +#if UX_SLAVE_REQUEST_DATA_MAX_LENGTH >= 1024 +#define UX_DEMO_MAX_MESSAGE_LENGTH (1024) +#else +#define UX_DEMO_MAX_MESSAGE_LENGTH (UX_SLAVE_REQUEST_DATA_MAX_LENGTH) +#endif +#define UX_DEMO_N_CLOCKS (1) +#define UX_DEMO_N_DATA_RATES (1) +#define UX_DEMO_BULK_OUT_EP 0x02 +#define UX_DEMO_BULK_IN_EP 0x81 +#define UX_DEMO_INTERRUPT_IN_EP 0x83 +#define UX_DEMO_INTERRUPT_IN_SIZE (8) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); + +static VOID ux_test_hcd_entry_should_not_be_called(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_disconnect(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +static UINT ux_test_ccid_icc_power_on(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_icc_power_off(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_get_slot_status(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_xfr_block(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_get_parameters(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_reset_parameters(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_set_parameters(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_escape(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_icc_clock(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_t0_apdu(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_secure(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_mechanical(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_abort(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_set_data_rate_and_clock_frequency(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +static UX_DEVICE *host_device = UX_NULL; +static UCHAR host_bulk_out[UX_DEMO_MAX_MESSAGE_LENGTH]; +static UCHAR host_bulk_out_busy[UX_DEMO_MAX_MESSAGE_LENGTH]; +static UCHAR host_bulk_in[UX_DEMO_MAX_MESSAGE_LENGTH]; +static ULONG host_bulk_in_length; +static UCHAR host_interrupt_in[UX_DEMO_INTERRUPT_IN_SIZE]; +static ULONG host_interrupt_in_length; + +static UX_HOST_CLASS_DUMMY *host_ccid = UX_NULL; + +static struct _SLOT_TESTER { + TX_SEMAPHORE semaphore; + UINT state; + ULONG timeout; + ULONG flags; +} slot_tester[UX_DEMO_MAX_SLOT_INDEX + 1]; +#define SLOT_TESTER_FLAG_ABORT (1u) +#define SLOT_TESTER_STATE_IDLE (0u) +#define SLOT_TESTER_STATE_START (1u) +#define SLOT_TESTER_STATE_WAIT (2u) +#define SLOT_TESTER_STATE_NEXT (3u) + +static ULONG enum_counter; + +static ULONG error_counter; +static ULONG error_callback_counter; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_on_set_cfg; +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_enum_mem_alloc_count; + +static ULONG rsc_test_sem_usage; +static ULONG rsc_test_sem_get_count; +static ULONG rsc_test_mutex_usage; +static ULONG rsc_test_mem_alloc_count; + +static UX_DEVICE_CLASS_CCID_HANDLES device_ccid_handles = +{ + ux_test_ccid_icc_power_on, + ux_test_ccid_icc_power_off, + ux_test_ccid_get_slot_status, + ux_test_ccid_xfr_block, + ux_test_ccid_get_parameters, + ux_test_ccid_reset_parameters, + ux_test_ccid_set_parameters, + ux_test_ccid_escape, + ux_test_ccid_icc_clock, + ux_test_ccid_t0_apdu, + ux_test_ccid_secure, + ux_test_ccid_mechanical, + ux_test_ccid_abort, + ux_test_ccid_set_data_rate_and_clock_frequency, +}; +static ULONG device_ccid_clocks[] = +{ + 14320, +}; +static ULONG device_ccid_data_rates[] = +{ + 115200, +}; +static UX_DEVICE_CLASS_CCID *device_ccid = UX_NULL; +static UX_DEVICE_CLASS_CCID_PARAMETER device_ccid_parameter; +static UCHAR device_ccid_soft_reset_count = 0; + +static struct _TEST_CCID_CALLBACK_LOG { + UX_DEVICE_CLASS_CCID_HANDLE handle; + ULONG buf_length; + UCHAR buf[UX_DEMO_MAX_MESSAGE_LENGTH + 4]; +} device_ccid_callback_log; +static inline void ux_test_callback_log(UX_DEVICE_CLASS_CCID_HANDLE handle, UCHAR *ccid_msg) +{ +ULONG buf_length; + device_ccid_callback_log.handle = handle; + if (ccid_msg == UX_NULL) + { + device_ccid_callback_log.buf[0] = 0; + device_ccid_callback_log.buf_length = 0; + return; + } + buf_length = UX_DEVICE_CLASS_CCID_MESSAGE_LENGTH_GET(ccid_msg) + UX_DEVICE_CLASS_CCID_MESSAGE_HEADER_LENGTH; + UX_TEST_ASSERT(buf_length <= UX_DEMO_MAX_MESSAGE_LENGTH); + _ux_utility_memory_copy(device_ccid_callback_log.buf, ccid_msg, buf_length); + device_ccid_callback_log.buf_length = buf_length; +} + +/* Define device framework. */ + +#define _W(w) UX_W0(w),UX_W1(w) +#define _DW(dw) UX_DW0(dw),UX_DW1(dw),UX_DW2(dw),UX_DW3(dw) + +#define _CONFIGURATION_DESCRIPTOR(total_len, n_ifc, cfg_val) \ + 0x09, 0x02, UX_W0(total_len), UX_W1(total_len), (n_ifc), (cfg_val), \ + 0x00, 0xc0, 0x32, + +#define _INTERFACE_DESCRIPTOR(ifc_n, alt, n_ep, cls, sub, protocol) \ + 0x09, 0x04, (ifc_n), (alt), (n_ep), (cls), (sub), (protocol), 0x00, + +#define _SMART_CARD_DESCRIPTORS \ + 0x36, /* bLength. */ \ + 0x21, /* bDescriptorType. */ \ + 0x10, 0x01, /* bcdCCID. */ \ + UX_DEMO_MAX_SLOT_INDEX, /* bMaxSlotIndex. */ \ + 0x01, /* bVoltageSupport (1-5V,2-3.0V,4-1.8V). */ \ + 0x00, 0x00, 0x00, 0x00, /* dwProtocols PPPP, RRRR. */ \ + _DW(14320), /* dwDefaultClock (KHz). */ \ + _DW(14320), /* dwMaximumClock (KHz). */ \ + UX_DEMO_N_CLOCKS, /* bNumClockSupported. */ \ + _DW(115200), /* dwDataRate (bps). */ \ + _DW(115200), /* dwMaxDataRate (bps). */ \ + UX_DEMO_N_DATA_RATES, /* bNumDataRatesSupported. */ \ + 0x00, 0x00, 0x00, 0x00, /* dwMaxIFSD. */ \ + 0x00, 0x00, 0x00, 0x00, /* dwSynchProtocols PPPP, RRRR. */ \ + 0x00, 0x00, 0x00, 0x00, /* dwMechanical (1-accept,2-eject,4-capture,8-lock/unlock). */\ + 0x00, 0x00, 0x00, 0x00, /* dwFeatures. */ \ + _DW(1024), /* dwMaxCCIDMessageLength. */ \ + 0, /* bClassGetResponse. */ \ + 0, /* bClassEnvelope. */ \ + _W(0x0000), /* wLcdLayout, XXYY. */ \ + 0x3, /* bPINSupport, 1-Verification, 2-Modification. */ \ + UX_DEMO_MAX_BUSY_SLOTS, /* bMaxCCIDBusySlots. */ + + +#define _ENDPOINT_DESCRIPTOR(addr, attr, pktsize, interval) \ + 0x07, 0x05, (addr), (attr), UX_W0(pktsize), UX_W1(pktsize), (interval), + +#define _CFG_TOTAL_LEN (9+9+0x36+7+7+7) + +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0xEF bDeviceClass: Composite class code + 0x02 bDeviceSubclass: class sub code + 0x00 bDeviceProtocol: Device protocol + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0x00, 0x00, 0x00, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 0x03, + 0x01, + + _CONFIGURATION_DESCRIPTOR(_CFG_TOTAL_LEN, 1, 1) + _INTERFACE_DESCRIPTOR(0, 0, 3, 0x0B, 0x00, 0x00) + _SMART_CARD_DESCRIPTORS + _ENDPOINT_DESCRIPTOR(UX_DEMO_BULK_OUT_EP, 0x02, 64, 0x00) + _ENDPOINT_DESCRIPTOR(UX_DEMO_BULK_IN_EP, 0x02, 64, 0x00) + _ENDPOINT_DESCRIPTOR(UX_DEMO_INTERRUPT_IN_EP, 0x03, UX_DEMO_INTERRUPT_IN_SIZE, 0x04) +}; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_full_speed) +#define device_framework_high_speed device_framework_full_speed + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "AzureRTOS" */ + 0x09, 0x04, 0x01, 9, + 'A','z','u','r','e','R','T','O','S', + + /* Product string descriptor : Index 2 - "ccid device" */ + 0x09, 0x04, 0x02, 11, + 'C','C','I','D',' ','d','e','v','i','c','e', + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +/* Test interactions */ + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT test_slave_change_function(ULONG change) +{ + return 0; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + // printf("hCbChange: %lx %p %p\n", event, (VOID*)cls, inst); + switch(event) + { + + case UX_DEVICE_INSERTION: + host_ccid = inst; + break; + + case UX_DEVICE_REMOVAL: + if (host_ccid == inst) + host_ccid = UX_NULL; + break; + + case UX_DEVICE_CONNECTION: + host_device = (UX_DEVICE *)inst; + break; + + case UX_DEVICE_DISCONNECTION: + if ((VOID *)host_device == inst) + host_device = UX_NULL; + break; + +#if defined(UX_HOST_STANDALONE) + case UX_STANDALONE_WAIT_BACKGROUND_TASK: + tx_thread_relinquish(); + break; +#endif + + default: + break; + } + return 0; +} + +static VOID test_ccid_instance_activate(VOID *dummy_instance) +{ + if (device_ccid == UX_NULL) + device_ccid = (UX_DEVICE_CLASS_CCID *)dummy_instance; +} +static VOID test_ccid_instance_deactivate(VOID *dummy_instance) +{ + if ((VOID*)device_ccid == dummy_instance) + device_ccid = UX_NULL; +} +static VOID test_ccid_soft_reset(VOID *dummy_instance) +{ + device_ccid_soft_reset_count ++; +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + error_callback_counter ++; +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_enum_sem_get_count = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_host_class_ccid_busy_abort_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + printf("Running CCID Busy and Abort Test.................................... "); +#if !UX_TEST_MULTI_EP_OVER(2) + printf("Skip\n"); + test_control_return(0); + return; +#endif + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* Initialize the free memory pointer */ + stack_pointer = (CHAR *) usbx_memory; + memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 4); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + if (status != UX_SUCCESS) + { + + printf(" ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register Host DUMMY class. */ + status = ux_host_stack_class_register(_ux_host_class_dummy_name, _ux_host_class_dummy_entry); + if (status != UX_SUCCESS) + { + + printf(" ERROR #3\n"); + 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, + test_slave_change_function); + if(status!=UX_SUCCESS) + { + + printf(" ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a ccid device. */ + _ux_utility_memory_set(&device_ccid_parameter, 0, sizeof(device_ccid_parameter)); + device_ccid_parameter.ux_device_class_ccid_handles = &device_ccid_handles; + device_ccid_parameter.ux_device_class_ccid_instance_activate = test_ccid_instance_activate; + device_ccid_parameter.ux_device_class_ccid_instance_deactivate = test_ccid_instance_deactivate; + device_ccid_parameter.ux_device_class_ccid_max_n_slots = UX_DEMO_MAX_SLOT_INDEX + 1; + device_ccid_parameter.ux_device_class_ccid_max_n_busy_slots = UX_DEMO_MAX_BUSY_SLOTS; + device_ccid_parameter.ux_device_class_ccid_max_transfer_length = UX_DEMO_MAX_MESSAGE_LENGTH; + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_device_class_ccid_name, + ux_device_class_ccid_entry, + 1, 0, &device_ccid_parameter); + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_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(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #9\n"); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + stack_pointer += UX_DEMO_STACK_SIZE; + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #10\n"); + test_control_return(1); + } + + for (int i = 0; i <= UX_DEMO_MAX_SLOT_INDEX; i ++) + { + slot_tester[i].timeout = TX_WAIT_FOREVER; + status = tx_semaphore_create(&slot_tester[i].semaphore, "slot_test_semaphore", 0); + UX_TEST_ASSERT(status == TX_SUCCESS); + } +} + +static UINT _test_check_host_connection_error(VOID) +{ + if (device_ccid && host_ccid) + return(UX_SUCCESS); + if (error_callback_counter >= 3) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_connection_success(VOID) +{ + if (device_ccid && host_ccid) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_disconnection_success(VOID) +{ + if (device_ccid == UX_NULL && host_ccid == UX_NULL) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _ccid_message_bulk_out_in(UCHAR *out, ULONG out_length, UCHAR *in, ULONG *in_length) +{ +ULONG payload_size; +ULONG total_length, actual_length; +UINT status = UX_FUNCTION_NOT_SUPPORTED; + if (out) + { + total_length = out_length; + status = _ux_host_class_dummy_transfer(host_ccid, UX_DEMO_BULK_OUT_EP, 0, out, total_length, &actual_length); + if (status != UX_SUCCESS) + { + printf("BulkOUT fail: 0x%x\n", status); + return(status); + } + } + if (in) + { + payload_size = _ux_host_class_dummy_get_max_payload_size(host_ccid, UX_DEMO_BULK_IN_EP, 0); + while(1) + { + status = _ux_host_class_dummy_transfer(host_ccid, UX_DEMO_BULK_IN_EP, 0, in, payload_size, &actual_length); + *in_length = actual_length; + if (status != UX_SUCCESS) + { + printf("BulkIN fail: 0x%x\n", status); + return(status); + } + /* Check time extension. */ + if (((in[7] >> 6) & 0x3u) == 0x2) + { + /* Try to read another packet. */ + // printf("TimeExtension\n"); + continue; + } + /* Check short packet. */ + if (actual_length < payload_size) + return(status); + else + break; + } + /* Read remaining message. */ + total_length = UX_DEVICE_CLASS_CCID_MESSAGE_LENGTH_GET(in); + total_length += UX_DEVICE_CLASS_CCID_MESSAGE_HEADER_LENGTH; + //printf("FirstPacket, total %ld\n", total_length); + in += payload_size; + total_length -= payload_size; + if (total_length) + { + status = _ux_host_class_dummy_transfer(host_ccid, UX_DEMO_BULK_IN_EP, 0, in, total_length, &actual_length); + *in_length += actual_length; + } + } + else + { + /* Let other threads run. */ + tx_thread_sleep(1); + } + return(status); +} + +static UINT _ccid_message_interrupt_in(UCHAR *in, ULONG *in_length) +{ +ULONG payload_size = _ux_host_class_dummy_get_max_payload_size(host_ccid, UX_DEMO_INTERRUPT_IN_EP, 0); +UINT status; + status = _ux_host_class_dummy_transfer(host_ccid, UX_DEMO_INTERRUPT_IN_EP, 0, in, payload_size, in_length); + return(status); +} + +static UINT _ccid_abort(UCHAR bSlot, UCHAR bSeq) +{ +UX_ENDPOINT *endpoint = _ux_host_class_dummy_get_endpoint(host_ccid, 0, 0); +UX_TRANSFER *transfer = &endpoint->ux_endpoint_transfer_request; +UX_INTERFACE *interface = host_ccid->ux_host_class_dummy_interface; +UINT status; +ULONG length; +UCHAR cmd[10], rsp[10]; + /* Issue Abort request. */ + transfer->ux_transfer_request_type = 0x21; + transfer->ux_transfer_request_function = 0x01; + transfer->ux_transfer_request_index = interface->ux_interface_descriptor.bInterfaceNumber; + transfer->ux_transfer_request_value = bSlot | (bSeq << 8); + transfer->ux_transfer_request_requested_length = 0; + status = ux_host_stack_transfer_request(transfer); + if (status != UX_SUCCESS) + { + return(status); + } + /* Issue Abort Message. */ + _ux_utility_memory_set(cmd, 0, 10); + cmd[0] = 0x72; + cmd[5] = bSlot; + cmd[6] = bSeq; + status = _ccid_message_bulk_out_in(cmd, 10, rsp, &length); + return(status); +} + +#define _TEST_CCID_BULK_OUT_CHECK(h, l, b) \ + UX_TEST_ASSERT(status == UX_SUCCESS); \ + UX_TEST_ASSERT(device_ccid_callback_log.handle == (h)); \ + if ((h) != UX_NULL) { \ + UX_TEST_ASSERT(device_ccid_callback_log.buf_length == (l)); \ + if (b) { \ + UX_TEST_ASSERT(_ux_utility_memory_compare(device_ccid_callback_log.buf, (b), (l)) == UX_SUCCESS); \ + } \ + } + +#define _TEST_CCID_BULK_IN_HEADER_CHECK(type,len,slot,seq,stat,err) \ + UX_TEST_ASSERT(host_bulk_in[0] == (type));\ + UX_TEST_ASSERT((len) == _ux_utility_long_get(host_bulk_in + 1));\ + UX_TEST_ASSERT(host_bulk_in[5] == (slot));\ + UX_TEST_ASSERT(host_bulk_in[6] == (seq));\ + UX_TEST_ASSERT(host_bulk_in[7] == (stat)); /* bStatus: not present. */\ + UX_TEST_ASSERT(host_bulk_in[8] == (err)); + +static VOID _buffer_dump(VOID *buf, ULONG len) +{ +ULONG i; + for(i = 0; i < len; i ++) + printf(" %02x", ((UCHAR *)buf)[i]); + printf("\n"); +} + +static VOID _ccid_icc_insert_test(VOID) +{ +UINT status; + + stepinfo(">>>>>>>>>> Test Insert\n"); + ux_device_class_ccid_icc_insert(device_ccid, 0, 0); + ux_device_class_ccid_icc_insert(device_ccid, 1, 0); + status = _ccid_message_interrupt_in(host_interrupt_in, &host_interrupt_in_length); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(host_interrupt_in_length == 2); + UX_TEST_ASSERT(host_interrupt_in[0] == 0x50); + +#if UX_DEVICE_CLASS_CCID_MAX_N_SLOTS > 1 + if (host_interrupt_in[1] == 0x03) + { + status = _ccid_message_interrupt_in(host_interrupt_in, &host_interrupt_in_length); + UX_TEST_ASSERT(host_interrupt_in_length == 2); + UX_TEST_ASSERT(host_interrupt_in[0] == 0x50); + UX_TEST_ASSERT(host_interrupt_in[1] == 0x0D); /* Slot0: exist, Slot1: insert. */ + } + else + UX_TEST_ASSERT(host_interrupt_in[1] == 0x0F); +#else + UX_TEST_ASSERT(host_interrupt_in[1] == 0x03); /* Slot0: exist. */ +#endif + +#if UX_DEVICE_CLASS_CCID_MAX_N_SLOTS > 1 + #define _RM_SLOT 1 + #define _RM_CHECK 0x09 /* Slot0: exist, Slot1: remove. */ +#else + #define _RM_SLOT 0 + #define _RM_CHECK 0x02 /* Slot0: remove, Slot1: remove. */ +#endif + stepinfo(">>>>>>>>>> Test Remove\n"); + ux_device_class_ccid_icc_remove(device_ccid, _RM_SLOT); + status = _ccid_message_interrupt_in(host_interrupt_in, &host_interrupt_in_length); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(host_interrupt_in_length == 2); + UX_TEST_ASSERT(host_interrupt_in[0] == 0x50); + UX_TEST_ASSERT(host_interrupt_in[1] == _RM_CHECK); + +#if UX_DEVICE_CLASS_CCID_MAX_N_SLOTS > 1 + #define _INS_SLOT 1 + #define _INS_CHECK 0x0D /* Slot0: exist, Slot1: insert. */ +#else + #define _INS_SLOT 0 + #define _INS_CHECK 0x03 /* Slot0: insert, Slot1: remove. */ +#endif + stepinfo(">>>>>>>>>> Test Insert (auto)\n"); + ux_device_class_ccid_icc_insert(device_ccid, _INS_SLOT, 1); + status = _ccid_message_interrupt_in(host_interrupt_in, &host_interrupt_in_length); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(host_interrupt_in_length == 2); + UX_TEST_ASSERT(host_interrupt_in[0] == 0x50); + UX_TEST_ASSERT(host_interrupt_in[1] == _INS_CHECK); /* Slot0: exist, Slot1: insert. */ +} + +static VOID _ccid_icc_power_on_off_test(VOID) +{ +UINT status; + /* PC_to_RDR_IccPowerOn, RDR_to_PC_DataBlock */ + + /* Message(IccPowerOn). */ + stepinfo(">>>>>>>>>> Test IccPowerOn\n"); + _ux_utility_memory_set(host_bulk_out, 0, 10); + host_bulk_out[0] = 0x62; + host_bulk_out[5] = 0; /* bSlot. */ + host_bulk_out[6] = 0; /* bSeq. */ + _ux_utility_long_put(host_bulk_out+1, 0); + host_bulk_out[7] = 2; + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_icc_power_on, 10, host_bulk_out) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x80, 0, 0, 0, 0, 0) + +#if UX_DEVICE_CLASS_CCID_MAX_N_SLOTS > 1 + + /* Message(IccPowerOff). */ + stepinfo(">>>>>>>>>> Test IccPowerOff\n"); + host_bulk_out[0] = 0x63; + host_bulk_out[5] = 0; /* bSlot. */ + host_bulk_out[6] = 1; /* bSeq. */ + host_bulk_out[7] = 0; + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_icc_power_off, 10, host_bulk_out) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x81, 0, 0, 1, 1, 0) + + /* Message(IccPowerOff) -> BUSY_WITH_AUTO_SEQUENCE. */ + stepinfo(">>>>>>>>>> Test IccPowerOff -> BUSY_WITH_AUTO_SEQUENCE\n"); + host_bulk_out[0] = 0x63; + host_bulk_out[5] = 1; /* bSlot. */ + host_bulk_out[6] = 0; /* bSeq. */ + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(UX_NULL, 10, host_bulk_out) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x81, 0, 1, 0, 0x41, 0xF2) + + /* Message(IccPowerOff). */ + stepinfo(">>>>>>>>>> Test seq done - IccPowerOff\n"); + ux_device_class_ccid_auto_seq_done(device_ccid, 1, UX_DEVICE_CLASS_CCID_ICC_ACTIVE); + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_icc_power_off, 10, host_bulk_out) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x81, 0, 1, 0, 1, 0) +#else + + /* Message(IccPowerOff) -> BUSY_WITH_AUTO_SEQUENCE. */ + stepinfo(">>>>>>>>>> Test IccPowerOff -> BUSY_WITH_AUTO_SEQUENCE\n"); + host_bulk_out[0] = 0x63; + host_bulk_out[5] = 0; /* bSlot. */ + host_bulk_out[6] = 1; /* bSeq. */ + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(UX_NULL, 10, host_bulk_out) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x81, 0, 0, 1, 0x41, 0xF2) + + /* Message(IccPowerOff). */ + stepinfo(">>>>>>>>>> Test seq done - IccPowerOff\n"); + ux_device_class_ccid_auto_seq_done(device_ccid, 0, UX_DEVICE_CLASS_CCID_ICC_ACTIVE); + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_icc_power_off, 10, host_bulk_out) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x81, 0, 0, 1, 1, 0) +#endif + + /* Message(IccPowerOn). */ + host_bulk_out[0] = 0x62; + host_bulk_out[5] = 0; /* bSlot. */ + host_bulk_out[6] = 3; /* bSeq. */ + host_bulk_out[7] = 1; + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_icc_power_on, 10, host_bulk_out) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x80, 0, 0, 3, 0, 0) +} + +static VOID _ccid_invalid_slot_test(VOID) +{ +UINT status; + /* PC_to_RDR_IccPowerOn, RDR_to_PC_DataBlock */ + + /* Message(IccPowerOn). */ + _ux_utility_memory_set(host_bulk_out, 0, 10); + host_bulk_out[0] = 0x62; + host_bulk_out[5] = 0; /* bSlot. */ + host_bulk_out[6] = 0; /* bSeq. */ + _ux_utility_long_put(host_bulk_out+1, 0); + host_bulk_out[7] = 1; + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_icc_power_on, 10, host_bulk_out) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x80, 0, 0, 0, 0, 0) + +#if UX_DEVICE_CLASS_CCID_MAX_N_SLOTS > 1 + + /* Good slot. */ + host_bulk_out[5] = 1; /* bSlot. */ + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_icc_power_on, 10, host_bulk_out) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x80, 0, 1, 0, 0, 0) +#endif + +#if UX_DEVICE_CLASS_CCID_MAX_N_SLOTS > 2 + + /* Good slot. */ + host_bulk_out[5] = 2; /* bSlot. */ + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_icc_power_on, 10, host_bulk_out) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x80, 0, 2, 0, 0, 0) +#endif + +#if UX_DEVICE_CLASS_CCID_MAX_N_SLOTS > 3 + + /* Invalid slot. */ + host_bulk_out[5] = 3; /* bSlot. */ + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(UX_NULL, 10, host_bulk_out) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x80, 0, 3, 0, 0x42, 5) +#endif +} + +static VOID _ccid_busy_slot_test(VOID) +{ +UINT status; + stepinfo(">>>>>>>>>> Test CCID Busy ...\n"); + + /* PC_to_RDR_XfrBlock, RDR_to_PC_DataBlock. */ + _ux_utility_memory_set(host_bulk_out, 0, 10); + _ux_utility_memory_set(host_bulk_out_busy, 0, 10); + /* Same slot response busy. */ + { + stepinfo(">>>>>>>>>> Test CCID Busy - Xfer blocked\n"); + /* _XfrBlock ... blocked. */ + host_bulk_out[0] = 0x6F; + host_bulk_out[5] = 0; /* bSlot. */ + host_bulk_out[6] = 8; /* bSeq. */ + _ux_utility_long_put(host_bulk_out+1, 0); + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, UX_NULL, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_xfr_block, 10, host_bulk_out) + + stepinfo(">>>>>>>>>> Test CCID Busy - Xfer response busy\n"); + /* _XfrBlock ... response busy. */ + host_bulk_out_busy[0] = 0x6F; + host_bulk_out_busy[5] = 0; /* bSlot. */ + host_bulk_out_busy[6] = 8; /* bSeq. */ + _ux_utility_long_put(host_bulk_out_busy+1, 0); + host_bulk_out_busy[6] = 9; /* bSeq. */ + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out_busy, 10, host_bulk_in, &host_bulk_in_length); +#if defined(UX_DEVICE_STANDALONE) + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_xfr_block, 10, host_bulk_out) /* Task is polled */ +#else + _TEST_CCID_BULK_OUT_CHECK(UX_NULL, 10, host_bulk_out) +#endif + _TEST_CCID_BULK_IN_HEADER_CHECK(0x80, 0, 0, 9, 0x40, 0xE0) + + stepinfo(">>>>>>>>>> Test CCID Busy - Xfer done\n"); + /* Response. */ +#if defined(UX_DEVICE_STANDALONE) + slot_tester[0].state = SLOT_TESTER_STATE_NEXT; +#else + tx_semaphore_put(&slot_tester[0].semaphore); +#endif + status = _ccid_message_bulk_out_in(UX_NULL, 10, host_bulk_in, & host_bulk_in_length); + UX_TEST_ASSERT(status == UX_SUCCESS); + _TEST_CCID_BULK_IN_HEADER_CHECK(0x80, 64-10, 0, 8, 0, 0) + } +#if UX_DEVICE_CLASS_CCID_MAX_N_SLOTS > 1 + /* Max number of slots exceed, response busy. */ + { + /* _XfrBlock(0) ... blocked. */ + host_bulk_out[5] = 0; /* bSlot. */ + host_bulk_out[6] = 8; /* bSeq. */ + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, UX_NULL, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_xfr_block, 10, host_bulk_out) + + /* _XfrBlock(1) ... blocked. */ + host_bulk_out[5] = 1; /* bSlot. */ + host_bulk_out[6] = 2; /* bSeq. */ + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, UX_NULL, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_xfr_block, 10, host_bulk_out) + + /* _XfrBlock(2) ... response busy. */ + host_bulk_out[5] = 2; /* bSlot. */ + host_bulk_out[6] = 7; /* bSeq. */ + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(UX_NULL, 10, host_bulk_out) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x80, 0, 2, 7, 0x40, 0xE0) + + /* Response(1). */ + tx_semaphore_put(&slot_tester[1].semaphore); + status = _ccid_message_bulk_out_in(UX_NULL, 10, host_bulk_in, & host_bulk_in_length); + UX_TEST_ASSERT(status == UX_SUCCESS); + _TEST_CCID_BULK_IN_HEADER_CHECK(0x80, 64-10, 1, 2, 0, 0) + + /* _XfrBlock(2) ... Blocked. */ + host_bulk_out[5] = 2; /* bSlot. */ + host_bulk_out[6] = 7; /* bSeq. */ + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, UX_NULL, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_xfr_block, 10, host_bulk_out) + + /* Response(0). */ + tx_semaphore_put(&slot_tester[0].semaphore); + status = _ccid_message_bulk_out_in(UX_NULL, 10, host_bulk_in, & host_bulk_in_length); + UX_TEST_ASSERT(status == UX_SUCCESS); + _TEST_CCID_BULK_IN_HEADER_CHECK(0x80, 64-10, 0, 8, 0, 0) + + /* Response(2). */ + tx_semaphore_put(&slot_tester[2].semaphore); + status = _ccid_message_bulk_out_in(UX_NULL, 10, host_bulk_in, & host_bulk_in_length); + UX_TEST_ASSERT(status == UX_SUCCESS); + _TEST_CCID_BULK_IN_HEADER_CHECK(0x80, 64-10, 2, 7, 0, 0) + } +#endif + +} + +static VOID _ccid_abort_test(VOID) +{ +UINT status; + /* PC_to_RDR_XfrBlock, RDR_to_PC_DataBlock. */tx_thread_sleep(10); + _ux_utility_memory_set(host_bulk_out, 0, 10); + _ux_utility_memory_set(host_bulk_out_busy, 0, 10); + /* Same slot response busy. */ + { + /* _XfrBlock ... blocked. */ + stepinfo(">>>>>>>>>> Test CCID Abort - Xfer blocked\n"); + host_bulk_out[0] = 0x6F; + host_bulk_out[5] = 0; /* bSlot. */ + host_bulk_out[6] = 8; /* bSeq. */ + _ux_utility_long_put(host_bulk_out+1, 0); + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out, 10, UX_NULL, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_xfr_block, 10, host_bulk_out) + + /* _XfrBlock ... response busy. */ + stepinfo(">>>>>>>>>> Test CCID Abort - Xfer busy\n"); + host_bulk_out_busy[0] = 0x6F; + host_bulk_out_busy[5] = 0; /* bSlot. */ + host_bulk_out_busy[6] = 9; /* bSeq. */ + device_ccid_callback_log.handle = UX_NULL; + status = _ccid_message_bulk_out_in(host_bulk_out_busy, 10, host_bulk_in, &host_bulk_in_length); +#if defined(UX_DEVICE_STANDALONE) + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_xfr_block, 10, host_bulk_out) /* Still polled in wait state. */ +#else + _TEST_CCID_BULK_OUT_CHECK(UX_NULL, 10, host_bulk_out) +#endif + _TEST_CCID_BULK_IN_HEADER_CHECK(0x80, 0, 0, 9, 0x40, 0xE0) + + /* Abort. */ + stepinfo(">>>>>>>>>> Test CCID Abort - Xfer abort\n"); + status = _ccid_abort(0, 12); + UX_TEST_ASSERT(status == UX_SUCCESS); + + /* _XfrBlock ... OK. */ + stepinfo(">>>>>>>>>> Test CCID Abort - Xfer OK\n"); + host_bulk_out[0] = 0x6F; + host_bulk_out[5] = 0; /* bSlot. */ + host_bulk_out[6] = 20; /* bSeq. */ + _ux_utility_long_put(host_bulk_out+1, 0); + device_ccid_callback_log.handle = UX_NULL; +#if defined(UX_DEVICE_STANDALONE) + slot_tester[0].state = SLOT_TESTER_STATE_NEXT; +#else + tx_semaphore_put(&slot_tester[0].semaphore); +#endif + status = _ccid_message_bulk_out_in(host_bulk_out, 10, host_bulk_in, &host_bulk_in_length); + _TEST_CCID_BULK_OUT_CHECK(ux_test_ccid_xfr_block, 10, host_bulk_out) + _TEST_CCID_BULK_IN_HEADER_CHECK(0x80, 64-10, 0, 20, 0, 0) + } +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +ULONG mem_free; +ULONG loop; +ULONG parameter_u32[64/4]; +USHORT *parameter_u16 = (USHORT*)parameter_u32; +UCHAR *parameter_u8 = (UCHAR*)parameter_u32; + + + stepinfo("\n"); + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + status = ux_test_sleep_break_on_success(100, _test_check_host_connection_success); + UX_TEST_ASSERT(status == UX_SUCCESS); + + _ccid_icc_insert_test(); + _ccid_icc_power_on_off_test(); + + _ccid_invalid_slot_test(); + _ccid_busy_slot_test(); + _ccid_abort_test(); + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + status = ux_test_sleep_break_on_success(100, _test_check_host_disconnection_success); + UX_TEST_ASSERT(status == UX_SUCCESS); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_device_class_ccid_name, _ux_device_class_ccid_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); + tx_thread_relinquish(); +#else + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); +#endif + } +} + + +static UINT ux_test_ccid_icc_power_on(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ +UX_DEVICE_CLASS_CCID_PC_TO_RDR_ICC_POWER_ON_HEADER *icc_power_on; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_DATA_BLOCK_HEADER *data_block; + ux_test_callback_log(ux_test_ccid_icc_power_on, io_msg->ux_device_class_ccid_messages_pc_to_rdr); + /* Access to command. */ + icc_power_on = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_ICC_POWER_ON_HEADER*)io_msg->ux_device_class_ccid_messages_pc_to_rdr; + /* Access to data. */ + data_block = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_DATA_BLOCK_HEADER*)io_msg->ux_device_class_ccid_messages_rdr_to_pc; + /* bPowerSelect. */ + icc_power_on->bPowerSelect; + /* Update bStatus,bError. */ + data_block->bStatus = UX_DEVICE_CLASS_CCID_ICC_ACTIVE; + // data_block->bError = 0; + /* Update data length (reply message header only). */ + io_msg->ux_device_class_ccid_messages_rdr_to_pc_length = 10; +#if defined(UX_DEVICE_STANDALONE) + return(UX_STATE_NEXT); +#else + return(UX_SUCCESS); +#endif +} +static UINT ux_test_ccid_icc_power_off(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ +UX_DEVICE_CLASS_CCID_PC_TO_RDR_ICC_POWER_OFF_HEADER *cmd; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS_HEADER *rsp; + ux_test_callback_log(ux_test_ccid_icc_power_off, io_msg->ux_device_class_ccid_messages_pc_to_rdr); + /* Access to command. */ + cmd = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_ICC_POWER_OFF_HEADER*)io_msg->ux_device_class_ccid_messages_pc_to_rdr; + /* Access to data. */ + rsp = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS_HEADER*)io_msg->ux_device_class_ccid_messages_rdr_to_pc; + /* Update bStatus,bError. */ + rsp->bStatus = UX_DEVICE_CLASS_CCID_ICC_INACTIVE; + // rsp->bError = 0; +#if defined(UX_DEVICE_STANDALONE) + return(UX_STATE_NEXT); +#else + return(UX_SUCCESS); +#endif +} +static UINT ux_test_ccid_get_slot_status(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ +UX_DEVICE_CLASS_CCID_PC_TO_RDR_GET_SLOT_STATUS_HEADER *cmd; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS_HEADER *rsp; + ux_test_callback_log(ux_test_ccid_get_slot_status, io_msg->ux_device_class_ccid_messages_pc_to_rdr); + /* Access to command. */ + cmd = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_GET_SLOT_STATUS_HEADER*)io_msg->ux_device_class_ccid_messages_pc_to_rdr; + /* Access to data. */ + rsp = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS_HEADER*)io_msg->ux_device_class_ccid_messages_rdr_to_pc; + /* Update bStatus,bError. */ + // rsp->bStatus = 0; + // rsp->bError = 0; + // rsp->bClockStatus = 0; +#if defined(UX_DEVICE_STANDALONE) + return(UX_STATE_NEXT); +#else + return(UX_SUCCESS); +#endif +} +static UINT ux_test_ccid_xfr_block(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ +UX_DEVICE_CLASS_CCID_PC_TO_RDR_XFR_BLOCK_HEADER *cmd; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_DATA_BLOCK_HEADER *rsp; +UCHAR *cmd_data; +UCHAR *rsp_data; +UCHAR i; + ux_test_callback_log(ux_test_ccid_xfr_block, io_msg->ux_device_class_ccid_messages_pc_to_rdr); + /* Access to command. */ + cmd = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_XFR_BLOCK_HEADER*)io_msg->ux_device_class_ccid_messages_pc_to_rdr; + /* Access to data. */ + rsp = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_DATA_BLOCK_HEADER*)io_msg->ux_device_class_ccid_messages_rdr_to_pc; + /* Access to data buffers. */ + cmd_data = (UCHAR*)io_msg->ux_device_class_ccid_messages_pc_to_rdr + UX_DEVICE_CLASS_CCID_MESSAGE_HEADER_LENGTH; + rsp_data = (UCHAR*)io_msg->ux_device_class_ccid_messages_rdr_to_pc + UX_DEVICE_CLASS_CCID_MESSAGE_HEADER_LENGTH; + + /* Time extension. */ + // ux_device_class_ccid_time_extension(device_ccid, slot, 10); + +#if defined(UX_DEVICE_STANDALONE) + switch(slot_tester[cmd->bSlot].state) + { + case SLOT_TESTER_STATE_START: + slot_tester[cmd->bSlot].state = SLOT_TESTER_STATE_WAIT; + return(UX_STATE_WAIT); + case SLOT_TESTER_STATE_WAIT: + return(UX_STATE_WAIT); + case SLOT_TESTER_STATE_NEXT: + slot_tester[cmd->bSlot].state = SLOT_TESTER_STATE_IDLE; + break; + default: + slot_tester[cmd->bSlot].state = SLOT_TESTER_STATE_START; + return(UX_STATE_WAIT); + } +#else + + /* Semaphore wait. */ + tx_semaphore_get(&slot_tester[cmd->bSlot].semaphore, slot_tester[cmd->bSlot].timeout); + /* Abort? */ + if (slot_tester[cmd->bSlot].flags & SLOT_TESTER_FLAG_ABORT) + { + slot_tester[cmd->bSlot].flags &= ~SLOT_TESTER_FLAG_ABORT; + return(UX_ERROR); + } +#endif + + /* Update bStatus,bError. */ + // rsp->bStatus = 0; + // rsp->bError = 0; + + /* Update data. */ + for (i = 10; i < 64; i ++) + rsp_data[i] = i; + + /* Update data length. */ + UX_DEVICE_CLASS_CCID_MESSAGE_LENGTH_SET(rsp, 64-10); + io_msg->ux_device_class_ccid_messages_rdr_to_pc_length = 64; + +#if defined(UX_DEVICE_STANDALONE) + return(UX_STATE_NEXT); +#else + return(UX_SUCCESS); +#endif +} +static UINT ux_test_ccid_get_parameters(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ +UX_DEVICE_CLASS_CCID_PC_TO_RDR_GET_PARAMETERS_HEADER *cmd; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_HEADER *rsp; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_T0 *t0; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_T1 *t1; + ux_test_callback_log(ux_test_ccid_get_parameters, io_msg->ux_device_class_ccid_messages_pc_to_rdr); + /* Access to command. */ + cmd = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_GET_PARAMETERS_HEADER*)io_msg->ux_device_class_ccid_messages_pc_to_rdr; + /* Access to data. */ + rsp = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_HEADER*)io_msg->ux_device_class_ccid_messages_rdr_to_pc; + /* Parameters protocol. */ + rsp->bProtocolNum = 0; + if (rsp->bProtocolNum == 0) + { + t0 = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_T0 *)rsp; + t0->bmFindexDindex = 0; + /* ... */ + } + else if (rsp->bProtocolNum == 1) + { + t1 = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_T1 *)rsp; + t1->bmFindexDindex = 0; + /* ... */ + } + /* Update bStatus,bError. */ + // rsp->bStatus = 0; + // rsp->bError = 0; + /* Update data length. */ + UX_DEVICE_CLASS_CCID_MESSAGE_LENGTH_SET(rsp, 5); + io_msg->ux_device_class_ccid_messages_rdr_to_pc_length = 5+10; +#if defined(UX_DEVICE_STANDALONE) + return(UX_STATE_NEXT); +#else + return(UX_SUCCESS); +#endif +} +static UINT ux_test_ccid_reset_parameters(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ +UX_DEVICE_CLASS_CCID_PC_TO_RDR_RESET_PARAMETERS_HEADER *cmd; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_HEADER *rsp; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_T0 *t0; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_T1 *t1; + ux_test_callback_log(ux_test_ccid_reset_parameters, io_msg->ux_device_class_ccid_messages_pc_to_rdr); + /* Access to command. */ + cmd = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_RESET_PARAMETERS_HEADER*)io_msg->ux_device_class_ccid_messages_pc_to_rdr; + /* Access to response. */ + rsp = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_HEADER*)io_msg->ux_device_class_ccid_messages_rdr_to_pc; + /* Parameters protocol. */ + rsp->bProtocolNum = 0; + if (rsp->bProtocolNum == 0) + { + t0 = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_T0 *)rsp; + t0->bmFindexDindex = 0; + /* ... */ + } + else if (rsp->bProtocolNum == 1) + { + t1 = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_T1 *)rsp; + t1->bmFindexDindex = 0; + /* ... */ + } + /* Update bStatus,bError. */ + // rsp->bStatus = 0; + // rsp->bError = 0; + /* Update data length. */ + UX_DEVICE_CLASS_CCID_MESSAGE_LENGTH_SET(rsp, 5); + io_msg->ux_device_class_ccid_messages_rdr_to_pc_length = 5+10; +#if defined(UX_DEVICE_STANDALONE) + return(UX_STATE_NEXT); +#else + return(UX_SUCCESS); +#endif +} +static UINT ux_test_ccid_set_parameters(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ +UX_DEVICE_CLASS_CCID_PC_TO_RDR_SET_PARAMETERS_HEADER *cmd; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_HEADER *rsp; +UX_DEVICE_CLASS_CCID_PC_TO_RDR_SET_PARAMETERS_T0 *cmd_t0; +UX_DEVICE_CLASS_CCID_PC_TO_RDR_SET_PARAMETERS_T1 *cmd_t1; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_T0 *rsp_t0; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_T1 *rsp_t1; + ux_test_callback_log(ux_test_ccid_set_parameters, io_msg->ux_device_class_ccid_messages_pc_to_rdr); + /* Access to command. */ + cmd = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_SET_PARAMETERS_HEADER*)io_msg->ux_device_class_ccid_messages_pc_to_rdr; + /* Access to response. */ + rsp = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_HEADER*)io_msg->ux_device_class_ccid_messages_rdr_to_pc; + if (rsp->bProtocolNum == 0) + { + cmd_t0 = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_SET_PARAMETERS_T0 *)cmd; + rsp_t0 = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_T0 *)rsp; + /* ... */ + } + else + { + cmd_t1 = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_SET_PARAMETERS_T1 *)cmd; + rsp_t1 = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_PARAMETERS_T1 *)rsp; + } + /* Update bStatus,bError. */ + // rsp->bStatus = 0; + // rsp->bError = 0; + /* Update data length. */ + UX_DEVICE_CLASS_CCID_MESSAGE_LENGTH_SET(rsp, 5); + io_msg->ux_device_class_ccid_messages_rdr_to_pc_length = 5+10; +#if defined(UX_DEVICE_STANDALONE) + return(UX_STATE_NEXT); +#else + return(UX_SUCCESS); +#endif +} +static UINT ux_test_ccid_escape(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ +UX_DEVICE_CLASS_CCID_PC_TO_RDR_ESCAPE_HEADER *cmd; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_ESCAPE_HEADER *rsp; +UCHAR *cmd_data; +UCHAR *rsp_data; + ux_test_callback_log(ux_test_ccid_escape, io_msg->ux_device_class_ccid_messages_pc_to_rdr); + /* Access to command. */ + cmd = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_ESCAPE_HEADER*)io_msg->ux_device_class_ccid_messages_pc_to_rdr; + /* Access to data. */ + rsp = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_ESCAPE_HEADER*)io_msg->ux_device_class_ccid_messages_rdr_to_pc; + cmd_data = io_msg->ux_device_class_ccid_messages_pc_to_rdr + UX_DEVICE_CLASS_CCID_MESSAGE_HEADER_LENGTH; + rsp_data = io_msg->ux_device_class_ccid_messages_rdr_to_pc + UX_DEVICE_CLASS_CCID_MESSAGE_HEADER_LENGTH; + /* Update bStatus,bError. */ + // rsp->bStatus = 0; + // rsp->bError = 0; + /* Update data length. */ + UX_DEVICE_CLASS_CCID_MESSAGE_LENGTH_SET(rsp, 128); + io_msg->ux_device_class_ccid_messages_rdr_to_pc_length = 128+10; +#if defined(UX_DEVICE_STANDALONE) + return(UX_STATE_NEXT); +#else + return(UX_SUCCESS); +#endif +} +static UINT ux_test_ccid_icc_clock(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ +UX_DEVICE_CLASS_CCID_PC_TO_RDR_ICC_CLOCK_HEADER *cmd; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS_HEADER *rsp; + ux_test_callback_log(ux_test_ccid_icc_clock, io_msg->ux_device_class_ccid_messages_pc_to_rdr); + /* Access to command. */ + cmd = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_ICC_CLOCK_HEADER*)io_msg->ux_device_class_ccid_messages_pc_to_rdr; + /* Access to data. */ + rsp = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS_HEADER*)io_msg->ux_device_class_ccid_messages_rdr_to_pc; + /* Clock command. */ + cmd->bClockCommand; + /* Update bStatus,bError. */ + // rsp->bStatus = 0; + // rsp->bError = 0; +#if defined(UX_DEVICE_STANDALONE) + return(UX_STATE_NEXT); +#else + return(UX_SUCCESS); +#endif +} +static UINT ux_test_ccid_t0_apdu(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ +UX_DEVICE_CLASS_CCID_PC_TO_RDR_T0_APDU_HEADER *cmd; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS_HEADER *rsp; + ux_test_callback_log(ux_test_ccid_t0_apdu, io_msg->ux_device_class_ccid_messages_pc_to_rdr); + /* Access to command. */ + cmd = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_T0_APDU_HEADER*)io_msg->ux_device_class_ccid_messages_pc_to_rdr; + /* Access to data. */ + rsp = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS_HEADER*)io_msg->ux_device_class_ccid_messages_rdr_to_pc; + /* Changes. */ + if (cmd->bmChanges & UX_DEVICE_CLASS_CCID_CHANGE_CLASS_ENVELOPE) + { + cmd->bClassEnvelope; + } + if (cmd->bmChanges & UX_DEVICE_CLASS_CCID_CHANGE_CLASS_GET_RESPONSE) + { + cmd->bClassGetResponse; + } + /* Update bStatus,bError. */ + rsp->bStatus = 0; + rsp->bError = 0; + +#if defined(UX_DEVICE_STANDALONE) + return(UX_STATE_NEXT); +#else + return(UX_SUCCESS); +#endif +} +static UINT ux_test_ccid_secure(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ +UX_DEVICE_CLASS_CCID_PC_TO_RDR_SECURE_HEADER *cmd; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_DATA_BLOCK_HEADER *rsp; +UCHAR *cmd_data; +UCHAR *rsp_data; + ux_test_callback_log(ux_test_ccid_secure, io_msg->ux_device_class_ccid_messages_pc_to_rdr); + /* Access to command. */ + cmd = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_SECURE_HEADER*)io_msg->ux_device_class_ccid_messages_pc_to_rdr; + /* Access to data. */ + rsp = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_DATA_BLOCK_HEADER*)io_msg->ux_device_class_ccid_messages_rdr_to_pc; + + cmd->wLevelParameter; + rsp->bChainParameter; + + cmd_data = io_msg->ux_device_class_ccid_messages_pc_to_rdr + UX_DEVICE_CLASS_CCID_MESSAGE_HEADER_LENGTH; + rsp_data = io_msg->ux_device_class_ccid_messages_rdr_to_pc + UX_DEVICE_CLASS_CCID_MESSAGE_HEADER_LENGTH; + + /* Update bStatus,bError. */ + // rsp->bStatus = 0; + // rsp->bError = 0; + /* Update data length. */ + UX_DEVICE_CLASS_CCID_MESSAGE_LENGTH_SET(rsp, 128/8); + io_msg->ux_device_class_ccid_messages_rdr_to_pc_length = 128/8+10; +#if defined(UX_DEVICE_STANDALONE) + return(UX_STATE_NEXT); +#else + return(UX_SUCCESS); +#endif +} +static UINT ux_test_ccid_mechanical(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ +UX_DEVICE_CLASS_CCID_PC_TO_RDR_MECHANICAL_HEADER *cmd; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS_HEADER *rsp; + ux_test_callback_log(ux_test_ccid_mechanical, io_msg->ux_device_class_ccid_messages_pc_to_rdr); + /* Access to command. */ + cmd = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_MECHANICAL_HEADER*)io_msg->ux_device_class_ccid_messages_pc_to_rdr; + /* Access to data. */ + rsp = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS_HEADER*)io_msg->ux_device_class_ccid_messages_rdr_to_pc; + /* Update bStatus,bError. */ + // rsp->bStatus = 0; + // rsp->bError = 0; +#if defined(UX_DEVICE_STANDALONE) + return(UX_STATE_NEXT); +#else + return(UX_SUCCESS); +#endif +} +static UINT ux_test_ccid_abort(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ +UX_DEVICE_CLASS_CCID_PC_TO_RDR_ABORT_HEADER *cmd; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS_HEADER *rsp; + /* Control request Abort. */ + if (io_msg == UX_NULL) + { + ux_test_callback_log(ux_test_ccid_abort, UX_NULL); + slot_tester[slot].flags |= SLOT_TESTER_FLAG_ABORT; +#if defined(UX_DEVICE_STANDALONE) + slot_tester[slot].state = SLOT_TESTER_STATE_NEXT; + return(UX_STATE_NEXT); +#else + tx_semaphore_put(&slot_tester[slot].semaphore); + return(UX_SUCCESS); +#endif + } + /* Bulk OUT Abort. */ + ux_test_callback_log(ux_test_ccid_abort, io_msg->ux_device_class_ccid_messages_pc_to_rdr); + /* Access to command. */ + cmd = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_ABORT_HEADER*)io_msg->ux_device_class_ccid_messages_pc_to_rdr; + /* Access to data. */ + rsp = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS_HEADER*)io_msg->ux_device_class_ccid_messages_rdr_to_pc; + /* Update bStatus,bError. */ + // rsp->bStatus = 0; + // rsp->bError = 0; +#if defined(UX_DEVICE_STANDALONE) + return(UX_STATE_NEXT); +#else + return(UX_SUCCESS); +#endif +} +static UINT ux_test_ccid_set_data_rate_and_clock_frequency(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ +UX_DEVICE_CLASS_CCID_PC_TO_RDR_SET_DATA_RATE_AND_CLOCK_FREQUENCY *cmd; +UX_DEVICE_CLASS_CCID_RDR_TO_PC_DATA_RATE_AND_CLOCK_FREQUENCY *rsp; +ULONG data_rate; +ULONG clock; + ux_test_callback_log(ux_test_ccid_set_data_rate_and_clock_frequency, io_msg->ux_device_class_ccid_messages_pc_to_rdr); + /* Access to command. */ + cmd = (UX_DEVICE_CLASS_CCID_PC_TO_RDR_SET_DATA_RATE_AND_CLOCK_FREQUENCY*)io_msg->ux_device_class_ccid_messages_pc_to_rdr; + /* Access to data. */ + rsp = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_DATA_RATE_AND_CLOCK_FREQUENCY*)io_msg->ux_device_class_ccid_messages_rdr_to_pc; + data_rate = UX_DEVICE_CLASS_CCID_PC_TO_RDR_CLOCK_FREQUENCY_GET(cmd); + clock = UX_DEVICE_CLASS_CCID_PC_TO_RDR_DATA_RATE_GET(cmd); + /* Update bStatus,bError. */ + // rsp->bStatus = 0; + // rsp->bError = 0; + /* Update response data rate and clock. */ + UX_DEVICE_CLASS_CCID_RDR_TO_PC_CLOCK_FREQUENCY_SET(rsp, clock); + UX_DEVICE_CLASS_CCID_RDR_TO_PC_DATA_RATE_SET(rsp, data_rate); +#if defined(UX_DEVICE_STANDALONE) + return(UX_STATE_NEXT); +#else + return(UX_SUCCESS); +#endif +} diff --git a/test/regression/usbx_device_dfu_basic_test.c b/test/regression/usbx_device_dfu_basic_test.c new file mode 100644 index 00000000..b73afa62 --- /dev/null +++ b/test/regression/usbx_device_dfu_basic_test.c @@ -0,0 +1,900 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" + +#include "fx_api.h" + +#include "ux_device_class_dfu.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +#define UX_DEMO_REQUEST_MAX_LENGTH \ + ((UX_HCD_SIM_HOST_MAX_PAYLOAD) > (UX_SLAVE_REQUEST_DATA_MAX_LENGTH) ? \ + (UX_HCD_SIM_HOST_MAX_PAYLOAD) : (UX_SLAVE_REQUEST_DATA_MAX_LENGTH)) + + +/* Define constants. */ + +#define UX_DEMO_MEMORY_SIZE (128*1024) +#define UX_DEMO_STACK_SIZE (1024) + + +/* Define local/extern function prototypes. */ + +static void test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static void tx_test_thread_host_simulation_entry(ULONG); +static void tx_test_thread_slave_simulation_entry(ULONG); + +static VOID demo_thread_dfu_activate(VOID *dfu); +static VOID demo_thread_dfu_deactivate(VOID *dfu); +static UINT demo_thread_dfu_read(VOID *dfu, ULONG block_number, UCHAR * data_pointer, ULONG length, ULONG *actual_length); +static UINT demo_thread_dfu_write(VOID *dfu, ULONG block_number, UCHAR * data_pointer, ULONG length, ULONG *media_status); +static UINT demo_thread_dfu_get_status(VOID *dfu, ULONG *media_status); +static UINT demo_thread_dfu_notify(VOID *dfu, ULONG notification); +static UINT demo_thread_dfu_custom_request(VOID *dfu, UX_SLAVE_TRANSFER *transfer); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +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 interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +static UX_SLAVE_CLASS_DFU_PARAMETER dfu_parameter; + +static UX_DEVICE *device; +static ULONG dfu_block; +static ULONG dfu_transfer_length; +static ULONG dfu_actual_length; +static UCHAR dfu_host_buffer[UX_DEMO_REQUEST_MAX_LENGTH]; +static UCHAR dfu_device_buffer[UX_DEMO_REQUEST_MAX_LENGTH]; + + +/* Define device framework. */ + +/* DFU descriptor must be same for all frameworks!!! */ +#define DFU_FUNCTION_DESCRIPTOR \ + /* Functional descriptor for DFU. */ \ + 0x09, 0x21, \ + 0x0f, /* bmAttributes: B3 bitWillDetach */ \ + /* B2 bitManifestationTolerant */ \ + /* B1 bitCanUpload, B0 bitCanDnload */ \ + 0xE8, 0x03, /* wDetachTimeOut: 0x03E8 (1000) */ \ + UX_W0(UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH), \ + UX_W1(UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH), /* wTransferSize: */ \ + 0x00, 0x01, /* bcdDFUVersion: 0x0100 */ + +/* Interface descriptor for APP/DFU mode. */ +#define DFU_INTERFACE_DESCRIPTOR(bInterfaceNumber, bInterfaceProtocol) \ + /* Interface descriptor for DFU. */ \ + 0x09, 0x04, \ + (bInterfaceNumber), 0x00, 0x00, \ + 0xFE, 0x01, (bInterfaceProtocol), \ + 0x00, \ + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x40, + 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x1b, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor for DFU (bInterfaceProtocol = 1). */ + DFU_INTERFACE_DESCRIPTOR(0x00, 0x01) + DFU_FUNCTION_DESCRIPTOR +}; + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x99, 0x99, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x1b, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor for DFU (bInterfaceProtocol = 1). */ + DFU_INTERFACE_DESCRIPTOR(0x00, 0x01) + DFU_FUNCTION_DESCRIPTOR +}; + +/* 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 sizeof(string_framework) +static UCHAR string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Microsoft AzureRTOS" */ + 0x09, 0x04, 0x01, 19, + 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', + 't', ' ', 'A', 'z', 'u', 'r', 'e', 'R', + 'T', 'O', 'S', + + /* Product string descriptor : Index 2 - "DFU Demo Device" */ + 0x09, 0x04, 0x02, 15, + 'D', 'F', 'U', ' ', 'D', 'e', 'm', 'o', + ' ', 'D', 'e', 'v', 'i', 'c', 'e', + + /* Serial Number string descriptor : Index 3 - "0000" */ + 0x09, 0x04, 0x03, 0x04, + '0', '0', '0', '0' +}; + +/* 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 sizeof(language_id_framework) +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; + + +#define DEVICE_FRAMEWORK_LENGTH_DFU sizeof(device_framework_dfu) +static UCHAR device_framework_dfu[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x40, + 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x1B, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor for DFU (bInterfaceProtocol = 2). */ + DFU_INTERFACE_DESCRIPTOR(0x00, 0x02) + DFU_FUNCTION_DESCRIPTOR +}; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* 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); + } + } +} + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static UINT demo_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + if (event == UX_DEVICE_CONNECTION) + { + device = (UX_DEVICE *)inst; + } + if (event == UX_DEVICE_DISCONNECTION) + { + if ((VOID *)device == inst) + device = UX_NULL; + } +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_device_dfu_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +ULONG test_n; + + /* Inform user. */ + printf("Running Device DFU Basic Functionality 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(); + + /* 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 #%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(demo_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* There is no host class for DFU now. */ + + /* 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); + } + + /* Store the DFU parameters. */ + dfu_parameter.ux_slave_class_dfu_parameter_instance_activate = demo_thread_dfu_activate; + dfu_parameter.ux_slave_class_dfu_parameter_instance_deactivate = demo_thread_dfu_deactivate; + dfu_parameter.ux_slave_class_dfu_parameter_read = demo_thread_dfu_read; + dfu_parameter.ux_slave_class_dfu_parameter_write = demo_thread_dfu_write; + dfu_parameter.ux_slave_class_dfu_parameter_get_status = demo_thread_dfu_get_status; + dfu_parameter.ux_slave_class_dfu_parameter_notify = demo_thread_dfu_notify; +#ifdef UX_DEVICE_CLASS_DFU_CUSTOM_REQUEST_ENABLE + dfu_parameter.ux_device_class_dfu_parameter_custom_request = demo_thread_dfu_custom_request; +#endif + dfu_parameter.ux_slave_class_dfu_parameter_framework = device_framework_dfu; + dfu_parameter.ux_slave_class_dfu_parameter_framework_length = DEVICE_FRAMEWORK_LENGTH_DFU; + + /* Initilize the device dfu class. The class is connected with interface 1 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_dfu_name, ux_device_class_dfu_entry, + 1, 0, (VOID *)&dfu_parameter); + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_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_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(&tx_test_thread_host_simulation, "tx demo host simulation", tx_test_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx demo slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +static UINT _req_DFU_LOCK(UX_TRANSFER *control_transfer) +{ +UINT status; +#if defined(UX_HOST_STANDALONE) + while(1) + { + ux_system_tasks_run(); + tx_thread_relinquish(); + + UX_ENDPOINT *endpoint = control_transfer -> ux_transfer_request_endpoint; + if (endpoint == UX_NULL || endpoint -> ux_endpoint_state != UX_ENDPOINT_RUNNING) + { + status = UX_ENDPOINT_HANDLE_UNKNOWN; + break; + } + UX_DEVICE *device = endpoint -> ux_endpoint_device; + if (device == UX_NULL || device -> ux_device_handle != (ULONG)(ALIGN_TYPE)(device)) + { + status = UX_DEVICE_HANDLE_UNKNOWN; + break; + } + if ((device -> ux_device_flags & UX_DEVICE_FLAG_LOCK) == 0) + { + device -> ux_device_flags |= UX_DEVICE_FLAG_LOCK; + control_transfer -> ux_transfer_request_flags |= UX_TRANSFER_FLAG_AUTO_DEVICE_UNLOCK; + control_transfer -> ux_transfer_request_timeout_value = UX_WAIT_FOREVER; + status = UX_SUCCESS; + break; + } + } +#else + status = _ux_utility_semaphore_get(&control_transfer->ux_transfer_request_endpoint->ux_endpoint_device->ux_device_protection_semaphore, UX_WAIT_FOREVER); +#endif + if (status != UX_SUCCESS) + { + printf("ERROR #%d: %x\n", __LINE__, status); + test_control_return(1); + } +} +static UINT _req_DFU_GETSTATE(UX_TRANSFER *control_transfer) +{ + _req_DFU_LOCK(control_transfer); + control_transfer->ux_transfer_request_type = 0xA1; + control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_GET_STATE; + control_transfer->ux_transfer_request_index = 0; + control_transfer->ux_transfer_request_requested_length = 1; + control_transfer->ux_transfer_request_data_pointer = dfu_host_buffer; + control_transfer->ux_transfer_request_value = 0; + return ux_host_stack_transfer_request(control_transfer); +} +static UINT _req_DFU_GETSTATUS(UX_TRANSFER *control_transfer) +{ + _req_DFU_LOCK(control_transfer); + control_transfer->ux_transfer_request_type = 0xA1; + control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_GET_STATUS; + control_transfer->ux_transfer_request_index = 0; + control_transfer->ux_transfer_request_requested_length = 6; + control_transfer->ux_transfer_request_data_pointer = dfu_host_buffer; + control_transfer->ux_transfer_request_value = 0; + return ux_host_stack_transfer_request(control_transfer); +} +static UINT _req_DFU_DETACH(UX_TRANSFER *control_transfer) +{ + _req_DFU_LOCK(control_transfer); + control_transfer->ux_transfer_request_type = 0x21; + control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_DETACH; + control_transfer->ux_transfer_request_index = 0; + control_transfer->ux_transfer_request_value = 1000; + control_transfer->ux_transfer_request_requested_length = 0; + return ux_host_stack_transfer_request(control_transfer); +} +static UINT _req_DFU_DNLOAD_IN(UX_TRANSFER *control_transfer, ULONG block, ULONG len) +{ + _req_DFU_LOCK(control_transfer); + control_transfer->ux_transfer_request_type = 0xA1; + control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_DOWNLOAD; + control_transfer->ux_transfer_request_index = 0; + control_transfer->ux_transfer_request_data_pointer = dfu_host_buffer; + control_transfer->ux_transfer_request_requested_length = len; + control_transfer->ux_transfer_request_value = block; + return ux_host_stack_transfer_request(control_transfer); +} +static UINT _req_DFU_DNLOAD(UX_TRANSFER *control_transfer, ULONG block, ULONG len) +{ + _req_DFU_LOCK(control_transfer); + control_transfer->ux_transfer_request_type = 0x21; + control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_DOWNLOAD; + control_transfer->ux_transfer_request_index = 0; + control_transfer->ux_transfer_request_data_pointer = dfu_host_buffer; + control_transfer->ux_transfer_request_requested_length = len; + control_transfer->ux_transfer_request_value = block; + return ux_host_stack_transfer_request(control_transfer); +} +static UINT _req_DFU_UPLOAD(UX_TRANSFER *control_transfer, ULONG block, ULONG len) +{ + _req_DFU_LOCK(control_transfer); + control_transfer->ux_transfer_request_type = 0xA1; + control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_UPLOAD; + control_transfer->ux_transfer_request_index = 0; + control_transfer->ux_transfer_request_data_pointer = dfu_host_buffer; + control_transfer->ux_transfer_request_requested_length = len; + control_transfer->ux_transfer_request_value = block; + return ux_host_stack_transfer_request(control_transfer); +} +static UINT _req_DFU_CLRSTATUS(UX_TRANSFER *control_transfer) +{ + _req_DFU_LOCK(control_transfer); + control_transfer->ux_transfer_request_type = 0x21; + control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_CLEAR_STATUS; + control_transfer->ux_transfer_request_index = 0; + control_transfer->ux_transfer_request_data_pointer = UX_NULL; + control_transfer->ux_transfer_request_requested_length = 0; + control_transfer->ux_transfer_request_value = 0; + return ux_host_stack_transfer_request(control_transfer); +} + + +static void tx_test_thread_host_simulation_entry(ULONG arg) +{ +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *control_transfer; +ULONG len, trans_len, block; +INT i; +UINT status; + + stepinfo("\n"); + + stepinfo(">>>>>>>>>>>> Test DFU connect\n"); + status = ux_test_wait_for_non_null((VOID **)&device); + UX_TEST_ASSERT(status == UX_SUCCESS); + if (device -> ux_device_state == UX_DEVICE_CONFIGURED) + { + printf("ERROR #%d, device state 0x%lx\n", __LINE__, device->ux_device_state); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Test DFU set configure\n"); + status = ux_host_stack_device_configuration_select(device->ux_device_first_configuration); + UX_TEST_ASSERT(status == UX_SUCCESS); + + /* Get endpoint and transfer request. */ + control_endpoint = &device->ux_device_control_endpoint; + control_transfer = &control_endpoint->ux_endpoint_transfer_request; + + stepinfo(">>>>>>>>>>>> Test DFU_GETSTATE\n"); + status = _req_DFU_GETSTATE(control_transfer); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: transfer status 0x%x\n", __LINE__, status); + test_control_return(1); + } + UX_TEST_ASSERT(dfu_host_buffer[0] == UX_SYSTEM_DFU_STATE_APP_IDLE); + + stepinfo(">>>>>>>>>>>> Test DFU DETACH\n"); + + /* Uses DFU framework after USB reset (re-connect). */ + ux_test_dcd_sim_slave_connect_framework(device_framework_dfu, DEVICE_FRAMEWORK_LENGTH_DFU); + status = _req_DFU_DETACH(control_transfer); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: transfer status 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = ux_test_wait_for_null((VOID **)&device); + UX_TEST_ASSERT(status == UX_SUCCESS); + status = ux_test_wait_for_non_null((VOID **)&device); + UX_TEST_ASSERT(status == UX_SUCCESS); + status = ux_host_stack_device_configuration_select(device->ux_device_first_configuration); + UX_TEST_ASSERT(status == UX_SUCCESS); + + status = _req_DFU_GETSTATE(control_transfer); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: transfer status 0x%x\n", __LINE__, status); + test_control_return(1); + } + UX_TEST_ASSERT(dfu_host_buffer[0] == UX_SYSTEM_DFU_STATE_DFU_IDLE); + +#if defined(UX_DEVICE_CLASS_DFU_CUSTOM_REQUEST_ENABLE) + status = _req_DFU_DNLOAD(control_transfer, 0, 0); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: transfer status 0x%x\n", __LINE__, status); + test_control_return(1); + } + UX_TEST_ASSERT(dfu_host_buffer[0] == UX_SYSTEM_DFU_STATE_DFU_IDLE); +#else +#endif + + +#if !defined(UX_DEVICE_CLASS_DFU_UPLOAD_DISABLE) + + stepinfo(">>>>>>>>>>>> Test DFU UPLOAD FAIL\n"); + status = _req_DFU_UPLOAD(control_transfer, 0, UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH + 1); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: UPLOAD should STALL\n", __LINE__); + test_control_return(1); + } + status = _req_DFU_CLRSTATUS(control_transfer); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: CLRSTATUS error 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Test DFU UPLOAD\n"); + trans_len = UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH; + for (block = 0; block < 99; block ++) + { + for (i = 0; i < trans_len; i ++) + { + dfu_device_buffer[i] = (UCHAR)(block + i); + dfu_host_buffer[i] = 0xFF; + } + dfu_actual_length = trans_len; + status = _req_DFU_UPLOAD(control_transfer, block, trans_len); + if (status != UX_SUCCESS) + { + printf("ERROR #%d(%ld, %ld): UPLOAD status 0x%x\n", __LINE__, block, trans_len, status); + test_control_return(1); + } + UX_TEST_ASSERT(dfu_transfer_length == trans_len); + UX_TEST_ASSERT(dfu_block == block); + if (ux_utility_memory_compare(dfu_host_buffer, dfu_device_buffer, trans_len) != UX_SUCCESS) + { + printf("ERROR #%d(%ld, %ld): data error\n", __LINE__, block, trans_len); + printf(" device buffer %p: %2x %2x ...\n", dfu_device_buffer, dfu_device_buffer[0], dfu_device_buffer[1]); + printf(" host buffer %p: %2x %2x ...\n", dfu_host_buffer, dfu_host_buffer[0], dfu_host_buffer[1]); + test_control_return(1); + } + } + /* Finish upload. */ + dfu_actual_length = trans_len >> 1; + status = _req_DFU_UPLOAD(control_transfer, block, trans_len); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: UPLOAD(0) 0x%x\n", __LINE__, status); + test_control_return(1); + } + /* Check state. */ + status = _req_DFU_GETSTATE(control_transfer); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: transfer status 0x%x\n", __LINE__, status); + test_control_return(1); + } + UX_TEST_ASSERT(dfu_host_buffer[0] == UX_SYSTEM_DFU_STATE_DFU_IDLE); +#endif + + stepinfo(">>>>>>>>>>>> Test DFU DNLOAD error\n"); + status = _req_DFU_DNLOAD_IN(control_transfer, 0, 16); + UX_TEST_CHECK_CODE(UX_TRANSFER_STALLED, status); +#if defined(UX_DEVICE_CLASS_DFU_ERROR_GET_ENABLE) + status = _req_DFU_GETSTATUS(control_transfer); + UX_TEST_CHECK_SUCCESS(status); +#endif + status = _req_DFU_CLRSTATUS(control_transfer); + UX_TEST_CHECK_SUCCESS(status); + + stepinfo(">>>>>>>>>>>> Test DFU DNLOAD\n"); + for (len = 1, block = 0; len < UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH * 2; len <<= 1) + { + for (i = 0; i < len; i ++) + { + dfu_host_buffer[i] = (UCHAR)(block + i); + dfu_device_buffer[i] = 0xFF; + } + trans_len = UX_MIN(len, UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH); + + status = _req_DFU_DNLOAD(control_transfer, block, trans_len); + if (status != UX_SUCCESS) + { + printf("ERROR #%d(%ld, %ld): DNLOAD status 0x%x\n", __LINE__, block, trans_len, status); + test_control_return(1); + } + UX_TEST_ASSERT(dfu_transfer_length == trans_len); + UX_TEST_ASSERT(dfu_block == block); + if (ux_utility_memory_compare(dfu_host_buffer, dfu_device_buffer, trans_len) != UX_SUCCESS) + { + printf("ERROR #%d(%ld, %ld): data error\n", __LINE__, block, trans_len); + test_control_return(1); + } + + status = _req_DFU_GETSTATUS(control_transfer); + if (status != UX_SUCCESS) + { + printf("ERROR #%d(%ld, %ld): GETSTATUS status 0x%x\n", __LINE__, block, trans_len, status); + test_control_return(1); + } + + block ++; + } + /* Finish download. */ + status = _req_DFU_DNLOAD(control_transfer, block, 0); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: DNLOAD(0) 0x%x\n", __LINE__, status); + test_control_return(1); + } + /* Manifestation. */ + status = _req_DFU_GETSTATE(control_transfer); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: GETSTATE status 0x%x\n", __LINE__, status); + test_control_return(1); + } + UX_TEST_ASSERT(dfu_host_buffer[0] == UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_MANIFEST_SYNC); + + /* Uses DFU framework after USB reset (re-connect). */ + ux_test_dcd_sim_slave_connect_framework(UX_NULL, 0); + status = _req_DFU_GETSTATUS(control_transfer); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: GETSTATUS status 0x%x\n", __LINE__, status); + test_control_return(1); + } + UX_TEST_ASSERT(dfu_host_buffer[4] == UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_MANIFEST_WAIT_RESET); + + /* Reset */ + status = ux_test_wait_for_null((VOID **)&device); + UX_TEST_ASSERT(status == UX_SUCCESS); + status = ux_test_wait_for_non_null((VOID **)&device); + UX_TEST_ASSERT(status == UX_SUCCESS); + status = ux_host_stack_device_configuration_select(device->ux_device_first_configuration); + UX_TEST_ASSERT(status == UX_SUCCESS); + + status = _req_DFU_GETSTATE(control_transfer); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: transfer status 0x%x\n", __LINE__, status); + test_control_return(1); + } + UX_TEST_ASSERT(dfu_host_buffer[0] == UX_SYSTEM_DFU_STATE_APP_IDLE); + + stepinfo(">>>>>>>>>>>> All Done\n"); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* 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 void tx_test_thread_slave_simulation_entry(ULONG arg) +{ + while(1) + { + +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); + tx_thread_relinquish(); +#else + + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); +#endif + } +} + +static UINT demo_device_state_change(ULONG event) +{ + return(UX_SUCCESS); +} + +static VOID demo_thread_dfu_activate(VOID *dfu) +{ +} + +static VOID demo_thread_dfu_deactivate(VOID *dfu) +{ +} + +static UINT demo_thread_dfu_read(VOID *dfu, ULONG block_number, UCHAR * data_pointer, ULONG length, ULONG *actual_length) +{ +ULONG return_length; + + stepinfo("dfuRead %ld,%ld: %2x %2x %2x %2x ... -> %p\n", block_number, length, + dfu_device_buffer[0], dfu_device_buffer[1], dfu_device_buffer[2], dfu_device_buffer[3], + data_pointer); + dfu_block = block_number; + dfu_transfer_length = length; + + return_length = UX_MIN(length, sizeof(dfu_device_buffer)); + return_length = UX_MIN(return_length, dfu_actual_length); + + ux_utility_memory_copy(data_pointer, dfu_device_buffer, return_length); + + /* Here is where the data block is read from the firmware. */ + /* Some code needs to be inserted specifically for a target platform. */ + *actual_length = return_length; + return(UX_SUCCESS); +} + +static UINT demo_thread_dfu_write(VOID *dfu, ULONG block_number, UCHAR * data_pointer, ULONG length, ULONG *media_status) +{ + stepinfo("dfuWrite %ld,%ld\n", block_number, length); + dfu_block = block_number; + dfu_transfer_length = length; + ux_utility_memory_copy(dfu_device_buffer, data_pointer, UX_MIN(length, sizeof(dfu_device_buffer))); + + /* Here is where the data block is coming to be written to the firmware. */ + /* Some code needs to be inserted specifically for a target platform. */ + /* Return media status ok. */ + *media_status = UX_SLAVE_CLASS_DFU_MEDIA_STATUS_OK ; + return(UX_SUCCESS); +} + +static UINT demo_thread_dfu_get_status(VOID *dfu, ULONG *media_status) +{ + + /* Return media status ok. */ + *media_status = UX_SLAVE_CLASS_DFU_MEDIA_STATUS_OK ; + + return(UX_SUCCESS); +} + +static UINT demo_thread_dfu_notify(VOID *dfu, ULONG notification) +{ + stepinfo("dfuNotify 0x%lx\n", notification); + switch (notification) + { + + + case UX_SLAVE_CLASS_DFU_NOTIFICATION_BEGIN_DOWNLOAD : + + /* Begin of Download. */ + break; + + case UX_SLAVE_CLASS_DFU_NOTIFICATION_END_DOWNLOAD : + + /* Completion of Download. */ + break; + + case UX_SLAVE_CLASS_DFU_NOTIFICATION_ABORT_DOWNLOAD : + + /* Download was aborted. */ + break; + + case UX_SLAVE_CLASS_DFU_NOTIFICATION_BEGIN_UPLOAD : + + /* Begin of UPLOAD. */ + break; + + case UX_SLAVE_CLASS_DFU_NOTIFICATION_END_UPLOAD : + + /* Completion of UPLOAD. */ + break; + + case UX_SLAVE_CLASS_DFU_NOTIFICATION_ABORT_UPLOAD : + + /* Download was aborted. */ + break; + + default : + + /* Bad notification signal. Should never get here. */ + break; + + } + + return(UX_SUCCESS); +} + +static UINT demo_thread_dfu_custom_request(VOID *dfu, UX_SLAVE_TRANSFER *transfer) +{ +UCHAR *setup; +UCHAR *buffer; + + /* Check state and request to insert custom operation, before the standard + handling process. + If no standard handling process is needed, return UX_SUCCESS. + */ + + /* E.g., accept DNLOAD command with wLength 0 in dfuIDLE. */ + if (ux_device_class_dfu_state_get((UX_SLAVE_CLASS_DFU *)dfu) == UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_IDLE) + { + setup = transfer -> ux_slave_transfer_request_setup; + buffer = transfer -> ux_slave_transfer_request_data_pointer; + + if (setup[UX_SETUP_REQUEST] == UX_SLAVE_CLASS_DFU_COMMAND_DOWNLOAD && + setup[UX_SETUP_LENGTH] == 0 && + setup[UX_SETUP_LENGTH + 1] == 0) + { + + /* Accept the case (by default it's stalled). */ + stepinfo("dfuIDLE - accept dfuDNLOAD & wLength 0\n"); + + /* Fill the status data payload. First with status. */ + *buffer = UX_SLAVE_CLASS_DFU_STATUS_OK; + + /* Poll time out value is set to 500ms. */ + *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT) = UX_DW0(500); + *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 1) = UX_DW1(500); + *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 2) = UX_DW2(500); + + /* Next state: still dfuIDLE. */ + *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_STATE) = (UCHAR) UX_SYSTEM_DFU_STATE_DFU_IDLE; + + /* String index set to 0. */ + *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_STRING) = 0; + + /* We have a request to obtain the status of the DFU instance. */ + _ux_device_stack_transfer_request(transfer, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH); + + /* Inform stack it's taken. */ + return(UX_SUCCESS); + } + } + + /* No custom request. */ + return(UX_ERROR); +} diff --git a/test/regression/usbx_dpump_basic_test.c b/test/regression/usbx_dpump_basic_test.c new file mode 100644 index 00000000..25152f3d --- /dev/null +++ b/test/regression/usbx_dpump_basic_test.c @@ -0,0 +1,651 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + + +/* Define USBX demo constants. */ + +#define UX_DEMO_STACK_SIZE 4096 +#define UX_DEMO_BUFFER_SIZE 2048 +#define UX_DEMO_RUN 1 +#define UX_DEMO_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the demo application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + + +/* Define USBX demo global variables. */ + +static unsigned char host_out_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; +static unsigned char host_in_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; +static unsigned char slave_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave; + +static UINT expected_error; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, + +#ifdef UX_DEVICE_BIDIRECTIONAL_ENDPOINT_SUPPORT + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00 +#else + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00 +#endif + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00, + +#ifdef UX_DEVICE_BIDIRECTIONAL_ENDPOINT_SUPPORT + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00 +#else + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00 +#endif + }; + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* 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 + }; + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID tx_demo_instance_activate(VOID *dpump_instance); +static VOID tx_demo_instance_deactivate(VOID *dpump_instance); + +#if defined(UX_HOST_STANDALONE) +static UINT tx_demo_host_change_function(ULONG e, UX_HOST_CLASS *c, VOID *p); +#else +#define tx_demo_host_change_function UX_NULL +#endif + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); +static void tx_demo_thread_slave_simulation_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (expected_error == 0 || error_code != expected_error) + { + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %x\n", __LINE__, system_level, system_context, error_code); + // test_control_return(1); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_dpump_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; + + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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("Running DPUMP Basic Functionality Test.............................. ERROR #1\n"); + 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(tx_demo_host_change_function); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running DPUMP Basic Functionality Test.............................. ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running DPUMP Basic Functionality Test.............................. ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running DPUMP Basic Functionality Test.............................. ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = tx_demo_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = tx_demo_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running DPUMP Basic Functionality Test.............................. ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running DPUMP Basic Functionality Test.............................. ERROR #7\n"); + 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("Running DPUMP Basic Functionality Test.............................. ERROR #4\n"); + 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("Running DPUMP Basic Functionality Test.............................. ERROR #8\n"); + test_control_return(1); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running DPUMP Basic Functionality Test.............................. ERROR #9\n"); + test_control_return(1); + } +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG actual_length; +UCHAR current_char; +UX_HOST_CLASS *class; +UINT i; +#if 0 +UX_ENDPOINT *endpoint; +#endif + + + /* Inform user. */ + printf("Running DPUMP Basic Functionality Test.............................. "); + + /* Find the class container with unregistered name. */ + status = ux_host_stack_class_get(_ux_system_host_class_hid_name, &class); + + /* Should return error. */ + if (status != UX_HOST_CLASS_UNKNOWN) + { + + /* DPUMP basic test error. */ + printf("ERROR #10\n"); + test_control_return(1); + } + + /* Find the main data pump container. */ + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + /* DPUMP basic test error. */ + printf("ERROR #10\n"); + test_control_return(1); + } + + /* We get the first instance of the data pump device. */ + do + { + + status = ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump); + +#if defined(UX_HOST_STANDALONE) + ux_system_tasks_run(); +#endif + tx_thread_relinquish(); + + } while (status != UX_SUCCESS); + + /* We still need to wait for the data pump status to be live. */ + while (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + { + +#if defined(UX_HOST_STANDALONE) + ux_system_tasks_run(); +#endif + tx_thread_relinquish(); + + } + + /* At this point, the data pump class has been found. Now use the + data pump to send and receive data between the host and device. */ + + /* We start with a 'A' in buffer. */ + current_char = 'A'; + + /* Perform this test sequence 100 times. */ + for (i = 0; i < 100; i++) + { + + /* Increment thread counter. */ + thread_0_counter++; + + /* Initialize the write buffer. */ + _ux_utility_memory_set(host_out_buffer, current_char, UX_HOST_CLASS_DPUMP_PACKET_SIZE); + + /* Increment the character in buffer. */ + current_char++; + + /* Check for upper alphabet limit. */ + if (current_char > 'Z') + current_char = 'A'; + + /* Write to the host Data Pump Bulk out endpoint. */ + status = _ux_host_class_dpump_write (dpump, host_out_buffer, UX_HOST_CLASS_DPUMP_PACKET_SIZE, &actual_length); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + /* DPUMP basic test error. */ + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Verify that the status and the amount of data is correct. */ + if ((status != UX_SUCCESS) || actual_length != UX_HOST_CLASS_DPUMP_PACKET_SIZE) + { + + /* DPUMP basic test error. */ + printf("ERROR #12\n"); + test_control_return(1); + } + +#if defined(UX_HOST_STANDALONE) + /* Relinquish to other thread. */ + tx_thread_relinquish(); +#endif + + /* Read to the Data Pump Bulk out endpoint. */ + status = _ux_host_class_dpump_read (dpump, host_in_buffer, UX_HOST_CLASS_DPUMP_PACKET_SIZE, &actual_length); + + /* Verify that the status and the amount of data is correct. */ + if ((status != UX_SUCCESS) || actual_length != UX_HOST_CLASS_DPUMP_PACKET_SIZE) + { + + /* DPUMP basic test error. */ + printf("ERROR #13\n"); + test_control_return(1); + } + + /* Relinquish to other thread. */ + tx_thread_relinquish(); + } + +#if 0 + /* Test ux_host_stack_endpoint_reset with invalid endpoint number. */ + endpoint = dpump -> ux_host_class_dpump_interface -> ux_interface_first_endpoint; + endpoint -> ux_endpoint_descriptor.bEndpointAddress = 0xf; + expected_error = UX_TRANSFER_STALLED; + status = _ux_host_stack_endpoint_reset(endpoint); + + /* Check for error. */ + if (status == UX_SUCCESS) + { + + /* DPUMP basic test error. */ + printf("ERROR #14\n"); + test_control_return(1); + } +#endif + + expected_error = 0; + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* DPUMP error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + + +static void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG actual_length; +#if defined(UX_DEVICE_STANDALONE) +#define DPUMP_DEVICE_STATE_READ UX_STATE_STEP +#define DPUMP_DEVICE_STATE_WRITE UX_STATE_STEP + 1 +UINT dpump_device_state = UX_STATE_RESET; +#endif + + + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + + /* Run device tasks. */ + ux_system_tasks_run(); + + /* DPUMP echo state machine. */ + switch(dpump_device_state) + { + case UX_STATE_RESET: + if (dpump_slave != UX_NULL) + + /* Start reading. */ + dpump_device_state = DPUMP_DEVICE_STATE_READ; + break; + + case DPUMP_DEVICE_STATE_READ: + + /* Read from the device data pump. */ + if (dpump_slave == UX_NULL) + { + dpump_device_state = UX_STATE_RESET; + break; + } + status = ux_device_class_dpump_read_run(dpump_slave, slave_buffer, UX_HOST_CLASS_DPUMP_PACKET_SIZE, &actual_length); + + if (status < UX_STATE_NEXT) + { + printf("ERROR #%d: read status 0x%x\n", __LINE__, status); + error_counter ++; + return; + } + + if (status == UX_STATE_NEXT) + { + if (actual_length != UX_HOST_CLASS_DPUMP_PACKET_SIZE) + { + printf("ERROR #%d: read length %ld\n", __LINE__, actual_length); + error_counter ++; + return; + } + + dpump_device_state = DPUMP_DEVICE_STATE_WRITE; + } + break; + + case DPUMP_DEVICE_STATE_WRITE: + + /* Now write to the device data pump. */ + if (dpump_slave == UX_NULL) + { + dpump_device_state = UX_STATE_RESET; + break; + } + status = ux_device_class_dpump_write_run(dpump_slave, slave_buffer, UX_HOST_CLASS_DPUMP_PACKET_SIZE, &actual_length); + + if (status < UX_STATE_NEXT) + { + printf("ERROR #%d: write status 0x%x\n", __LINE__, status); + error_counter ++; + return; + } + + if (status == UX_STATE_NEXT) + dpump_device_state = DPUMP_DEVICE_STATE_READ; + break; + + default: + dpump_device_state = UX_STATE_RESET; + } + + /* Increment thread counter. */ + thread_1_counter++; + + /* Relinquish to other thread. */ + tx_thread_relinquish(); + +#else + /* Ensure the dpump class on the device is still alive. */ + while (dpump_slave != UX_NULL) + { + + /* Increment thread counter. */ + thread_1_counter++; + + /* Read from the device data pump. */ + status = _ux_device_class_dpump_read(dpump_slave, slave_buffer, UX_HOST_CLASS_DPUMP_PACKET_SIZE, &actual_length); + + /* Verify that the status and the amount of data is correct. */ + if ((status != UX_SUCCESS) || actual_length != UX_HOST_CLASS_DPUMP_PACKET_SIZE) + { + printf("ERROR #%d.%ld: read status 0x%x, length %ld\n", __LINE__, thread_1_counter, status, actual_length); + + /* Increment error counter. */ + error_counter++; + + /* Return from thread. */ + return; + } + + /* Now write to the device data pump. */ + status = _ux_device_class_dpump_write(dpump_slave, slave_buffer, UX_HOST_CLASS_DPUMP_PACKET_SIZE, &actual_length); + + /* Verify that the status and the amount of data is correct. */ + if ((status != UX_SUCCESS) || actual_length != UX_HOST_CLASS_DPUMP_PACKET_SIZE) + { + printf("ERROR #%d.%ld: write status 0x%x, length %ld\n", __LINE__, thread_1_counter, status, actual_length); + + /* Increment error counter. */ + error_counter++; + + /* Return from thread. */ + return; + } + } + + /* Relinquish to other thread. */ + tx_thread_relinquish(); +#endif + } +} + +static VOID tx_demo_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID tx_demo_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + +#if defined(UX_HOST_STANDALONE) +static UINT tx_demo_host_change_function(ULONG e, UX_HOST_CLASS *c, VOID *p) +{ + if (e == UX_STANDALONE_WAIT_BACKGROUND_TASK) + { + tx_thread_relinquish(); + } +} +#endif diff --git a/test/regression/usbx_hid_interrupt_endpoint_get_report_test.c b/test/regression/usbx_hid_interrupt_endpoint_get_report_test.c new file mode 100644 index 00000000..b68cb9df --- /dev/null +++ b/test/regression/usbx_hid_interrupt_endpoint_get_report_test.c @@ -0,0 +1,417 @@ +/* This file tests retrieving an input report via the interrupt endpoint. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR buffer[1024]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* @BUG_FIX_PENDING: ux_dcd_sim_slave_function.c doesn't support transfer aborts, which happen during device unregistration of a class. */ + if (error_code != UX_FUNCTION_NOT_SUPPORTED) + { + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_interrupt_endpoint_get_report_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running HID Interrupt Endpoint Get Report 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_ENDPOINT *interrupt_endpoint; +UX_TRANSFER *interrupt_endpoint_transfer_request; +ULONG report_id; +UX_SLAVE_CLASS_HID_EVENT hid_event; +UX_SLAVE_CLASS_HID *slave_hid; +UINT max_get_report_attempts = 5; + + + /* 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); + } + + /* Set report id. */ + report_id = 0; + + /* Get the slave hid. */ + slave_hid = _ux_system_slave -> ux_system_slave_device.ux_slave_device_first_interface -> ux_slave_interface_class_instance; + + /* Get the endpoint and transfer request. */ + interrupt_endpoint = hid -> ux_host_class_hid_interrupt_endpoint; + interrupt_endpoint_transfer_request = &interrupt_endpoint -> ux_endpoint_transfer_request; + + /* Kill the periodic thread so it doesn't get the report before us. */ + status = _ux_host_class_hid_periodic_report_stop(hid); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Add an event for the host to get. */ + + /* Set the length. */ + hid_event.ux_device_class_hid_event_length = 8; + + /* First byte is a modifier byte. */ + hid_event.ux_device_class_hid_event_buffer[0] = 0x01; + + /* Second byte is reserved. */ + hid_event.ux_device_class_hid_event_buffer[1] = 0x02; + + /* The 6 next bytes are keys. */ + hid_event.ux_device_class_hid_event_buffer[2] = 0x03; + hid_event.ux_device_class_hid_event_buffer[3] = 0x04; + hid_event.ux_device_class_hid_event_buffer[4] = 0x05; + hid_event.ux_device_class_hid_event_buffer[5] = 0x06; + hid_event.ux_device_class_hid_event_buffer[6] = 0x07; + hid_event.ux_device_class_hid_event_buffer[7] = 0x08; + + /* Add the event. */ + status = ux_device_class_hid_event_set(slave_hid, &hid_event); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Create a transfer request for the GET_REPORT request. We don't need to fill in all the members + because this is not a control transfer request. */ + interrupt_endpoint_transfer_request -> ux_transfer_request_data_pointer = buffer; + interrupt_endpoint_transfer_request -> ux_transfer_request_requested_length = hid_event.ux_device_class_hid_event_length; + + /* Wait for the device's interrupt thread to pick up the event and send it to us. */ + while (1) + { + + /* Send request to HCD layer. */ + status = ux_host_stack_transfer_request(interrupt_endpoint_transfer_request); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Did we receive it? */ + if (buffer[0] == 0x01 && + buffer[1] == 0x02 && + buffer[2] == 0x03 && + buffer[3] == 0x04 && + buffer[4] == 0x05 && + buffer[5] == 0x06 && + buffer[6] == 0x07 && + buffer[7] == 0x08) + break; + + max_get_report_attempts--; + if (max_get_report_attempts == 0) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + ux_utility_thread_sleep(10); + } + + /* 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_hid_keyboard_basic_test.c b/test/regression/usbx_hid_keyboard_basic_test.c new file mode 100644 index 00000000..a077d2ac --- /dev/null +++ b/test/regression/usbx_hid_keyboard_basic_test.c @@ -0,0 +1,582 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_host_class_hid.h" +#include "ux_host_class_hid_keyboard.h" +#include "ux_device_class_hid.h" +#include "ux_device_stack.h" +#include "ux_test_utility_sim.h" +#include "ux_test_hcd_sim_host.h" + +/* Define constants. */ +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE 2048 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) + +/* Define local/extern function prototypes. */ +static void demo_thread_entry(ULONG); +static UINT demo_thread_hid_callback(UX_SLAVE_CLASS_HID *, UX_SLAVE_CLASS_HID_EVENT *); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); +static void tx_demo_thread_slave_simulation_entry(ULONG); + + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static ULONG error_counter; +static TX_THREAD demo_thread; +static UX_HOST_CLASS *class_driver; +static ULONG class_driver_index; +static UX_HOST_CLASS_HID *hid; +static UX_HOST_CLASS_HID_CLIENT *hid_client; +static UX_HOST_CLASS_HID_KEYBOARD *keyboard; +static UINT status; +static UINT transfer_completed; +static ULONG requested_length; +static TX_SEMAPHORE demo_semaphore; + +static ULONG keyboard_char; +static ULONG keyboard_state; +static UCHAR keyboard_queue[1024]; +static ULONG keyboard_queue_index; + +static UX_SLAVE_CLASS_HID_PARAMETER hid_parameter; + +static UCHAR hid_keyboard_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + /* Modifier keys. */ + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + /* Padding. */ + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + /* LEDs. */ + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + /* Padding. */ + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + /* Keys. */ + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0, // END_COLLECTION + + 0xa1, 0x01, // COLLECTION (Application) + 0x19, 0x01, // USAGE_MINIMUM (1) + 0x29, 0x04, // USAGE_MAXIMUM (4) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x04, // REPORT_COUNT (4) + 0xb1, 0x02, // FEATURE (Data,Var,Abs) + 0x85, 0x02, // REPORT_ID (2) + 0x19, 0x05, // USAGE_MINIMUM (5) + 0x29, 0x07, // USAGE_MAXIMUM (7) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x03, // REPORT_COUNT (3) + 0xb1, 0x02, // FEATURE (Data,Var,Abs) + 0x85, 0x04, // REPORT_ID (4) + 0x09, 0x08, // USAGE (8) + 0x75, 0x10, // REPORT_SIZE (16) + 0x95, 0x01, // REPORT_COUNT (1) + 0xb1, 0x02, // FEATURE (Data,Var,Abs) + 0xc0, // END_COLLECTION + +}; +#define HID_KEYBOARD_REPORT_LENGTH (sizeof(hid_keyboard_report)/sizeof(hid_keyboard_report[0])) + + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 52 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00, + 0x00, + + /* HID descriptor */ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, HID_KEYBOARD_REPORT_LENGTH, + 0x00, + + /* Endpoint descriptor (Interrupt) */ + 0x07, 0x05, 0x82, 0x03, 0x08, 0x00, 0x08 + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 62 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* 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, HID_KEYBOARD_REPORT_LENGTH, + 0x00, + + /* 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 + }; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_keyboard_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + /* Inform user. */ + printf("Running HID Keyboard Basic Functionality 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 #1\n"); + test_control_return(1); + } + + /* Register the error callback. */ + ux_utility_error_callback_register(ux_test_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 #2\n"); + 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 #3\n"); + 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 #4\n"); + 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 #6\n"); + test_control_return(1); + } + + /* Initialize the hid class parameters for a keyboard. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_keyboard_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_KEYBOARD_REPORT_LENGTH; + hid_parameter.ux_device_class_hid_parameter_callback = 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 #7\n"); + test_control_return(1); + } + + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #8\n"); + 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 #5\n"); + 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 #9\n"); + test_control_return(1); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #10\n"); + test_control_return(1); + } + +} + +static UINT demo_class_hid_connect_wait(ULONG nb_loop) +{ + +UINT status; +UX_HOST_CLASS *class; + + /* Find the main HID container */ + status = ux_host_stack_class_get(_ux_system_host_class_hid_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* We get the first instance of the hid device */ + do + { + + status = ux_host_stack_class_instance_get(class, 0, (void **) &hid); + if (status == UX_SUCCESS && hid -> ux_host_class_hid_state == UX_HOST_CLASS_INSTANCE_LIVE) + return(UX_SUCCESS); + _ux_utility_delay_ms(10); + } while (nb_loop --); + + return(UX_ERROR); +} + +static UINT demo_class_hid_disconnect_wait(ULONG nb_loop) +{ + +UINT status; +UX_HOST_CLASS *class; + + /* Find the main HID container */ + status = ux_host_stack_class_get(_ux_system_host_class_hid_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* We get the first instance of the hid device */ + do { + + status = ux_host_stack_class_instance_get(class, 0, (void **) &hid); + if (status != UX_SUCCESS) + return(UX_SUCCESS); + _ux_utility_delay_ms(10); + } while(nb_loop --); + + return(UX_ERROR); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UINT max_hid_loop; + + + /* Initilize max loop value. */ + max_hid_loop = 16; + + /* Find the HID class */ + status = demo_class_hid_connect_wait(50); + if (status != UX_SUCCESS) + { + + /* HID Keyboard basic test error. */ + printf("ERROR #11\n"); + test_control_return(1); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Get the keyboard instance */ + keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)hid_client -> ux_host_class_hid_client_local_instance; + + /* Init the keyboard queue index. */ + keyboard_queue_index = 0; + + while (max_hid_loop--) + { + /* Get a key/state from the keyboard. */ + status = ux_host_class_hid_keyboard_key_get(keyboard, &keyboard_char, &keyboard_state); + + /* Check if there is something. */ + if (status == UX_SUCCESS) + { + /* We have a character in the queue. */ + keyboard_queue[keyboard_queue_index] = (UCHAR) keyboard_char; + + /* Can we accept more ? */ + if(keyboard_queue_index < 1024) + keyboard_queue_index++; + + } + + tx_thread_sleep(10); + } + + /* Simulate disconnect. */ + ux_test_hcd_sim_host_disconnect(); + demo_class_hid_disconnect_wait(5); + + /* 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); +} + +static void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + +UX_SLAVE_DEVICE *device; +UX_SLAVE_INTERFACE *interface; +UX_SLAVE_CLASS_HID *hid; +UX_SLAVE_CLASS_HID_EVENT hid_event; +UCHAR key; + + /* Get the pointer to the device. */ + device = &_ux_system_slave -> ux_system_slave_device; + + /* Set the first key to 'a' which is 04. */ + key = 0x04; + + /* reset the HID event structure. */ + ux_utility_memory_set(&hid_event, 0, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + + while(1) + { + + /* Is the device configured ? */ + while (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED) + { +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); + tx_thread_relinquish(); +#else + /* Then wait. */ + tx_thread_sleep(10); +#endif + } + + /* Until the device stays configured. */ + while (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED) + { + + /* Get the interface. We use the first interface, this is a simple device. */ + interface = device -> ux_slave_device_first_interface; + + /* Form that interface, derive the HID owner. */ + hid = interface -> ux_slave_interface_class_instance; + +#if defined(UX_DEVICE_STANDALONE) + ULONG tick_to_wait = UX_MS_TO_TICK(2000); + ULONG tick_start = _ux_utility_time_get(); + while(_ux_utility_time_elapsed(tick_start, _ux_utility_time_get()) < tick_to_wait) + { + ux_system_tasks_run(); + tx_thread_relinquish(); + } +#else + /* Wait for 2 seconds. */ + ux_utility_thread_sleep(UX_MS_TO_TICK(2000)); +#endif + + /* Then insert a key into the keyboard event. Length is fixed to 8. */ + hid_event.ux_device_class_hid_event_length = 8; + + /* First byte is a modifier byte. */ + hid_event.ux_device_class_hid_event_buffer[0] = 0; + + /* Second byte is reserved. */ + hid_event.ux_device_class_hid_event_buffer[1] = 0; + + /* The 6 next bytes are keys. We only have one key here. */ + hid_event.ux_device_class_hid_event_buffer[2] = key; + + /* Set the keyboard event. */ + ux_device_class_hid_event_set(hid, &hid_event); + + /* Next event has the key depressed. */ + hid_event.ux_device_class_hid_event_buffer[2] = 0; + + /* Length is fixed to 8. */ + hid_event.ux_device_class_hid_event_length = 8; + + /* Set the keyboard event. */ + ux_device_class_hid_event_set(hid, &hid_event); + + /* Are we at the end of alphabet ? */ + if (key != (0x04 + 26)) + + /* Next key. */ + key++; + + else + + /* Start over again. */ + key = 0x04; + + } + } +} + diff --git a/test/regression/usbx_hid_keyboard_extraction_test.c b/test/regression/usbx_hid_keyboard_extraction_test.c new file mode 100644 index 00000000..5972faee --- /dev/null +++ b/test/regression/usbx_hid_keyboard_extraction_test.c @@ -0,0 +1,378 @@ +/* This test concentrates on keyboard device removal. */ + +#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) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + /* Add a feature report to hit some code in _ux_host_class_hid_instance_clean(). */ + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0xb1, 0x00, // FEATURE (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_keyboard_extraction_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 Device Removal Keyboard 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_system_host_change_function); + 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\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 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 UINT ux_hcd_sim_host_entry_filter_device_extraction_test(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; + + switch(function) + { + case UX_HCD_GET_PORT_STATUS: + + /* No device on this port. */ + status = 0; + + /* This is a Full speed device. */ + status |= UX_PS_DS_FS; + + break; + + + default: + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + break; + } + + return status; +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_KEYBOARD *keyboard; +UX_HCD *hcd; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the keyboard instance */ + keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)hid_client -> ux_host_class_hid_client_local_instance; + + hcd = UX_DEVICE_HCD_GET(hid -> ux_host_class_hid_device); + + /* Change the HCD entry function to our filter function. */ + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter_device_extraction_test; + + /* Signal port activity to the enum thread. */ + hcd -> ux_hcd_root_hub_signal[0] = 1; + + /* Signal enum thread. */ + _ux_utility_semaphore_put(&_ux_system_host -> ux_system_host_enum_semaphore); + + /* Wait for hid class to shut down. */ + while(hid -> ux_host_class_hid_state == UX_HOST_CLASS_INSTANCE_LIVE) + tx_thread_sleep(10); + + /* 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_hid_keyboard_extraction_test2.c b/test/regression/usbx_hid_keyboard_extraction_test2.c new file mode 100644 index 00000000..66fb56de --- /dev/null +++ b/test/regression/usbx_hid_keyboard_extraction_test2.c @@ -0,0 +1,371 @@ +/* This test concentrates on keyboard device removal. + This is similar to the first extraction test, except there is no ux_system_host_change_function. + This allows us to hit the following false condition in _ux_host_class_hid_keyboard_deactivate: + if (_ux_system_host -> ux_system_host_change_function != UX_NULL) */ + +#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) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + /* Add a feature report to hit some code in _ux_host_class_hid_instance_clean(). */ + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0xb1, 0x00, // FEATURE (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_keyboard_extraction_test2_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 Device Removal Keyboard Test2........................... "); + + /* 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(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\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 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 UINT ux_hcd_sim_host_entry_filter_device_extraction_test(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; + + switch(function) + { + case UX_HCD_GET_PORT_STATUS: + + /* No device on this port. */ + status = 0; + + /* This is a Full speed device. */ + status |= UX_PS_DS_FS; + + break; + + + default: + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + break; + } + + return status; +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HCD *hcd; + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + hcd = UX_DEVICE_HCD_GET(hid -> ux_host_class_hid_device); + + /* Change the HCD entry function to our filter function. */ + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter_device_extraction_test; + + /* Signal port activity to the enum thread. */ + hcd -> ux_hcd_root_hub_signal[0] = 1; + + /* Signal enum thread. */ + _ux_utility_semaphore_put(&_ux_system_host -> ux_system_host_enum_semaphore); + + /* Wait for hid class to shut down. */ + while(hid -> ux_host_class_hid_state == UX_HOST_CLASS_INSTANCE_LIVE) + tx_thread_sleep(10); + + /* 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_hid_keyboard_key_get_test.c b/test/regression/usbx_hid_keyboard_key_get_test.c new file mode 100644 index 00000000..92afcba0 --- /dev/null +++ b/test/regression/usbx_hid_keyboard_key_get_test.c @@ -0,0 +1,558 @@ +/* This test concentrates on the ux_host_class_hid_keyboard_key_get API. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_host_class_hid.h" +#include "ux_host_class_hid_keyboard.h" +#include "ux_device_class_hid.h" +#include "ux_device_stack.h" + +/* Define constants. */ +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE 2048 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) + +/* Define local/extern function prototypes. */ +static void demo_thread_entry(ULONG); +static UINT demo_thread_hid_callback(UX_SLAVE_CLASS_HID *, UX_SLAVE_CLASS_HID_EVENT *); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); +static void tx_demo_thread_slave_simulation_entry(ULONG); + + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static ULONG error_counter; +static TX_THREAD demo_thread; +static UX_HOST_CLASS *class_driver; +static ULONG class_driver_index; +static UX_HOST_CLASS_HID *hid; +static UX_HOST_CLASS_HID_CLIENT *hid_client; +static UX_HOST_CLASS_HID_KEYBOARD *keyboard; +static UINT status; +static UINT transfer_completed; +static ULONG requested_length; +static TX_SEMAPHORE demo_semaphore; + +static ULONG keyboard_char; +static ULONG keyboard_state; +static UCHAR keyboard_queue[1024]; +static ULONG keyboard_queue_index; + +static UX_SLAVE_CLASS_HID_PARAMETER hid_parameter; + + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 52 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00, + 0x00, + + /* HID descriptor */ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, 0x3f, + 0x00, + + /* Endpoint descriptor (Interrupt) */ + 0x07, 0x05, 0x82, 0x03, 0x08, 0x00, 0x08 + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 62 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* 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, 0x3f, + 0x00, + + /* 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 + }; + +#define HID_KEYBOARD_REPORT_LENGTH 63 +static UCHAR hid_keyboard_report[HID_KEYBOARD_REPORT_LENGTH] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; + + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* @BUG_FIX_PENDING: ux_dcd_sim_slave_function.c doesn't support transfer aborts, which happen during device unregistration of a class. */ + if (error_code != UX_FUNCTION_NOT_SUPPORTED) + { + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_keyboard_key_get_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + /* Inform user. */ + printf("Running HID Keyboard Key Get 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\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 on line %d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the hid class parameters for a keyboard. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_keyboard_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_KEYBOARD_REPORT_LENGTH; + hid_parameter.ux_device_class_hid_parameter_callback = 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); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, 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 UINT demo_class_hid_get(void) +{ + +UINT status; +UX_HOST_CLASS *class; + + /* Find the main HID container */ + status = ux_host_stack_class_get(_ux_system_host_class_hid_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* We get the first instance of the hid device */ + do + { + + status = ux_host_stack_class_instance_get(class, 0, (void **) &hid); + tx_thread_sleep(10); + } while (status != UX_SUCCESS); + + /* We still need to wait for the hid status to be live */ + while (hid -> ux_host_class_hid_state != UX_HOST_CLASS_INSTANCE_LIVE) + tx_thread_sleep(10); + + return(UX_SUCCESS); +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UINT max_hid_loop; +ALIGN_TYPE tmp; +ULONG key, state; + + /* Initilize max loop value. Make sure we wrap. */ + max_hid_loop = 2*UX_HOST_CLASS_HID_KEYBOARD_USAGE_ARRAY_LENGTH; + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + /* HID Keyboard basic test error. */ + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the keyboard instance */ + keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)hid_client -> ux_host_class_hid_client_local_instance; + + /**************************************************/ + /** Test case: _ux_host_stack_class_instance_verify() fails. **/ + /**************************************************/ + + /* Set the keyboard's class container to NULL. */ + tmp = (ALIGN_TYPE)keyboard -> ux_host_class_hid_keyboard_hid; + keyboard -> ux_host_class_hid_keyboard_hid = UX_NULL; + + if(ux_host_class_hid_keyboard_key_get(keyboard, &key, &state) != UX_HOST_CLASS_INSTANCE_UNKNOWN) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Restore state for next test. */ + keyboard -> ux_host_class_hid_keyboard_hid = (UX_HOST_CLASS_HID *)tmp; + + /**************************************************/ + /** Test case: if ((array_tail+2) >= array_end) (wraps) **/ + /**************************************************/ + + /* Init the keyboard queue index. */ + keyboard_queue_index = 0; + + while (max_hid_loop--) + { + /* Get a key/state from the keyboard. */ + status = ux_host_class_hid_keyboard_key_get(keyboard, &keyboard_char, &keyboard_state); + + /* Check if there is something. */ + if (status == UX_SUCCESS) + { + /* We have a character in the queue. */ + keyboard_queue[keyboard_queue_index] = (UCHAR) keyboard_char; + + /* Can we accept more ? */ + if(keyboard_queue_index < 1024) + keyboard_queue_index++; + + } + + tx_thread_sleep(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); +} + +static void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + +UX_SLAVE_DEVICE *device; +UX_SLAVE_INTERFACE *interface; +UX_SLAVE_CLASS_HID *hid; +UX_SLAVE_CLASS_HID_EVENT hid_event; +UCHAR key; + + /* Get the pointer to the device. */ + device = &_ux_system_slave -> ux_system_slave_device; + + /* Set the first key to 'a' which is 04. */ + key = 0x04; + + /* reset the HID event structure. */ + ux_utility_memory_set(&hid_event, 0, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + + while(1) + { + + /* Is the device configured ? */ + while (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED) + + /* Then wait. */ + tx_thread_sleep(10); + + /* Until the device stays configured. */ + while (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED) + { + + /* Get the interface. We use the first interface, this is a simple device. */ + interface = device -> ux_slave_device_first_interface; + + /* Form that interface, derive the HID owner. */ + hid = interface -> ux_slave_interface_class_instance; + + /* Wait for 2 seconds. */ + ux_utility_thread_sleep(2); + + /* Then insert a key into the keyboard event. Length is fixed to 8. */ + hid_event.ux_device_class_hid_event_length = 8; + + /* First byte is a modifier byte. */ + hid_event.ux_device_class_hid_event_buffer[0] = 0; + + /* Second byte is reserved. */ + hid_event.ux_device_class_hid_event_buffer[1] = 0; + + /* The 6 next bytes are keys. We only have one key here. */ + hid_event.ux_device_class_hid_event_buffer[2] = key; + + /* Set the keyboard event. */ + ux_device_class_hid_event_set(hid, &hid_event); + + /* Next event has the key depressed. */ + hid_event.ux_device_class_hid_event_buffer[2] = 0; + + /* Length is fixed to 8. */ + hid_event.ux_device_class_hid_event_length = 8; + + /* Set the keyboard event. */ + ux_device_class_hid_event_set(hid, &hid_event); + + /* Are we at the end of alphabet ? */ + if (key != (0x04 + 26)) + + /* Next key. */ + key++; + + else + + /* Start over again. */ + key = 0x04; + + } + } +} + diff --git a/test/regression/usbx_hid_keyboard_key_test.c b/test/regression/usbx_hid_keyboard_key_test.c new file mode 100644 index 00000000..64d93ed0 --- /dev/null +++ b/test/regression/usbx_hid_keyboard_key_test.c @@ -0,0 +1,1194 @@ +/* This file tests that the host correctly receives the keys the device sends to it. */ + +#include "usbx_test_common_hid.h" + +#include "ux_host_class_hid_keyboard.h" + +#define HOST_WAIT_TIME 1 +#define SLAVE_WAIT_TIME (6*HOST_WAIT_TIME) + +#ifndef UX_HID_KEYBOARD_PHANTOM_STATE +#define UX_HID_KEYBOARD_PHANTOM_STATE 0x01 +#endif +#define KEY_START (UX_HID_KEYBOARD_PHANTOM_STATE+1) + +static UCHAR ux_host_class_hid_keyboard_regular_array[] = +{ + 0,0,0,0, + 'a','b','c','d','e','f','g','h','i','j','k','l','m','n', + 'o','p','q','r','s','t','u','v','w','x','y','z', + '1','2','3','4','5','6','7','8','9','0', + 0x0d,0x1b,0x08,0x07,0x20,'-','=','[',']', + '\\','#',';',0x27,'`',',','.','/',0xf0, + 0xbb,0xbc,0xbd,0xbe,0xbf,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6, + 0x00,0xf1,0x00,0xd2,0xc7,0xc9,0xd3,0xcf,0xd1,0xcd,0xcb,0xd0,0xc8,0xf2, + '/','*','-','+', + 0x0d,'1','2','3','4','5','6','7','8','9','0','.','\\',0x00,0x00,'=', + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +static UCHAR ux_host_class_hid_keyboard_capslock_array[] = +{ + 0,0,0,0, + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z', + '1','2','3','4','5','6','7','8','9','0', + 0x0d,0x1b,0x08,0x07,0x20,'-','=','[',']', + '\\','#',';',0x27,'`',',','.','/',0xf0, + 0xbb,0xbc,0xbd,0xbe,0xbf,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6, + 0x00,0xf1,0x00,0xd2,0xc7,0xc9,0xd3,0xcf,0xd1,0xcd,0xcb,0xd0,0xc8,0xf2, + '/','*','-','+', + 0x0d,'1','2','3','4','5','6','7','8','9','0','.','\\',0x00,0x00,'=', + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +static UCHAR ux_host_class_hid_keyboard_shift_array[] = +{ + 0,0,0,0, + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N', + 'O','P','Q','R','S','T','U','V','W','X','Y','Z', + '!','@','#','$','%','^','&','*','(',')', + 0x0d,0x1b,0x08,0x07,0x20,'_','+','{','}', + '|','~',':','"','~','<','>','?',0xf0, + 0xbb,0xbc,0xbd,0xbe,0xbf,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6, + 0x00,0xf1,0x00,0xd2,0xc7,0xc9,0xd3,0xcf,0xd1,0xcd,0xcb,0xd0,0xc8,0xf2, + '/','*','-','+', + 0x0d,'1','2','3','4','5','6','7','8','9','0','.','\\',0x00,0x00,'=', + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +static UCHAR ux_host_class_hid_keyboard_shift_capslock_array[] = +{ + 0,0,0,0, + 'a','b','c','d','e','f','g','h','i','j', 'k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z', + '!','@','#','$','%','^','&','*','(',')', + 0x0d,0x1b,0x08,0x07,0x20,'_','+','{','}', + '|','~',':','"','~','<','>','?',0xf0, + 0xbb,0xbc,0xbd,0xbe,0xbf,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6, + 0x00,0xf1,0x00,0xd2,0xc7,0xc9,0xd3,0xcf,0xd1,0xcd,0xcb,0xd0,0xc8,0xf2, + '/','*','-','+', + 0x0d,'1','2','3','4','5','6','7','8','9','0','.','\\',0x00,0x00,'=', + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +static UCHAR ux_host_class_hid_keyboard_numlock_on_array[] = +{ + '/','*','-','+', + 0x0d,'1','2','3','4','5','6','7','8','9','0','.','\\',0x00,0x00,'=', +}; + +static UCHAR ux_host_class_hid_keyboard_numlock_off_array[] = +{ + '/','*','-','+', + 0x0d,0xcf,0xd0,0xd1,0xcb,'5',0xcd,0xc7,0xc8,0xc9,0xd2,0xd3,'\\',0x00,0x00,'=', +}; + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static volatile ULONG test_host_phase = 0; +static volatile ULONG test_slave_phase = 0; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, ARRAY_COUNT(ux_host_class_hid_keyboard_regular_array) + 1, // LOGICAL_MAXIMUM () + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, ARRAY_COUNT(ux_host_class_hid_keyboard_regular_array) + 1, // USAGE_MAXIMUM () + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* @BUG_FIX_PENDING: ux_dcd_sim_slave_function.c doesn't support transfer aborts, which happen during device unregistration of a class. */ + if (error_code != UX_FUNCTION_NOT_SUPPORTED && + error_code != UX_BUFFER_OVERFLOW /* Key queue overflow! */) + { + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: 0x%x\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_keyboard_key_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running HID Keyboard Key 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, error code: 0x%x\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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: 0x%x\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, error code: 0x%x\n", __LINE__, status); + 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; + + /* Initialize 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running HID Keyboard Basic Functionality Test....................... ERROR #10\n"); + test_control_return(1); + } + +} + + +static UINT _wait_key(UX_HOST_CLASS_HID_KEYBOARD *keyboard, ULONG *keyboard_key, ULONG *keyboard_state) +{ + +UINT status; +UINT i; + + + for(i = 0; i < 200; i ++) + { + status = ux_host_class_hid_keyboard_key_get(keyboard, keyboard_key, keyboard_state); + if (status == UX_SUCCESS) + { + // printf("Key: %lx,%lx\n", *keyboard_key, *keyboard_state); + +#if defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE_REPORT_LOCK_KEYS) || defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE_REPORT_MODIFIER_KEYS) + if (*keyboard_state & UX_HID_KEYBOARD_STATE_FUNCTION) + continue; +#endif + +#if !defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE_REPORT_KEY_DOWN_ONLY) + if (*keyboard_state & UX_HID_KEYBOARD_STATE_KEY_UP) + continue; +#endif + return UX_SUCCESS; + } + _ux_utility_delay_ms(1); + } + return UX_ERROR; +} + + +static UINT tx_demo_phase_sync(ULONG in_host, ULONG nb_loop, ULONG tick_in_loop) +{ + +ULONG i; + + + for (i = 0; i < nb_loop; i ++) + { + if (in_host) + { + if (test_host_phase <= test_slave_phase) + return UX_SUCCESS; + } + else + { + if (test_slave_phase <= test_host_phase) + return UX_SUCCESS; + } + _ux_utility_thread_sleep(tick_in_loop); + } + return UX_ERROR; +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_KEYBOARD *keyboard; +ULONG keyboard_key; +ULONG keyboard_state; +ULONG expected_key; +ULONG num_keypad_keys; +ULONG i, n; +UCHAR *test_array[4] = { + ux_host_class_hid_keyboard_regular_array, + ux_host_class_hid_keyboard_shift_array, + ux_host_class_hid_keyboard_capslock_array, + ux_host_class_hid_keyboard_shift_capslock_array +}; + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the keyboard instance */ + keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)hid_client -> ux_host_class_hid_client_local_instance; + + /**************************************************************************/ + /** 1. Test receiving maximum keys at once. **/ + test_host_phase ++; + // printf("###### host step: %ld ######\n", test_host_phase); + + for (i = 4; i < 10; i++) + { + + status = _wait_key(keyboard, &keyboard_key, &keyboard_state); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + expected_key = ux_host_class_hid_keyboard_regular_array[i]; + + if (keyboard_key != expected_key) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + } + + /**************************************************************************/ + /** 2. Test keys. **/ + test_host_phase ++; + // printf("###### host step: %ld ######\n", test_host_phase); + + for (n = 0; n < 4; n ++) + { + for (i = KEY_START; i < ARRAY_COUNT(ux_host_class_hid_keyboard_regular_array); i++) + { + + /* These keys change the keyboard state and are not retrievable. */ + if (i == UX_HID_LED_KEY_CAPS_LOCK || + i == UX_HID_LED_KEY_NUM_LOCK || + i == UX_HID_LED_KEY_SCROLL_LOCK) + continue; + + status = _wait_key(keyboard, &keyboard_key, &keyboard_state); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + // printf("test key: %lx @ %lx\n", keyboard_key, keyboard_state); + expected_key = test_array[n][i]; + + if (keyboard_key != expected_key) + { + + printf("Error on line %d, test %ld.%ld, state 0x%lx, key 0x%lx <> 0x%lx\n", __LINE__, n, i, keyboard_state, expected_key, keyboard_key); + test_control_return(1); + } + } + } + + /**************************************************************************/ + /** 3. Test number pad keys. **/ + test_host_phase ++; + // printf("###### host step: %ld ######\n", test_host_phase); + + /** Test numlock on keys. **/ + + num_keypad_keys = (UX_HID_KEYBOARD_KEYS_KEYPAD_UPPER_RANGE - UX_HID_KEYBOARD_KEYS_KEYPAD_LOWER_RANGE) + 1; + + for (i = 0; i < ARRAY_COUNT(ux_host_class_hid_keyboard_numlock_on_array); i++) + { + + status = _wait_key(keyboard, &keyboard_key, &keyboard_state); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + expected_key = ux_host_class_hid_keyboard_numlock_on_array[i]; + + if (keyboard_key != ux_host_class_hid_keyboard_numlock_on_array[i]) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + } + + /** Test numlock off keys. **/ + + for (i = 0; i < ARRAY_COUNT(ux_host_class_hid_keyboard_numlock_off_array); i++) + { + + status = _wait_key(keyboard, &keyboard_key, &keyboard_state); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + // printf("test key: %lx @ %lx\n", keyboard_key, keyboard_state); + + expected_key = ux_host_class_hid_keyboard_numlock_off_array[i]; + + if (keyboard_key != ux_host_class_hid_keyboard_numlock_off_array[i]) + { + + printf("Error on line %d, test %ld, state 0x%lx, key 0x%lx <> 0x%lx\n", __LINE__, i, keyboard_state, expected_key, keyboard_key); + test_control_return(1); + } + } + + /**************************************************************************/ + /** 4. Test states. **/ + test_host_phase ++; + // printf("###### host step: %ld ######\n", test_host_phase); + + /** Test keyboard on states. **/ + + status = _wait_key(keyboard, &keyboard_key, &keyboard_state); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Ensure every bit is enabled (represented by 0xff07 (search for "Define HID Keyboard States." in ux_host_class_hid_keyboard.h)). */ + if ((keyboard_state & 0xFFFF) != 0xff07) + { + + printf("Error on line %d, test %ld.%ld, state 0x%lx\n", __LINE__, n, i, keyboard_state); + test_control_return(1); + } + + /** Test keyboard off states. **/ + + status = _wait_key(keyboard, &keyboard_key, &keyboard_state); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Ensure every bit is disabled. */ + if ((keyboard_state & 0xFFFF) != 0x0000) + { + + printf("Error on line %d, test %ld.%ld, state 0x%lx\n", __LINE__, n, i, keyboard_state); + test_control_return(1); + } + + /**************************************************************************/ + /** 5. Test raw key. **/ + + /* Disable decode. */ + ux_host_class_hid_keyboard_ioctl(keyboard, UX_HID_KEYBOARD_IOCTL_DISABLE_KEYS_DECODE, UX_NULL); + test_host_phase ++; + // printf("###### host step: %ld ######\n", test_host_phase); + + for (i = KEY_START; i < ARRAY_COUNT(ux_host_class_hid_keyboard_regular_array); i++) + { +#if 0 + /* These keys change the keyboard state and are not retrievable. */ + if (i == UX_HID_LED_KEY_CAPS_LOCK || + i == UX_HID_LED_KEY_NUM_LOCK || + i == UX_HID_LED_KEY_SCROLL_LOCK) + continue; +#endif + + status = _wait_key(keyboard, &keyboard_key, &keyboard_state); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + expected_key = i; + + if (keyboard_key != expected_key) + { + + printf("Error on line %d, test %ld, 0x%lx <> 0x%lx\n", __LINE__, i, expected_key, keyboard_key); + // test_control_return(1); + } + } + + /**************************************************************************/ + /** 6. Test invalid key. **/ + + /* Enable decode. */ + ux_host_class_hid_keyboard_ioctl(keyboard, UX_HID_KEYBOARD_IOCTL_ENABLE_KEYS_DECODE, UX_NULL); + test_host_phase ++; + // printf("###### host step: %ld ######\n", test_host_phase); + + /* Wait slave execute. */ + if (tx_demo_phase_sync(UX_TRUE, 10, SLAVE_WAIT_TIME) != UX_SUCCESS) + { + printf("Error in line %d, thread phase error %ld <> %ld!\n", __LINE__, test_host_phase, test_slave_phase); + test_control_return(1); + } + + /* Wait a invalid key (discarded). */ + ux_utility_thread_sleep(HOST_WAIT_TIME * 2); + + /**************************************************************************/ + /** 7. Test key array overflow. **/ + + /* Flush keys. */ + do { + status = ux_host_class_hid_keyboard_key_get(keyboard, &keyboard_key, &keyboard_state); + } while(status == UX_SUCCESS); + + /* No read, test array full. */ + ux_host_class_hid_keyboard_ioctl(keyboard, UX_HID_KEYBOARD_IOCTL_DISABLE_KEYS_DECODE, UX_NULL); + test_host_phase ++; + // printf("###### host step: %ld ######\n", test_host_phase); + + /* Wait until test done. */ + while(test_slave_phase != 0) + _ux_utility_delay_ms(10); + + /* There are keys remain in key array. */ + for (i = 0; i < UX_HOST_CLASS_HID_KEYBOARD_USAGE_ARRAY_LENGTH / 2 - 1; i ++) + { + + status = ux_host_class_hid_keyboard_key_get(keyboard, &keyboard_key, &keyboard_state); + if(status != UX_SUCCESS) + { + printf("Error on line %d.%ld, error code 0x%x\n", __LINE__, i, status); + test_control_return(1); + } + if (keyboard_key != 5) + { + printf("Error on line %d, key 0x%lx,0x%lx @ %ld\n", __LINE__, keyboard_key, keyboard_state, i); + test_control_return(1); + } + } + status = ux_host_class_hid_keyboard_key_get(keyboard, &keyboard_key, &keyboard_state); + if(status == UX_SUCCESS) + { + printf("Error on line %d, error code 0x%x\n", __LINE__, status); + } + + /* 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); +} + +static void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + +UINT status; +UX_SLAVE_DEVICE *device; +UX_SLAVE_INTERFACE *interface; +UX_SLAVE_CLASS_HID *hid; +UX_SLAVE_CLASS_HID_EVENT hid_event; +UINT i, n; +UCHAR state_modifier[2] = {0, (0x01 << 1)}; + + /* Get the pointer to the device. */ + device = &_ux_system_slave -> ux_system_slave_device; + + /* reset the HID event structure. */ + ux_utility_memory_set(&hid_event, 0, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + + /* Is the device configured ? */ + while (device->ux_slave_device_state != UX_DEVICE_CONFIGURED) + + /* Then wait. */ + tx_thread_sleep(10); + + /* Get the interface. We use the first interface, this is a simple device. */ + interface = device->ux_slave_device_first_interface; + + /* Form that interface, derive the HID owner. */ + hid = interface->ux_slave_interface_class_instance; + + /**************************************************************************/ + /** 1. Test receiving maximum keys at once. **/ + test_slave_phase ++; + // printf("****** slave step: %ld ******\n", test_slave_phase); + + hid_event.ux_device_class_hid_event_length = 8; + + /* Modification byte. */ + hid_event.ux_device_class_hid_event_buffer[0] = 0; + + /* Reserved byte. */ + hid_event.ux_device_class_hid_event_buffer[1] = 0; + + /* Set keys. */ + for (i = 0; i < 6; i++) + hid_event.ux_device_class_hid_event_buffer[2 + i] = 4 + i; + + ux_device_class_hid_event_set(hid, &hid_event); +#if 0 + /* Release keys. */ + for (i = 0; i < 6; i++) + hid_event.ux_device_class_hid_event_buffer[2 + i] = 0; + + ux_device_class_hid_event_set(hid, &hid_event); +#endif + ux_utility_thread_sleep(SLAVE_WAIT_TIME); + + /* Reset for next test. */ + ux_utility_memory_set(&hid_event, 0, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + + /**************************************************************************/ + /** 2. Test keys. **/ + test_slave_phase ++; + // printf("****** slave step: %ld ******\n", test_slave_phase); + + /** Test regular keys with/without SHIFT. Only go up to maximum value specified by report descriptor. **/ + + for (n = 0; n < 2; n ++) + { + + for (i = KEY_START; i < ARRAY_COUNT(ux_host_class_hid_keyboard_regular_array); i++) + { + + /* These keys change the keyboard state and are not retrievable. */ + if (i == UX_HID_LED_KEY_CAPS_LOCK || + i == UX_HID_LED_KEY_NUM_LOCK || + i == UX_HID_LED_KEY_SCROLL_LOCK) + continue; + + hid_event.ux_device_class_hid_event_length = 8; + + /* Modification byte. */ + hid_event.ux_device_class_hid_event_buffer[0] = state_modifier[n]; + + /* Reserved byte. */ + hid_event.ux_device_class_hid_event_buffer[1] = 0; + + /* Key byte. */ + hid_event.ux_device_class_hid_event_buffer[2] = i; + + status = ux_device_class_hid_event_set(hid, &hid_event); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + ux_utility_thread_sleep(SLAVE_WAIT_TIME); + } + + } + ux_utility_thread_sleep(SLAVE_WAIT_TIME); + + /** Test CAPS LOCK with/without SHIFT keys. Only go up to maximum value specified by report descriptor. **/ + + /* Turn CAPS LOCK on. */ + hid_event.ux_device_class_hid_event_length = 8; + hid_event.ux_device_class_hid_event_buffer[0] = 0; + hid_event.ux_device_class_hid_event_buffer[1] = 0; + hid_event.ux_device_class_hid_event_buffer[2] = UX_HID_LED_KEY_CAPS_LOCK; + status = ux_device_class_hid_event_set(hid, &hid_event); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + ux_utility_thread_sleep(SLAVE_WAIT_TIME); + + for (n = 0; n < 2; n ++) + { + + for (i = KEY_START; i < ARRAY_COUNT(ux_host_class_hid_keyboard_regular_array); i++) + { + + /* These keys change the keyboard state and are not retrievable. */ + if (i == UX_HID_LED_KEY_CAPS_LOCK || + i == UX_HID_LED_KEY_NUM_LOCK || + i == UX_HID_LED_KEY_SCROLL_LOCK) + continue; + + hid_event.ux_device_class_hid_event_length = 8; + + /* Modification byte. */ + hid_event.ux_device_class_hid_event_buffer[0] = state_modifier[n]; + + /* Reserved byte. */ + hid_event.ux_device_class_hid_event_buffer[1] = 0; + + /* Key byte. */ + hid_event.ux_device_class_hid_event_buffer[2] = i; + + status = ux_device_class_hid_event_set(hid, &hid_event); + if (status != UX_SUCCESS) + { + + /* ERROR */ + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + ux_utility_thread_sleep(SLAVE_WAIT_TIME); + } + } + ux_utility_thread_sleep(SLAVE_WAIT_TIME); + + /* Turn CAPS LOCK off. */ + hid_event.ux_device_class_hid_event_length = 8; + hid_event.ux_device_class_hid_event_buffer[0] = 0; + hid_event.ux_device_class_hid_event_buffer[1] = 0; + hid_event.ux_device_class_hid_event_buffer[2] = UX_HID_LED_KEY_CAPS_LOCK; + status = ux_device_class_hid_event_set(hid, &hid_event); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + ux_utility_thread_sleep(SLAVE_WAIT_TIME); + + /**************************************************************************/ + /** 3. Test num pad keys. **/ + test_slave_phase ++; + // printf("****** slave step: %ld ******\n", test_slave_phase); + + /** Test NUM LOCK on keys. NUM LOCK is on by default. **/ + + for (i = UX_HID_KEYBOARD_KEYS_KEYPAD_LOWER_RANGE; i <= UX_HID_KEYBOARD_KEYS_KEYPAD_UPPER_RANGE; i++) + { + + hid_event.ux_device_class_hid_event_length = 8; + + /* Modification byte. */ + hid_event.ux_device_class_hid_event_buffer[0] = 0; + + /* Reserved byte. */ + hid_event.ux_device_class_hid_event_buffer[1] = 0; + + /* Key byte. */ + hid_event.ux_device_class_hid_event_buffer[2] = i; + + status = ux_device_class_hid_event_set(hid, &hid_event); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + ux_utility_thread_sleep(SLAVE_WAIT_TIME); + } + ux_utility_thread_sleep(SLAVE_WAIT_TIME); + + /** Test NUM LOCK off keys. **/ + + /* Turn NUM LOCK off. */ + hid_event.ux_device_class_hid_event_length = 8; + hid_event.ux_device_class_hid_event_buffer[0] = 0; + hid_event.ux_device_class_hid_event_buffer[1] = 0; + hid_event.ux_device_class_hid_event_buffer[2] = UX_HID_LED_KEY_NUM_LOCK; + ux_device_class_hid_event_set(hid, &hid_event); + + ux_utility_thread_sleep(SLAVE_WAIT_TIME); + + for (i = UX_HID_KEYBOARD_KEYS_KEYPAD_LOWER_RANGE; i <= UX_HID_KEYBOARD_KEYS_KEYPAD_UPPER_RANGE; i++) + { + + hid_event.ux_device_class_hid_event_length = 8; + + /* Modification byte. */ + hid_event.ux_device_class_hid_event_buffer[0] = 0; + + /* Reserved byte. */ + hid_event.ux_device_class_hid_event_buffer[1] = 0; + + /* Key byte. */ + hid_event.ux_device_class_hid_event_buffer[2] = i; + + status = ux_device_class_hid_event_set(hid, &hid_event); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + ux_utility_thread_sleep(SLAVE_WAIT_TIME); + } + ux_utility_thread_sleep(SLAVE_WAIT_TIME); + + /* Turn NUM LOCK on. */ + hid_event.ux_device_class_hid_event_length = 8; + hid_event.ux_device_class_hid_event_buffer[0] = 0; + hid_event.ux_device_class_hid_event_buffer[1] = 0; + hid_event.ux_device_class_hid_event_buffer[2] = UX_HID_LED_KEY_NUM_LOCK; + status = ux_device_class_hid_event_set(hid, &hid_event); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + ux_utility_thread_sleep(SLAVE_WAIT_TIME); + + /**************************************************************************/ + /** 4. Test states. **/ + test_slave_phase ++; + // printf("****** slave step: %ld ******\n", test_slave_phase); + + /** Test key states. **/ + + /* Enable every bit in key state. */ + hid_event.ux_device_class_hid_event_length = 8; + hid_event.ux_device_class_hid_event_buffer[0] = 0xff; + hid_event.ux_device_class_hid_event_buffer[1] = 0; + hid_event.ux_device_class_hid_event_buffer[2] = UX_HID_LED_KEY_CAPS_LOCK; + hid_event.ux_device_class_hid_event_buffer[3] = UX_HID_LED_KEY_SCROLL_LOCK; + hid_event.ux_device_class_hid_event_buffer[4] = UX_HID_LED_KEY_NUM_LOCK; + + status = ux_device_class_hid_event_set(hid, &hid_event); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + ux_utility_thread_sleep(SLAVE_WAIT_TIME); + + /* Add a key so the host can receive it, allowing checking of key state. */ + hid_event.ux_device_class_hid_event_length = 8; + hid_event.ux_device_class_hid_event_buffer[0] = 0xff; + hid_event.ux_device_class_hid_event_buffer[1] = 0; + hid_event.ux_device_class_hid_event_buffer[2] = 0; + hid_event.ux_device_class_hid_event_buffer[3] = 0; + hid_event.ux_device_class_hid_event_buffer[4] = 0x04; + + status = ux_device_class_hid_event_set(hid, &hid_event); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + ux_utility_thread_sleep(SLAVE_WAIT_TIME); + + /** Test key states. **/ + + /* Disable every bit in key state. */ + hid_event.ux_device_class_hid_event_length = 8; + hid_event.ux_device_class_hid_event_buffer[0] = 0x00; + hid_event.ux_device_class_hid_event_buffer[1] = 0; + hid_event.ux_device_class_hid_event_buffer[2] = UX_HID_LED_KEY_CAPS_LOCK; + hid_event.ux_device_class_hid_event_buffer[3] = UX_HID_LED_KEY_SCROLL_LOCK; + hid_event.ux_device_class_hid_event_buffer[4] = UX_HID_LED_KEY_NUM_LOCK; + + /* Add a different key so the host can receive it, allowing checking of key state. */ + hid_event.ux_device_class_hid_event_buffer[5] = 0x05; + + status = ux_device_class_hid_event_set(hid, &hid_event); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + hid_event.ux_device_class_hid_event_buffer[2] = 0; + hid_event.ux_device_class_hid_event_buffer[3] = 0; + hid_event.ux_device_class_hid_event_buffer[4] = 0; + hid_event.ux_device_class_hid_event_buffer[5] = 0; + + ux_utility_thread_sleep(SLAVE_WAIT_TIME); + + /**************************************************************************/ + /** 5. Test raw key. **/ + test_slave_phase ++; + // printf("****** slave step: %ld ******\n", test_slave_phase); + + /* Wait decode mode change. */ + if (tx_demo_phase_sync(UX_FALSE, 20, SLAVE_WAIT_TIME) != UX_SUCCESS) + { + printf("Error in line %d, thread phase error %ld <> %ld!\n", __LINE__, test_host_phase, test_slave_phase); + test_control_return(1); + } + + /** Test raw key. **/ + + for (i = KEY_START; i < ARRAY_COUNT(ux_host_class_hid_keyboard_regular_array); i++) + { + + hid_event.ux_device_class_hid_event_length = 8; + + /* Modification byte. */ + hid_event.ux_device_class_hid_event_buffer[0] = 0; + + /* Reserved byte. */ + hid_event.ux_device_class_hid_event_buffer[1] = 0; + + /* Key byte. */ + hid_event.ux_device_class_hid_event_buffer[2] = i; + + status = ux_device_class_hid_event_set(hid, &hid_event); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + ux_utility_thread_sleep(SLAVE_WAIT_TIME); + } + ux_utility_thread_sleep(SLAVE_WAIT_TIME); + + /**************************************************************************/ + /** 6. Test invalid key. **/ + test_slave_phase ++; + // printf("****** slave step: %ld ******\n", test_slave_phase); + + /* Wait decode mode change. */ + if (tx_demo_phase_sync(UX_FALSE, 10, SLAVE_WAIT_TIME) != UX_SUCCESS) + { + printf("Error in line %d, thread phase error %ld <> %ld!\n", __LINE__, test_host_phase, test_slave_phase); + test_control_return(1); + } + + /* Key byte. */ + hid_event.ux_device_class_hid_event_buffer[2] = ARRAY_COUNT(ux_host_class_hid_keyboard_regular_array); + + status = ux_device_class_hid_event_set(hid, &hid_event); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + /* Key byte release. */ + hid_event.ux_device_class_hid_event_buffer[2] = 0; + + status = ux_device_class_hid_event_set(hid, &hid_event); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + ux_utility_thread_sleep(SLAVE_WAIT_TIME); + + /**************************************************************************/ + /** 7. Test key array overflow. **/ + test_slave_phase ++; + // printf("****** slave step: %ld ******\n", test_slave_phase); + + /* Wait decode mode change. */ + if (tx_demo_phase_sync(UX_FALSE, 10, SLAVE_WAIT_TIME) != UX_SUCCESS) + { + printf("Error in line %d, thread phase error %ld <> %ld!\n", __LINE__, test_host_phase, test_slave_phase); + test_control_return(1); + } + + /** Test key array full. **/ + + for (i = 0; i < UX_HOST_CLASS_HID_KEYBOARD_USAGE_ARRAY_LENGTH + 1; i++) + { + + /* Press key. */ + hid_event.ux_device_class_hid_event_length = 8; + hid_event.ux_device_class_hid_event_buffer[0] = 0; + hid_event.ux_device_class_hid_event_buffer[1] = 0; + hid_event.ux_device_class_hid_event_buffer[2] = 5; + status = ux_device_class_hid_event_set(hid, &hid_event); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + ux_utility_thread_sleep(SLAVE_WAIT_TIME); + + /* Release previous key. */ + hid_event.ux_device_class_hid_event_length = 8; + hid_event.ux_device_class_hid_event_buffer[0] = 0; + hid_event.ux_device_class_hid_event_buffer[1] = 0; + hid_event.ux_device_class_hid_event_buffer[2] = 0; + status = ux_device_class_hid_event_set(hid, &hid_event); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + ux_utility_thread_sleep(SLAVE_WAIT_TIME); + } + ux_utility_thread_sleep(SLAVE_WAIT_TIME); + + /* All done. */ + test_slave_phase = 0; +} \ No newline at end of file diff --git a/test/regression/usbx_hid_keyboard_key_with_report_id_test.c b/test/regression/usbx_hid_keyboard_key_with_report_id_test.c new file mode 100644 index 00000000..8e6eccf4 --- /dev/null +++ b/test/regression/usbx_hid_keyboard_key_with_report_id_test.c @@ -0,0 +1,722 @@ +/* This file tests that the host correctly receives the keys the device sends to it when + the report descriptor defines a non-zero report id. */ + +#include "usbx_test_common_hid.h" + +#include "ux_host_class_hid_keyboard.h" + +static UCHAR ux_host_class_hid_keyboard_regular_array[] = +{ + 0,0,0,0, + 'a','b','c','d','e','f','g','h','i','j', 'k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z', + '1','2','3','4','5','6','7','8','9','0', + 0x0d,0x1b,0x08,0x07,0x20,'-','=','[',']', + '\\','#',';',0x27,'`',',','.','/',0xf0, + 0xbb,0xbc,0xbd,0xbe,0xbf,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6, + 0x00,0xf1,0x00,0xd2,0xc7,0xc9,0xd3,0xcf,0xd1,0xcd,0xcd,0xd0,0xc8,0xf2, + '/','*','-','+', + 0x0d,'1','2','3','4','5','6','7','8','9','0','.','\\',0x00,0x00,'=', + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +static UCHAR ux_host_class_hid_keyboard_shift_array[] = +{ + 0,0,0,0, + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z', + '!','@','#','$','%','^','&','*','(',')', + 0x0d,0x1b,0x08,0x07,0x20,'_','+','{','}', + '|','~',':','"','~','<','>','?',0xf0, + 0xbb,0xbc,0xbd,0xbe,0xbf,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6, + 0x00,0xf1,0x00,0xd2,0xc7,0xc9,0xd3,0xcf,0xd1,0xcd,0xcd,0xd0,0xc8,0xf2, + '/','*','-','+', + 0x0d,'1','2','3','4','5','6','7','8','9','0','.','\\',0x00,0x00,'=', + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +static UCHAR ux_host_class_hid_keyboard_numlock_on_array[] = +{ + '/','*','-','+', + 0x0d,'1','2','3','4','5','6','7','8','9','0','.','\\',0x00,0x00,'=', +}; + +static UCHAR ux_host_class_hid_keyboard_numlock_off_array[] = +{ + '/','*','-','+', + 0x0d,0xcf,0xd0,0xd1,0xcb,'5',0xcd,0xc7,0xc8,0xc9,0xd2,0xd3,'\\',0x00,0x00,'=', +}; + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x85, 0x01, // REPORT_ID (1) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, ARRAY_COUNT(ux_host_class_hid_keyboard_regular_array), // LOGICAL_MAXIMUM () + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, ARRAY_COUNT(ux_host_class_hid_keyboard_regular_array), // USAGE_MAXIMUM () + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_keyboard_key_with_report_id_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running HID Keyboard Key With Report ID 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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; + hid_parameter.ux_device_class_hid_parameter_report_id = 1; + + /* 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running HID Keyboard Basic Functionality Test....................... ERROR #10\n"); + test_control_return(1); + } + +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_KEYBOARD *keyboard; +ULONG keyboard_key; +ULONG keyboard_state; +ULONG expected_key; +ULONG num_keypad_keys; +ULONG i; + + + /* 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); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the keyboard instance */ + keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)hid_client -> ux_host_class_hid_client_local_instance; + + /** Test receiving maximum keys at once. **/ + + for (i = 4; i < 10; i++) + { + + while (ux_host_class_hid_keyboard_key_get(keyboard, &keyboard_key, &keyboard_state) != UX_SUCCESS) + ux_utility_thread_sleep(1); + + expected_key = ux_host_class_hid_keyboard_regular_array[i]; + + if (keyboard_key != expected_key) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + } + + /** Test regular keys. **/ + + for (i = 1; i < ARRAY_COUNT(ux_host_class_hid_keyboard_regular_array); i++) + { + + /* These keys change the keyboard state and are not retrievable. */ + if (i == UX_HID_LED_KEY_CAPS_LOCK || + i == UX_HID_LED_KEY_NUM_LOCK || + i == UX_HID_LED_KEY_SCROLL_LOCK) + continue; + + while (ux_host_class_hid_keyboard_key_get(keyboard, &keyboard_key, &keyboard_state) != UX_SUCCESS) + ux_utility_thread_sleep(1); + + expected_key = ux_host_class_hid_keyboard_regular_array[i]; + + if (keyboard_key != expected_key) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + } + + /** Test shift keys. **/ + + for (i = 1; i < ARRAY_COUNT(ux_host_class_hid_keyboard_regular_array); i++) + { + + /* These keys change the keyboard state and are not retrievable. */ + if (i == UX_HID_LED_KEY_CAPS_LOCK || + i == UX_HID_LED_KEY_NUM_LOCK || + i == UX_HID_LED_KEY_SCROLL_LOCK) + continue; + + while (ux_host_class_hid_keyboard_key_get(keyboard, &keyboard_key, &keyboard_state) != UX_SUCCESS) + ux_utility_thread_sleep(1); + + expected_key = ux_host_class_hid_keyboard_shift_array[i]; + + if (keyboard_key != expected_key) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + } + + /** Test numlock on keys. **/ + + num_keypad_keys = (UX_HID_KEYBOARD_KEYS_KEYPAD_UPPER_RANGE - UX_HID_KEYBOARD_KEYS_KEYPAD_LOWER_RANGE) + 1; + + for (i = 0; i < ARRAY_COUNT(ux_host_class_hid_keyboard_numlock_on_array); i++) + { + + while (ux_host_class_hid_keyboard_key_get(keyboard, &keyboard_key, &keyboard_state) != UX_SUCCESS) + ux_utility_thread_sleep(2); + + expected_key = ux_host_class_hid_keyboard_numlock_on_array[i]; + + if (keyboard_key != ux_host_class_hid_keyboard_numlock_on_array[i]) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + } + + /** Test numlock off keys. **/ + + for (i = 0; i < ARRAY_COUNT(ux_host_class_hid_keyboard_numlock_off_array); i++) + { + + while (ux_host_class_hid_keyboard_key_get(keyboard, &keyboard_key, &keyboard_state) != UX_SUCCESS) + ux_utility_thread_sleep(2); + + expected_key = ux_host_class_hid_keyboard_numlock_off_array[i]; + + if (keyboard_key != ux_host_class_hid_keyboard_numlock_off_array[i]) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + } + + /** Test keyboard on states. **/ + + while (ux_host_class_hid_keyboard_key_get(keyboard, &keyboard_key, &keyboard_state) != UX_SUCCESS) + ux_utility_thread_sleep(2); + + /* Ensure every bit is enabled (represented by 0xff07 (search for "Define HID Keyboard States." in ux_host_class_hid_keyboard.h)). */ + if (keyboard_state != 0xff07) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /** Test keyboard off states. **/ + + while (ux_host_class_hid_keyboard_key_get(keyboard, &keyboard_key, &keyboard_state) != UX_SUCCESS) + ux_utility_thread_sleep(2); + + /* Ensure every bit is disabled. */ + if (keyboard_state != 0x0000) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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); +} + +static void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + +UX_SLAVE_DEVICE *device; +UX_SLAVE_INTERFACE *interface; +UX_SLAVE_CLASS_HID *hid; +UX_SLAVE_CLASS_HID_EVENT hid_event; +UINT i; + + /* Get the pointer to the device. */ + device = &_ux_system_slave -> ux_system_slave_device; + + /* reset the HID event structure. */ + ux_utility_memory_set(&hid_event, 0, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + + /* Is the device configured ? */ + while (device->ux_slave_device_state != UX_DEVICE_CONFIGURED) + + /* Then wait. */ + tx_thread_sleep(10); + + /* Get the interface. We use the first interface, this is a simple device. */ + interface = device->ux_slave_device_first_interface; + + /* Form that interface, derive the HID owner. */ + hid = interface->ux_slave_interface_class_instance; + + hid_event.ux_device_class_hid_event_report_id = 1; + + /** Test receiving maximum keys at once. **/ + + hid_event.ux_device_class_hid_event_length = 8; + + /* Modification byte. */ + hid_event.ux_device_class_hid_event_buffer[0] = 0; + + /* Reserved byte. */ + hid_event.ux_device_class_hid_event_buffer[1] = 0; + + /* Set keys. */ + for (i = 0; i < 6; i++) + hid_event.ux_device_class_hid_event_buffer[2 + i] = 4 + i; + + ux_device_class_hid_event_set(hid, &hid_event); + + ux_utility_thread_sleep(2); + + /** Test regular keys. Only go up to maximum value specified by report descriptor. **/ + + for (i = 1; i < ARRAY_COUNT(ux_host_class_hid_keyboard_regular_array); i++) + { + + /* These keys change the keyboard state and are not retrievable. */ + if (i == UX_HID_LED_KEY_CAPS_LOCK || + i == UX_HID_LED_KEY_NUM_LOCK || + i == UX_HID_LED_KEY_SCROLL_LOCK) + continue; + + hid_event.ux_device_class_hid_event_length = 8; + + /* Modification byte. */ + hid_event.ux_device_class_hid_event_buffer[0] = 0; + + /* Reserved byte. */ + hid_event.ux_device_class_hid_event_buffer[1] = 0; + + /* Key byte. */ + hid_event.ux_device_class_hid_event_buffer[2] = i; + + ux_device_class_hid_event_set(hid, &hid_event); + + ux_utility_thread_sleep(2); + } + + /** Test shift keys. Only go up to maximum value specified by report descriptor. **/ + + /* Turn CAPS LOCK on. */ + hid_event.ux_device_class_hid_event_length = 8; + hid_event.ux_device_class_hid_event_buffer[0] = 0; + hid_event.ux_device_class_hid_event_buffer[1] = 0; + hid_event.ux_device_class_hid_event_buffer[2] = UX_HID_LED_KEY_CAPS_LOCK; + ux_device_class_hid_event_set(hid, &hid_event); + + for (i = 1; i < ARRAY_COUNT(ux_host_class_hid_keyboard_regular_array); i++) + { + + /* These keys change the keyboard state and are not retrievable. */ + if (i == UX_HID_LED_KEY_CAPS_LOCK || + i == UX_HID_LED_KEY_NUM_LOCK || + i == UX_HID_LED_KEY_SCROLL_LOCK) + continue; + + hid_event.ux_device_class_hid_event_length = 8; + + /* Modification byte. */ + hid_event.ux_device_class_hid_event_buffer[0] = 0; + + /* Reserved byte. */ + hid_event.ux_device_class_hid_event_buffer[1] = 0; + + /* Key byte. */ + hid_event.ux_device_class_hid_event_buffer[2] = i; + + ux_device_class_hid_event_set(hid, &hid_event); + + ux_utility_thread_sleep(2); + } + + /* Turn CAPS LOCK off. */ + hid_event.ux_device_class_hid_event_length = 8; + hid_event.ux_device_class_hid_event_buffer[0] = 0; + hid_event.ux_device_class_hid_event_buffer[1] = 0; + hid_event.ux_device_class_hid_event_buffer[2] = UX_HID_LED_KEY_CAPS_LOCK; + ux_device_class_hid_event_set(hid, &hid_event); + + /** Test NUM LOCK on keys. NUM LOCK is on by default. **/ + + for (i = UX_HID_KEYBOARD_KEYS_KEYPAD_LOWER_RANGE; i <= UX_HID_KEYBOARD_KEYS_KEYPAD_UPPER_RANGE; i++) + { + + hid_event.ux_device_class_hid_event_length = 8; + + /* Modification byte. */ + hid_event.ux_device_class_hid_event_buffer[0] = 0; + + /* Reserved byte. */ + hid_event.ux_device_class_hid_event_buffer[1] = 0; + + /* Key byte. */ + hid_event.ux_device_class_hid_event_buffer[2] = i; + + ux_device_class_hid_event_set(hid, &hid_event); + + ux_utility_thread_sleep(2); + } + + /** Test NUM LOCK off keys. **/ + + /* Turn NUM LOCK off. */ + hid_event.ux_device_class_hid_event_length = 8; + hid_event.ux_device_class_hid_event_buffer[0] = 0; + hid_event.ux_device_class_hid_event_buffer[1] = 0; + hid_event.ux_device_class_hid_event_buffer[2] = UX_HID_LED_KEY_NUM_LOCK; + ux_device_class_hid_event_set(hid, &hid_event); + + for (i = UX_HID_KEYBOARD_KEYS_KEYPAD_LOWER_RANGE; i <= UX_HID_KEYBOARD_KEYS_KEYPAD_UPPER_RANGE; i++) + { + + hid_event.ux_device_class_hid_event_length = 8; + + /* Modification byte. */ + hid_event.ux_device_class_hid_event_buffer[0] = 0; + + /* Reserved byte. */ + hid_event.ux_device_class_hid_event_buffer[1] = 0; + + /* Key byte. */ + hid_event.ux_device_class_hid_event_buffer[2] = i; + + ux_device_class_hid_event_set(hid, &hid_event); + + ux_utility_thread_sleep(2); + } + + /* Turn NUM LOCK on. */ + hid_event.ux_device_class_hid_event_length = 8; + hid_event.ux_device_class_hid_event_buffer[0] = 0; + hid_event.ux_device_class_hid_event_buffer[1] = 0; + hid_event.ux_device_class_hid_event_buffer[2] = UX_HID_LED_KEY_NUM_LOCK; + ux_device_class_hid_event_set(hid, &hid_event); + + /** Test key states. **/ + + /* Enable every bit in key state. */ + hid_event.ux_device_class_hid_event_length = 8; + hid_event.ux_device_class_hid_event_buffer[0] = 0xff; + hid_event.ux_device_class_hid_event_buffer[1] = 0; + hid_event.ux_device_class_hid_event_buffer[2] = UX_HID_LED_KEY_CAPS_LOCK; + hid_event.ux_device_class_hid_event_buffer[3] = UX_HID_LED_KEY_SCROLL_LOCK; + + /* Add a key so the host can receive it, allowing checking of key state. */ + hid_event.ux_device_class_hid_event_buffer[4] = 0x04; + + ux_device_class_hid_event_set(hid, &hid_event); + + /** Test key states. **/ + + /* Disable every bit in key state. */ + hid_event.ux_device_class_hid_event_length = 8; + hid_event.ux_device_class_hid_event_buffer[0] = 0x00; + hid_event.ux_device_class_hid_event_buffer[1] = 0; + hid_event.ux_device_class_hid_event_buffer[2] = UX_HID_LED_KEY_CAPS_LOCK; + hid_event.ux_device_class_hid_event_buffer[3] = UX_HID_LED_KEY_SCROLL_LOCK; + hid_event.ux_device_class_hid_event_buffer[4] = UX_HID_LED_KEY_NUM_LOCK; + + /* Add a key so the host can receive it, allowing checking of key state. */ + hid_event.ux_device_class_hid_event_buffer[5] = 0x04; + + ux_device_class_hid_event_set(hid, &hid_event); +} diff --git a/test/regression/usbx_hid_mouse_basic_test.c b/test/regression/usbx_hid_mouse_basic_test.c new file mode 100644 index 00000000..2650b1af --- /dev/null +++ b/test/regression/usbx_hid_mouse_basic_test.c @@ -0,0 +1,510 @@ +/* This test is designed to test simple usage of the mouse class. */ + +#include "usbx_test_common_hid.h" + +#include "ux_host_class_hid_keyboard.h" +#include "ux_host_class_hid_mouse.h" + +#include "ux_test_utility_sim.h" +#include "ux_test_hcd_sim_host.h" + +static UX_HOST_CLASS_HID_MOUSE *mouse; +static UCHAR has_host_received; + + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 52 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00, + 0x00, + + /* HID descriptor */ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH), + MSB(HID_MOUSE_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 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_MOUSE_REPORT_LENGTH), + MSB(HID_MOUSE_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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_mouse_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; + + /* Inform user. */ + printf("Running HID Mouse Basic Functionality 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_mouse_name, ux_host_class_hid_mouse_entry); + if (status != UX_SUCCESS) + { + + printf("Error on line %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 on line %d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the hid class parameters for a mouse. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_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); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, 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 UINT sleep_break_on_removed(VOID) +{ + +UINT status; +UX_HOST_CLASS *class; + + /* Find the main HID container. */ + status = ux_host_stack_class_get(_ux_system_host_class_hid_name, &class); + if (status == UX_SUCCESS) + { + + /* Find the instance. */ + status = ux_host_stack_class_instance_get(class, 0, (void **) &hid); + if (status != UX_SUCCESS) + return UX_TRUE; + } + + return UX_FALSE; +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UINT max_num_loops; +UINT num_loops; +ULONG num_attempts; +ULONG max_attempts; +SLONG cur_mouse_wheel_movement; +SLONG next_mouse_wheel_movement; +SLONG cur_mouse_x_position; +SLONG cur_mouse_y_position; +SLONG next_mouse_x_position; +SLONG next_mouse_y_position; +ULONG cur_mouse_buttons; +UCHAR next_mouse_buttons; + + /* Initilize max loop value. */ + max_num_loops = 16; + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the mouse instance */ + mouse = (UX_HOST_CLASS_HID_MOUSE *)hid_client -> ux_host_class_hid_client_local_instance; + + /* Set number of successful loops to execute. */ + num_loops = 0; + max_num_loops = 16; + + /* Set number of fails. */ + num_attempts = 0; + max_attempts = 3*max_num_loops; + + /* Set initial mouse button values. */ + next_mouse_buttons = 0x01; + + /* Set initial mouse position values. */ + next_mouse_x_position = -8; + next_mouse_y_position = -8; + + /* Set initial mouse wheel value. */ + next_mouse_wheel_movement = -8; + + while (num_loops++ != max_num_loops) + { + + /* Once one works, the others should work as well. */ + while (1) + { + ux_host_class_hid_mouse_buttons_get(mouse, &cur_mouse_buttons); + if (cur_mouse_buttons == next_mouse_buttons) + break; + tx_thread_sleep(10); + } + ux_host_class_hid_mouse_position_get(mouse, &cur_mouse_x_position, &cur_mouse_y_position); + ux_host_class_hid_mouse_wheel_get(mouse, &cur_mouse_wheel_movement); + + /* Are these the expected values? */ + UX_TEST_ASSERT(cur_mouse_buttons == next_mouse_buttons && + cur_mouse_x_position == next_mouse_x_position && + cur_mouse_y_position == next_mouse_y_position && + cur_mouse_wheel_movement == next_mouse_wheel_movement); + + /* Signal to device to continue. */ + has_host_received = 1; + + /* Increment values. */ + next_mouse_buttons = 0x07 & (next_mouse_buttons + 1); + next_mouse_x_position++; + next_mouse_y_position++; + next_mouse_wheel_movement++; + } + + /* Simulate detach. */ + ux_test_hcd_sim_host_disconnect(); + ux_test_breakable_sleep(50, sleep_break_on_removed); + + /* 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); +} + +static void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + +UX_SLAVE_DEVICE *device; +UX_SLAVE_INTERFACE *interface; +UX_SLAVE_CLASS_HID *hid; +UX_SLAVE_CLASS_HID_EVENT hid_event; + + /* Get the pointer to the device. */ + device = &_ux_system_slave -> ux_system_slave_device; + + /* reset the HID event structure. */ + ux_utility_memory_set(&hid_event, 0, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + + /* Set length of event. */ + hid_event.ux_device_class_hid_event_length = 4; + + /* Set initial value for buttons. The first three bits are for buttons, the rest are padding. */ + hid_event.ux_device_class_hid_event_buffer[0] = 1; + + /* Set initial value for x and y positions. */ + hid_event.ux_device_class_hid_event_buffer[1] = -8; + hid_event.ux_device_class_hid_event_buffer[2] = -8; + + /* Set initial value for mouse wheel. */ + hid_event.ux_device_class_hid_event_buffer[3] = -8; + + while (1) + { + + /* Is the device configured ? */ + while (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED) + { +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); + tx_thread_relinquish(); +#else + /* Then wait. */ + tx_thread_sleep(10); +#endif + } + + + /* Until the device stays configured. */ + while (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED) + { +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); + tx_thread_relinquish(); +#endif + + /* Get the interface. We use the first interface, this is a simple device. */ + interface = device -> ux_slave_device_first_interface; + + /* From that interface, derive the HID owner. */ + hid = interface -> ux_slave_interface_class_instance; + + /* Set the mouse event. */ + ux_device_class_hid_event_set(hid, &hid_event); + + /* Wait for host to receive. */ + while (!has_host_received) + { +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); + tx_thread_relinquish(); +#else + tx_thread_sleep(10); +#endif + } + has_host_received = 0; + + /* Change the buttons. */ + hid_event.ux_device_class_hid_event_buffer[0] = (0x7 & hid_event.ux_device_class_hid_event_buffer[0] + 1); + + /* Change the x, y, and wheel positions. These are relative values. */ + hid_event.ux_device_class_hid_event_buffer[1] = 1; + hid_event.ux_device_class_hid_event_buffer[2] = 1; + hid_event.ux_device_class_hid_event_buffer[3] = 1; + } + } +} + diff --git a/test/regression/usbx_hid_mouse_extraction_test.c b/test/regression/usbx_hid_mouse_extraction_test.c new file mode 100644 index 00000000..3429928b --- /dev/null +++ b/test/regression/usbx_hid_mouse_extraction_test.c @@ -0,0 +1,370 @@ +/* This test is designed to test the extraction of a mouse device. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_mouse.h" + + +static UX_HOST_CLASS_HID_MOUSE *mouse; + + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 52 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00, + 0x00, + + /* HID descriptor */ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH), + MSB(HID_MOUSE_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 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_MOUSE_REPORT_LENGTH), + MSB(HID_MOUSE_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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_mouse_extraction_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + /* Inform user. */ + printf("Running HID Mouse Extraction 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_system_host_change_function); + 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_mouse_name, ux_host_class_hid_mouse_entry); + if (status != UX_SUCCESS) + { + + printf("Error on line %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 on line %d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the hid class parameters for a mouse. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_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 UINT ux_hcd_sim_host_entry_filter_device_extraction_test(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; + + switch(function) + { + case UX_HCD_GET_PORT_STATUS: + + /* No device on this port. */ + status = 0; + + /* This is a Full speed device. */ + status |= UX_PS_DS_FS; + + break; + + + default: + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + break; + } + + return status; +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HCD *hcd; + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the mouse instance */ + mouse = (UX_HOST_CLASS_HID_MOUSE *)hid_client -> ux_host_class_hid_client_local_instance; + + hcd = UX_DEVICE_HCD_GET(hid -> ux_host_class_hid_device); + + /* Change the HCD entry function to our filter function. */ + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter_device_extraction_test; + + /* Signal port activity to the enum thread. */ + hcd -> ux_hcd_root_hub_signal[0] = 1; + + /* Signal enum thread. */ + _ux_utility_semaphore_put(&_ux_system_host -> ux_system_host_enum_semaphore); + + /* Wait for hid class to shut down. */ + while(hid -> ux_host_class_hid_state == UX_HOST_CLASS_INSTANCE_LIVE) + tx_thread_sleep(10); + + /* 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_hid_mouse_extraction_test2.c b/test/regression/usbx_hid_mouse_extraction_test2.c new file mode 100644 index 00000000..7ab230c2 --- /dev/null +++ b/test/regression/usbx_hid_mouse_extraction_test2.c @@ -0,0 +1,369 @@ +/* This test is designed to test the extraction of a mouse device. + This is similar to the first extraction test, except there is no ux_system_host_change_function. + This allows us to hit the following false condition in _ux_host_class_hid_mouse_deactivate: + if (_ux_system_host -> ux_system_host_change_function != UX_NULL) +*/ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_mouse.h" + + +static UX_HOST_CLASS_HID_MOUSE *mouse; + + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 52 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00, + 0x00, + + /* HID descriptor */ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH), + MSB(HID_MOUSE_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 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_MOUSE_REPORT_LENGTH), + MSB(HID_MOUSE_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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_mouse_extraction_test2_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + /* Inform user. */ + printf("Running HID Mouse Extraction Test 2................................. "); + + /* 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(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_mouse_name, ux_host_class_hid_mouse_entry); + if (status != UX_SUCCESS) + { + + printf("Error on line %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 on line %d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the hid class parameters for a mouse. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_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 UINT ux_hcd_sim_host_entry_filter_device_extraction_test(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; + + switch(function) + { + case UX_HCD_GET_PORT_STATUS: + + /* No device on this port. */ + status = 0; + + /* This is a Full speed device. */ + status |= UX_PS_DS_FS; + + break; + + + default: + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + break; + } + + return status; +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HCD *hcd; + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the mouse instance */ + mouse = (UX_HOST_CLASS_HID_MOUSE *)hid_client -> ux_host_class_hid_client_local_instance; + + hcd = UX_DEVICE_HCD_GET(hid -> ux_host_class_hid_device); + + /* Change the HCD entry function to our filter function. */ + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter_device_extraction_test; + + /* Signal port activity to the enum thread. */ + hcd -> ux_hcd_root_hub_signal[0] = 1; + + /* Signal enum thread. */ + _ux_utility_semaphore_put(&_ux_system_host -> ux_system_host_enum_semaphore); + + /* Wait for hid class to shut down. */ + while(hid -> ux_host_class_hid_state == UX_HOST_CLASS_INSTANCE_LIVE) + tx_thread_sleep(10); + + /* 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_hid_remote_control_extraction_test.c b/test/regression/usbx_hid_remote_control_extraction_test.c new file mode 100644 index 00000000..ab871057 --- /dev/null +++ b/test/regression/usbx_hid_remote_control_extraction_test.c @@ -0,0 +1,361 @@ +/* This test is concentrates on extraction of a remote control device. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_remote_control.h" + + +static UX_HOST_CLASS_HID_REMOTE_CONTROL *remote_control; + + +static UCHAR hid_remote_control_report[] = { + + 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) + 0x09, 0x01, // USAGE (Consumer Control) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x02, // USAGE (Numeric Key Pad) + 0xa1, 0x02, // COLLECTION (Logical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x0a, // USAGE_MAXIMUM (Button 10) + 0x15, 0x01, // LOGICAL_MINIMUM (1) + 0x25, 0x0a, // LOGICAL_MAXIMUM (10) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0, // END_COLLECTION + 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) + 0x09, 0x86, // USAGE (Channel) + 0x09, 0xe0, // USAGE (Volume) + 0x15, 0xff, // LOGICAL_MINIMUM (-1) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x02, // REPORT_SIZE (2) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x46, // INPUT (Data,Var,Rel,Null) + 0xc0 // END_COLLECTION +}; +#define HID_REMOTE_CONTROL_REPORT_LENGTH (sizeof(hid_remote_control_report)/sizeof(hid_remote_control_report[0])) + + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 52 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00, + 0x00, + + /* HID descriptor */ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_REMOTE_CONTROL_REPORT_LENGTH), + MSB(HID_REMOTE_CONTROL_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 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_REMOTE_CONTROL_REPORT_LENGTH), + MSB(HID_REMOTE_CONTROL_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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_remote_control_extraction_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + /* Inform user. */ + printf("Running HID Remote Control Extraction 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_system_host_change_function); + 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_remote_control_name, ux_host_class_hid_remote_control_entry); + if (status != UX_SUCCESS) + { + + printf("Error on line %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 on line %d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the hid class parameters for a mouse. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_remote_control_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_REMOTE_CONTROL_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 UINT ux_hcd_sim_host_entry_filter_device_extraction_test(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; + + switch(function) + { + case UX_HCD_GET_PORT_STATUS: + + /* No device on this port. */ + status = 0; + + /* This is a Full speed device. */ + status |= UX_PS_DS_FS; + + break; + + + default: + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + break; + } + + return status; +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HCD *hcd; + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the mouse instance */ + remote_control = (UX_HOST_CLASS_HID_REMOTE_CONTROL *)hid_client -> ux_host_class_hid_client_local_instance; + + hcd = UX_DEVICE_HCD_GET(hid -> ux_host_class_hid_device); + + /* Change the HCD entry function to our filter function. */ + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter_device_extraction_test; + + /* Signal port activity to the enum thread. */ + hcd -> ux_hcd_root_hub_signal[0] = 1; + + /* Signal enum thread. */ + _ux_utility_semaphore_put(&_ux_system_host -> ux_system_host_enum_semaphore); + + /* Wait for hid class to shut down. */ + while(hid -> ux_host_class_hid_state == UX_HOST_CLASS_INSTANCE_LIVE) + tx_thread_sleep(10); + + /* 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_hid_remote_control_extraction_test2.c b/test/regression/usbx_hid_remote_control_extraction_test2.c new file mode 100644 index 00000000..7d82afa6 --- /dev/null +++ b/test/regression/usbx_hid_remote_control_extraction_test2.c @@ -0,0 +1,358 @@ +/* This test is concentrates on extraction of a remote control device. + This is similar to the first extraction test, except there is no ux_system_host_change_function. + This allows us to hit the following false condition in _ux_host_class_hid_remote_control_deactivate: + if (_ux_system_host -> ux_system_host_change_function != UX_NULL) */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_remote_control.h" + + +static UX_HOST_CLASS_HID_REMOTE_CONTROL *remote_control; + + +static UCHAR hid_remote_control_report[] = { + + 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) + 0x09, 0x01, // USAGE (Consumer Control) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x02, // USAGE (Numeric Key Pad) + 0xa1, 0x02, // COLLECTION (Logical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x0a, // USAGE_MAXIMUM (Button 10) + 0x15, 0x01, // LOGICAL_MINIMUM (1) + 0x25, 0x0a, // LOGICAL_MAXIMUM (10) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0, // END_COLLECTION + 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) + 0x09, 0x86, // USAGE (Channel) + 0x09, 0xe0, // USAGE (Volume) + 0x15, 0xff, // LOGICAL_MINIMUM (-1) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x02, // REPORT_SIZE (2) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x46, // INPUT (Data,Var,Rel,Null) + 0xc0 // END_COLLECTION +}; +#define HID_REMOTE_CONTROL_REPORT_LENGTH (sizeof(hid_remote_control_report)/sizeof(hid_remote_control_report[0])) + + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 52 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00, + 0x00, + + /* HID descriptor */ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_REMOTE_CONTROL_REPORT_LENGTH), + MSB(HID_REMOTE_CONTROL_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 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_REMOTE_CONTROL_REPORT_LENGTH), + MSB(HID_REMOTE_CONTROL_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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_remote_control_extraction_test2_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + /* Inform user. */ + printf("Running HID Remote Control Extraction Test 2........................ "); + + /* 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(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_remote_control_name, ux_host_class_hid_remote_control_entry); + if (status != UX_SUCCESS) + { + + printf("Error on line %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 on line %d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the hid class parameters for a mouse. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_remote_control_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_REMOTE_CONTROL_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 UINT ux_hcd_sim_host_entry_filter_device_extraction_test(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; + + switch(function) + { + case UX_HCD_GET_PORT_STATUS: + + /* No device on this port. */ + status = 0; + + /* This is a Full speed device. */ + status |= UX_PS_DS_FS; + + break; + + + default: + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + break; + } + + return status; +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HCD *hcd; + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the mouse instance */ + remote_control = (UX_HOST_CLASS_HID_REMOTE_CONTROL *)hid_client -> ux_host_class_hid_client_local_instance; + + hcd = UX_DEVICE_HCD_GET(hid -> ux_host_class_hid_device); + + /* Change the HCD entry function to our filter function. */ + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter_device_extraction_test; + + /* Signal port activity to the enum thread. */ + hcd -> ux_hcd_root_hub_signal[0] = 1; + + /* Signal enum thread. */ + _ux_utility_semaphore_put(&_ux_system_host -> ux_system_host_enum_semaphore); + + /* Wait for hid class to shut down. */ + while(hid -> ux_host_class_hid_state == UX_HOST_CLASS_INSTANCE_LIVE) + tx_thread_sleep(10); + + /* 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_hid_remote_control_tests.c b/test/regression/usbx_hid_remote_control_tests.c new file mode 100644 index 00000000..03da1fda --- /dev/null +++ b/test/regression/usbx_hid_remote_control_tests.c @@ -0,0 +1,692 @@ +/* TODO: some common stuff from storage we might want to pull out: + -memory check - pretty good + -connect and disconnect + -getting class/instance +*/ + +#include "ux_api.h" +#include "ux_utility.h" +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" +#include "ux_host_class_hid_remote_control.h" + +#include "ux_test.h" +#include "ux_test_actions.h" +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" + + +#define LSB(x) (x & 0xff) +#define MSB(x) ((x & 0xff00) >> 8) + +/* Define constants. */ +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_MEMORY_SIZE (64*1024) + +/* Define local/extern function prototypes. */ +static void test_main_thread_entry(ULONG); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static TX_THREAD test_main_thread; +static TX_THREAD test_slave_thread; +static UCHAR test_slave_thread_stack[4096]; +static UX_HOST_CLASS *global_host_hid_class; +static UX_HOST_CLASS_HID *global_host_hid; +static UX_SLAVE_CLASS_HID *global_slave_hid; +static UX_SLAVE_CLASS_HID *global_slave_hid_persistent; +static UX_HOST_CLASS_HID_CLIENT *global_host_hid_client; +static UX_HOST_CLASS_HID_REMOTE_CONTROL *global_host_remote_control; +static UX_SLAVE_CLASS_HID_PARAMETER global_slave_hid_parameter; +static UX_HCD *global_hcd; + + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) + 0x09, 0x01, // USAGE (Consumer Control) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x02, // USAGE (Numeric Key Pad) + 0xa1, 0x02, // COLLECTION (Logical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x0a, // USAGE_MAXIMUM (Button 10) + 0x15, 0x01, // LOGICAL_MINIMUM (1) + 0x25, 0x0a, // LOGICAL_MAXIMUM (10) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0, // END_COLLECTION + 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) + 0x09, 0x86, // USAGE (Channel) + 0x09, 0xe0, // USAGE (Volume) + 0x15, 0xff, // LOGICAL_MINIMUM (-1) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x02, // REPORT_SIZE (2) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x46, // INPUT (Data,Var,Rel,Null) + 0xc0 // END_COLLECTION +}; + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00, + 0x00, + + /* HID descriptor */ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(sizeof(hid_report_descriptor)), + MSB(sizeof(hid_report_descriptor)), + + /* Endpoint descriptor (Interrupt) */ + 0x07, 0x05, 0x82, 0x03, 0x08, 0x00, 0x08 + + }; + +#define FULL_SPEED_REPORT_DESCRIPTOR_LENGTH_LSB_POS (0x12 + 0x09 + 0x09 + 0x7) +#define FULL_SPEED_REPORT_DESCRIPTOR_LENGTH_MSB_POS (FULL_SPEED_REPORT_DESCRIPTOR_LENGTH_LSB_POS + 1) + + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* 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(sizeof(hid_report_descriptor)), + MSB(sizeof(hid_report_descriptor)), + + /* Endpoint descriptor (Interrupt) */ + 0x07, 0x05, 0x82, 0x03, 0x08, 0x00, 0x08 + + }; + +#define HIGH_SPEED_REPORT_DESCRIPTOR_LENGTH_LSB_POS (0x12 + 0x0a + 0x09 + 0x09 + 0x7) +#define HIGH_SPEED_REPORT_DESCRIPTOR_LENGTH_MSB_POS (HIGH_SPEED_REPORT_DESCRIPTOR_LENGTH_LSB_POS + 1) + + + /* 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 + }; + +/* Functions from storage basic test. */ + +static VOID get_global_hid_values() +{ + + UX_TEST_CHECK_SUCCESS(ux_host_stack_class_get(_ux_system_host_class_hid_name, &global_host_hid_class)); + UX_TEST_CHECK_SUCCESS(ux_host_stack_class_instance_get(global_host_hid_class, 0, (void **) &global_host_hid)); + UX_TEST_ASSERT(global_host_hid -> ux_host_class_hid_state == UX_HOST_CLASS_INSTANCE_LIVE); + global_host_hid_client = global_host_hid -> ux_host_class_hid_client; + UX_TEST_ASSERT(global_host_hid_client -> ux_host_class_hid_client_local_instance != UX_NULL); + global_host_remote_control = (UX_HOST_CLASS_HID_REMOTE_CONTROL *)global_host_hid_client -> ux_host_class_hid_client_local_instance; +} + +static VOID wait_for_enum_completion_and_get_global_hid_values() +{ + + ux_test_wait_for_enum_thread_completion(); + get_global_hid_values(); +} + +/* Returns whether or not the enumeration succeeded. */ +static VOID connect_host_and_slave() +{ + + ux_test_connect_slave_and_host_wait_for_enum_completion(); + get_global_hid_values(); +} + +/* General HID utilities. */ + +void set_report_descriptor(UCHAR *report_descriptor, ULONG report_descriptor_length) +{ + + /* Should only be called if the host and slave is disconnected. */ + UX_TEST_ASSERT(global_hcd->ux_hcd_nb_devices == 0); + UX_TEST_ASSERT(_ux_system_slave->ux_system_slave_device.ux_slave_device_state == UX_DEVICE_RESET); + + global_slave_hid_persistent->ux_device_class_hid_report_address = report_descriptor; + global_slave_hid_persistent->ux_device_class_hid_report_length = report_descriptor_length; + + device_framework_full_speed[FULL_SPEED_REPORT_DESCRIPTOR_LENGTH_LSB_POS] = LSB(report_descriptor_length); + device_framework_full_speed[FULL_SPEED_REPORT_DESCRIPTOR_LENGTH_MSB_POS] = MSB(report_descriptor_length); + + device_framework_high_speed[HIGH_SPEED_REPORT_DESCRIPTOR_LENGTH_LSB_POS] = LSB(report_descriptor_length); + device_framework_high_speed[HIGH_SPEED_REPORT_DESCRIPTOR_LENGTH_MSB_POS] = MSB(report_descriptor_length); +} + +UINT slave_hid_callback(UX_SLAVE_CLASS_HID *hid, UX_SLAVE_CLASS_HID_EVENT *event) +{ + return 0; +} + +VOID slave_class_hid_instance_activate(VOID *instance) +{ + + if (global_slave_hid_persistent) + UX_TEST_ASSERT(global_slave_hid_persistent == instance); + global_slave_hid_persistent = instance; + + global_slave_hid = instance; +} + +VOID slave_class_hid_instance_deactivate(VOID *instance) +{ + + global_slave_hid = UX_NULL; +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_remote_control_tests_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; + + + /* Inform user. */ + printf("Running HID Remote Control Tests.................................... "); + + stepinfo("\n"); + + /* 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(ux_test_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_remote_control_name, ux_host_class_hid_remote_control_entry); + if (status != UX_SUCCESS) + { + + printf("Error on line %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, sizeof(device_framework_high_speed), + device_framework_full_speed, sizeof(device_framework_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 for a mouse. */ + global_slave_hid_parameter.ux_slave_class_hid_instance_activate = slave_class_hid_instance_activate; + global_slave_hid_parameter.ux_slave_class_hid_instance_deactivate = slave_class_hid_instance_deactivate; + global_slave_hid_parameter.ux_device_class_hid_parameter_report_address = hid_report_descriptor; + global_slave_hid_parameter.ux_device_class_hid_parameter_report_length = sizeof(hid_report_descriptor); + global_slave_hid_parameter.ux_device_class_hid_parameter_callback = slave_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 *)&global_slave_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); + } + + global_hcd = &_ux_system_host->ux_system_host_hcd_array[0]; + + /* Create the main host simulation thread. */ + status = tx_thread_create(&test_main_thread, "test_main_thread", test_main_thread_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); + } +} + +/* basic_test resources */ + +static UINT basic_test_get_next_channel_volume_value(ULONG value) +{ + + if (value == 0x03) + return 0x00; + else if (value == 0x00) + return 0x01; + else if (value == 0x01) + return 0x03; + + return 0xff; +} + +static void basic_test_slave_thread_entry(ULONG arg) +{ + +UX_SLAVE_CLASS_HID_EVENT hid_event; +ULONG value; +UINT max_num_loops; + + + /* reset the HID event structure. */ + ux_utility_memory_set(&hid_event, 0, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + + /* Set length of event. */ + hid_event.ux_device_class_hid_event_length = 1; + + /* Set initial keypad value. */ + hid_event.ux_device_class_hid_event_buffer[0] = 0x01; + + /* Set initial channel value. */ + hid_event.ux_device_class_hid_event_buffer[0] |= (0x03 << 4); + + /* Set initial volume value. */ + hid_event.ux_device_class_hid_event_buffer[0] |= (0x01 << 6); + + max_num_loops = 2*UX_HOST_CLASS_HID_REMOTE_CONTROL_USAGE_ARRAY_LENGTH; + while (max_num_loops--) + { + + stepinfo(" slave - max_num_loops: %d\n", max_num_loops); + + /* Wait for host to receive. */ + ux_utility_thread_sleep(2); + + /* Set the mouse event. */ + UX_TEST_CHECK_SUCCESS(ux_device_class_hid_event_set(global_slave_hid, &hid_event)); + + /* Change keypad value. */ + value = hid_event.ux_device_class_hid_event_buffer[0] & 0x0f; + if (value >= 0x0a) + value = 0x01; + else + value++; + + hid_event.ux_device_class_hid_event_buffer[0] &= 0xf0; + hid_event.ux_device_class_hid_event_buffer[0] |= value; + + /* Change channel value. */ + value = ((hid_event.ux_device_class_hid_event_buffer[0] & 0x30) >> 4); + hid_event.ux_device_class_hid_event_buffer[0] &= ~0x30; + hid_event.ux_device_class_hid_event_buffer[0] |= (basic_test_get_next_channel_volume_value(value) << 4); + + /* Change volume value. */ + value = ((hid_event.ux_device_class_hid_event_buffer[0] & 0xc0) >> 6); + hid_event.ux_device_class_hid_event_buffer[0] &= ~0xc0; + hid_event.ux_device_class_hid_event_buffer[0] |= (basic_test_get_next_channel_volume_value(value) << 6); + } +} + +static void basic_test() +{ + +UINT max_num_loops; +ULONG usage; +ULONG value; +ULONG expected_keypad_value; +ULONG expected_channel_value; +ULONG expected_volume_value; + + + stepinfo("basic_test\n"); + + UX_TEST_CHECK_SUCCESS(tx_thread_create(&test_slave_thread, "test_slave_thread", basic_test_slave_thread_entry, 0, + test_slave_thread_stack, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START)); + + /* Initialize expected values. */ + expected_keypad_value = 0x01; + expected_channel_value = 0x03; + expected_volume_value = 0x01; + + /* Set number of successful loops to execute. */ + max_num_loops = 2*UX_HOST_CLASS_HID_REMOTE_CONTROL_USAGE_ARRAY_LENGTH; + while (max_num_loops--) + { + + stepinfo(" host - max_num_loops: %d\n", max_num_loops); + + /* Wait for an event from the device. Each event should have 3 usages. The first is the keypad. */ + while (ux_host_class_hid_remote_control_usage_get(global_host_remote_control, &usage, &value) != UX_SUCCESS) + tx_thread_sleep(1); + + if (usage != (0x00090000 | expected_keypad_value) || value != expected_keypad_value) + { + + printf("Error on line %d. usage: 0x%lx, expected usage: 0x%lx, value: 0x%lx, expected_keypad_value: 0x%lx\n", + __LINE__, usage, 0x00090000 | expected_keypad_value, value, expected_keypad_value); + test_control_return(1); + } + + if (++expected_keypad_value > 0x0a) + expected_keypad_value = 1; + + /* Get the channel value. */ + ux_host_class_hid_remote_control_usage_get(global_host_remote_control, &usage, &value); + if (usage != 0x000c0086 || value != expected_channel_value) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + expected_channel_value = basic_test_get_next_channel_volume_value(value); + + /* Get the volume value. */ + ux_host_class_hid_remote_control_usage_get(global_host_remote_control, &usage, &value); + if (usage != 0x000c00e0 || value != expected_volume_value) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + expected_volume_value = basic_test_get_next_channel_volume_value(value); + } + + UX_TEST_CHECK_SUCCESS(tx_thread_terminate(&test_slave_thread)); + UX_TEST_CHECK_SUCCESS(tx_thread_delete(&test_slave_thread)); +} + +/* event_overflow_test resources */ + +#define EBT_MAX_EVENTS ((UX_HOST_CLASS_HID_REMOTE_CONTROL_USAGE_ARRAY_LENGTH/2) - 1) +#define EBT_NUM_OVERFLOW_EVENTS 100 + +static TX_SEMAPHORE ebt_slave_wakes_host_semaphore; +static TX_SEMAPHORE ebt_host_wakes_slave_semaphore; + +static UCHAR host_event_buffer_test_hid_report_descriptor[] = { + + 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) + 0x09, 0x01, // USAGE (Consumer Control) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) + 0x09, 0xe0, // USAGE (Volume) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0xff, // LOGICAL_MAXIMUM (255) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x46, // INPUT (Data,Var,Rel,Null) + 0xc0 // END_COLLECTION +}; + +static void event_buffer_test_slave_thread_entry(ULONG arg) +{ + +UX_SLAVE_CLASS_HID_EVENT hid_event = { 0 }; +UINT i; + + + /* Add the exact amount. Remember, the host's usage array consists of pairs, + hence the divide by two. */ + for (i = 0; i < EBT_MAX_EVENTS; i++) + { + + /* Setup and send event. */ + hid_event.ux_device_class_hid_event_length = 1; + hid_event.ux_device_class_hid_event_buffer[0] = i; + UX_TEST_CHECK_SUCCESS(ux_device_class_hid_event_set(global_slave_hid, &hid_event)); + + /* Wait for host to receive it. */ + tx_thread_sleep(2); + } + + /* Wake up host test thread. */ + tx_semaphore_put(&ebt_slave_wakes_host_semaphore); + + /* Wait for second part of test. */ + tx_semaphore_get(&ebt_host_wakes_slave_semaphore, TX_WAIT_FOREVER); + + /* We expect to receive some errors. */ + ux_test_add_action_to_main_list_multiple(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_BUFFER_OVERFLOW), EBT_NUM_OVERFLOW_EVENTS); + + for (i = 0; i < EBT_MAX_EVENTS + EBT_NUM_OVERFLOW_EVENTS; i++) + { + + /* Setup and send event. */ + hid_event.ux_device_class_hid_event_length = 1; + hid_event.ux_device_class_hid_event_buffer[0] = i; + UX_TEST_CHECK_SUCCESS(ux_device_class_hid_event_set(global_slave_hid, &hid_event)); + + /* Wait for host to receive it. */ + tx_thread_sleep(2); + } + + /* Ensure all of our actions are gone. */ + UX_TEST_ASSERT_MESSAGE(ux_test_check_actions_empty(), "Number of actions remaining: %d\n", ux_test_get_num_actions_left()); + + /* Wake up host test thread. */ + tx_semaphore_put(&ebt_slave_wakes_host_semaphore); +} + +static void host_event_buffer_test() +{ + +ULONG usage; +ULONG value; +UINT i; + + + stepinfo("event_buffer_overflow_test\n"); + + ux_test_disconnect_slave_and_host_wait_for_enum_completion(global_hcd); + set_report_descriptor(host_event_buffer_test_hid_report_descriptor, sizeof(host_event_buffer_test_hid_report_descriptor)); + connect_host_and_slave(); + + UX_TEST_CHECK_SUCCESS(tx_semaphore_create(&ebt_slave_wakes_host_semaphore, "ebt_slave_wakes_host_semaphore", 0)); + UX_TEST_CHECK_SUCCESS(tx_semaphore_create(&ebt_host_wakes_slave_semaphore, "ebt_host_wakes_slave_semaphore", 0)); + + UX_TEST_CHECK_SUCCESS(tx_thread_create(&test_slave_thread, "test_slave_thread", event_buffer_test_slave_thread_entry, 0, + test_slave_thread_stack, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START)); + + stepinfo(" exact amount\n"); + + /* Wait for slave to send exact amount. */ + tx_semaphore_get(&ebt_slave_wakes_host_semaphore, TX_WAIT_FOREVER); + + /* Ensure exact amount was sent. */ + for (i = 0; i < EBT_MAX_EVENTS; i++) + { + + UX_TEST_CHECK_SUCCESS(ux_host_class_hid_remote_control_usage_get(global_host_remote_control, &usage, &value)); + UX_TEST_ASSERT(usage == 0x000c00e0); + UX_TEST_ASSERT(value == i); + } + + /* Should be no more. */ + UX_TEST_CHECK_NOT_SUCCESS(ux_host_class_hid_remote_control_usage_get(global_host_remote_control, &usage, &value)); + + stepinfo(" overflow\n"); + + /* Wake up slave. */ + tx_semaphore_put(&ebt_host_wakes_slave_semaphore); + + /* Wait for slave to overflow. */ + tx_semaphore_get(&ebt_slave_wakes_host_semaphore, TX_WAIT_FOREVER); + + /* Ensure exact amount was sent. */ + for (i = 0; i < EBT_MAX_EVENTS; i++) + { + + UX_TEST_CHECK_SUCCESS(ux_host_class_hid_remote_control_usage_get(global_host_remote_control, &usage, &value)); + UX_TEST_ASSERT(usage == 0x000c00e0); + UX_TEST_ASSERT(value == i); + } + + /* Should be no more. */ + UX_TEST_CHECK_NOT_SUCCESS(ux_host_class_hid_remote_control_usage_get(global_host_remote_control, &usage, &value)); + + UX_TEST_CHECK_SUCCESS(tx_thread_terminate(&test_slave_thread)); + UX_TEST_CHECK_SUCCESS(tx_thread_delete(&test_slave_thread)); +} + +static void test_main_thread_entry(ULONG arg) +{ + +UINT status; +UINT i; +void (*tests[])() = +{ + basic_test, + host_event_buffer_test, +}; + + + ux_test_wait_for_enum_thread_completion(); + get_global_hid_values(); + ux_test_memory_test_initialize(); + get_global_hid_values(); + /* Run tests. */ + for (i = 0; i < ARRAY_COUNT(tests); i++) + { + tests[i](); + + ux_test_disconnect_slave_and_host_wait_for_enum_completion(global_hcd); + set_report_descriptor(hid_report_descriptor, sizeof(hid_report_descriptor)); + connect_host_and_slave(); + + UX_TEST_ASSERT(ux_test_check_actions_empty()); + } + + /* 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); +} \ No newline at end of file diff --git a/test/regression/usbx_hid_report_descriptor_collection_overflow_test.c b/test/regression/usbx_hid_report_descriptor_collection_overflow_test.c new file mode 100644 index 00000000..295f47f5 --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_collection_overflow_test.c @@ -0,0 +1,313 @@ +/* This test ensures that the parser fails when too many collections are used. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static UINT callback_error_code; + +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) + 0xa1, 0x00, // COLLECTION (Physical) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x04, // REPORT_SIZE (4) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xa1, 0x00, // COLLECTION (Physical) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x06, // REPORT_SIZE (6) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xa1, 0x00, // COLLECTION (Physical) + 0x95, 0x07, // REPORT_COUNT (7) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + /* Add 5th collection (should break). */ + 0xa1, 0x00, // COLLECTION (Physical) + 0x95, 0x07, // REPORT_COUNT (7) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION +}; +#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 + }; + + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + 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_hid_report_descriptor_collection_overflow_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 Collection Oveflow 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); + } + + /* 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_hid_report_descriptor_compress_and_decompress_test.c b/test/regression/usbx_hid_report_descriptor_compress_and_decompress_test.c new file mode 100644 index 00000000..942c4680 --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_compress_and_decompress_test.c @@ -0,0 +1,502 @@ +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static SLONG input_report_buffer_decompressed_original[1024]; +static UCHAR input_report_buffer_compressed[1024]; +static SLONG input_report_buffer_decompressed[1024]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + + /* First field */ + 0x09, 0x01, // USAGE (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* Second field */ + 0x19, 0x02, // USAGE_MINIMUM (2) + 0x29, 0x04, // USAGE_MAXIMUM (4) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* Third field */ + 0x0a, 0xcd, 0xab, // USAGE (0xabcd) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* Fourth field */ + 0x19, 0x06, // USAGE_MINIMUM (6) + 0x29, 0x08, // USAGE_MAXIMUM (8) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x03, // REPORT_COUNT (3) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* Fifth field */ + 0x09, 0x01, // USAGE (1) + 0x75, 0x09, // REPORT_SIZE (9) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* Sixth field */ + 0x19, 0x0a, // USAGE_MINIMUM (10) + 0x29, 0x0c, // USAGE_MAXIMUM (12) + 0x75, 0x09, // REPORT_SIZE (9) + 0x95, 0x03, // REPORT_COUNT (3) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* Seventh field */ + 0x09, 0x0d, // USAGE (13) + 0x75, 0x1f, // REPORT_SIZE (31) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* Eigth field */ + 0x09, 0x0e, // USAGE (14) + 0x75, 0x20, // REPORT_SIZE (32) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* USBX expects keyboards to have at least one output report, otherwise it's an error. */ + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + + 0xc0, // END_COLLECTION +}; +#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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_compress_and_decompress_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 ux_host_class_hid_report_ compress/decompress 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; +UX_HOST_CLASS_HID_CLIENT_REPORT client_report; +UX_HOST_CLASS_HID_REPORT *input_report_descriptor; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the first input report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + input_report_descriptor = report_id.ux_host_class_hid_report_get_report; + if (input_report_descriptor -> ux_host_class_hid_report_id != 0) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* First field */ + + input_report_buffer_decompressed_original[0] = 0x00010001; + input_report_buffer_decompressed_original[1] = 0x01; + + /* Second field */ + + input_report_buffer_decompressed_original[2] = 0x00010002; + input_report_buffer_decompressed_original[3] = 0x01; + + input_report_buffer_decompressed_original[4] = 0x00010003; + input_report_buffer_decompressed_original[5] = 0x00; + + input_report_buffer_decompressed_original[6] = 0x00010004; + input_report_buffer_decompressed_original[7] = 0x01; + + /* Third field */ + + input_report_buffer_decompressed_original[8] = 0x0001abcd; + input_report_buffer_decompressed_original[9] = 0x30; + + /* Fourth field */ + + input_report_buffer_decompressed_original[10] = 0x00010006; + input_report_buffer_decompressed_original[11] = 0x52; + + input_report_buffer_decompressed_original[12] = 0x00010007; + input_report_buffer_decompressed_original[13] = 0x74; + + input_report_buffer_decompressed_original[14] = 0x00010008; + input_report_buffer_decompressed_original[15] = 0x96; + + /* Fifth field */ + + input_report_buffer_decompressed_original[16] = 0x00010001; + input_report_buffer_decompressed_original[17] = 0x0b8; + + /* Sixth field */ + + input_report_buffer_decompressed_original[18] = 0x0001000a; + input_report_buffer_decompressed_original[19] = 0x06d; + + input_report_buffer_decompressed_original[20] = 0x0001000b; + input_report_buffer_decompressed_original[21] = 0x1bf; + + input_report_buffer_decompressed_original[22] = 0x0001000c; + input_report_buffer_decompressed_original[23] = 0x003; + + /* Seventh field */ + + input_report_buffer_decompressed_original[24] = 0x0001000d; + input_report_buffer_decompressed_original[25] = 0x09674523; + + /* Eigth field */ + + input_report_buffer_decompressed_original[26] = 0x0001000e; + input_report_buffer_decompressed_original[27] = 0x03df9b57; + + /* Fill out the request for the decompress api. */ + client_report.ux_host_class_hid_client_report = input_report_descriptor; + client_report.ux_host_class_hid_client_report_buffer = input_report_buffer_decompressed_original; + client_report.ux_host_class_hid_client_report_actual_length = 0; + + /* Request compression. */ + status = _ux_host_class_hid_report_compress(hid, &client_report, input_report_buffer_compressed, 17); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Check output of report compression. */ + if ( + input_report_buffer_compressed[0] != 0x0b || + input_report_buffer_compressed[1] != 0x23 || + input_report_buffer_compressed[2] != 0x45 || + input_report_buffer_compressed[3] != 0x67 || + input_report_buffer_compressed[4] != 0x89 || + input_report_buffer_compressed[5] != 0xab || + input_report_buffer_compressed[6] != 0xcd || + input_report_buffer_compressed[7] != 0xef || + input_report_buffer_compressed[8] != 0x01 || + input_report_buffer_compressed[9] != 0x23 || + input_report_buffer_compressed[10] != 0x45 || + input_report_buffer_compressed[11] != 0x67 || + input_report_buffer_compressed[12] != 0x89 || + input_report_buffer_compressed[13] != 0xab || + input_report_buffer_compressed[14] != 0xcd || + input_report_buffer_compressed[15] != 0xef || + input_report_buffer_compressed[16] != 0x01 + ) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* You're gonna love this. Decompress it and make sure it matches the original! */ + + client_report.ux_host_class_hid_client_report_buffer = input_report_buffer_decompressed; + status = _ux_host_class_hid_report_decompress(hid, &client_report, input_report_buffer_compressed, 28); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + if (memcmp(input_report_buffer_decompressed, input_report_buffer_decompressed_original, 28)) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Decompress it with report id. */ + input_report_buffer_compressed[32] = 0x01; + memcpy(&input_report_buffer_compressed[33], &input_report_buffer_compressed[0], 17); + client_report.ux_host_class_hid_client_report_buffer = input_report_buffer_decompressed; + client_report.ux_host_class_hid_client_report->ux_host_class_hid_report_id = 0x1; + status = _ux_host_class_hid_report_decompress(hid, &client_report, &input_report_buffer_compressed[32], 29); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + if (memcmp(input_report_buffer_decompressed, input_report_buffer_decompressed_original, 28)) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Told ya! */ + + /* 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_hid_report_descriptor_compress_array_test.c b/test/regression/usbx_hid_report_descriptor_compress_array_test.c new file mode 100644 index 00000000..e9cf852c --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_compress_array_test.c @@ -0,0 +1,423 @@ +/* This test concentrates on the report compress api. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" +#include "ux_test.h" + + +static UCHAR input_report_buffer_compressed[1024]; +static SLONG input_report_buffer_decompressed_original[1024]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + /* Keys. */ + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x01, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x01, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0, // END_COLLECTION +}; +#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 + }; + + +static UCHAR ignore_errors; +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (!ignore_errors) + { + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_compress_array_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 Decompress 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; +UX_HOST_CLASS_HID_CLIENT_REPORT client_report; +UX_HOST_CLASS_HID_REPORT *input_report_descriptor; +SLONG report_buffer_decompressed[1024]; +UCHAR report_buffer_compressed[1024] = {0}; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /** Do basic test. **/ + + /* Get the first input report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + UX_TEST_CHECK_SUCCESS(ux_host_class_hid_report_id_get(hid, &report_id)); + input_report_descriptor = report_id.ux_host_class_hid_report_get_report; + + /* 1 */ + report_buffer_decompressed[0] = 0x00070001; + report_buffer_decompressed[1] = 0x1; + + /* 2 */ + report_buffer_decompressed[2] = 0x00070002; + report_buffer_decompressed[3] = 0x2; + + /* 3 */ + report_buffer_decompressed[4] = 0x00070003; + report_buffer_decompressed[5] = 0x3; + + /* 4 */ + report_buffer_decompressed[6] = 0x00070004; + report_buffer_decompressed[7] = 0x4; + + /* 5 */ + report_buffer_decompressed[8] = 0x00070005; + report_buffer_decompressed[9] = 0x5; + + /* 6 */ + report_buffer_decompressed[10] = 0x00070006; + report_buffer_decompressed[11] = 0x6; + + /* Fill out the request for the compress api. */ + client_report.ux_host_class_hid_client_report = input_report_descriptor; + client_report.ux_host_class_hid_client_report_buffer = report_buffer_decompressed; + client_report.ux_host_class_hid_client_report_actual_length = 0; + + /* Request compression. */ + UX_TEST_CHECK_SUCCESS(_ux_host_class_hid_report_compress(hid, &client_report, report_buffer_compressed, sizeof(report_buffer_compressed))); + + /* Check it. */ + UX_TEST_ASSERT(report_buffer_compressed[0] == 0x1); + UX_TEST_ASSERT(report_buffer_compressed[1] == 0x2); + UX_TEST_ASSERT(report_buffer_compressed[2] == 0x3); + UX_TEST_ASSERT(report_buffer_compressed[3] == 0x4); + UX_TEST_ASSERT(report_buffer_compressed[4] == 0x5); + UX_TEST_ASSERT(report_buffer_compressed[5] == 0x6); + + /** Test invalid usage page. **/ + + /* Get the first input report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + UX_TEST_CHECK_SUCCESS(ux_host_class_hid_report_id_get(hid, &report_id)); + input_report_descriptor = report_id.ux_host_class_hid_report_get_report; + + /* Add invalid usage page. */ + report_buffer_decompressed[0] = 0x00000000; + report_buffer_decompressed[1] = 0x00; + + /* Fill out the request for the compress api. */ + client_report.ux_host_class_hid_client_report = input_report_descriptor; + client_report.ux_host_class_hid_client_report_buffer = report_buffer_decompressed; + client_report.ux_host_class_hid_client_report_actual_length = 0; + + ignore_errors = 1; + + /* Request compression. This should fail. */ + UX_TEST_CHECK_NOT_SUCCESS(_ux_host_class_hid_report_compress(hid, &client_report, report_buffer_compressed, sizeof(report_buffer_compressed))); + + ignore_errors = 0; + + /** Test usage too large. **/ + + /* Get the first input report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + UX_TEST_CHECK_SUCCESS(ux_host_class_hid_report_id_get(hid, &report_id)); + input_report_descriptor = report_id.ux_host_class_hid_report_get_report; + + /* Add unknown usage. */ + report_buffer_decompressed[0] = 0x00070066; + report_buffer_decompressed[1] = 0x66; + + /* Fill out the request for the compress api. */ + client_report.ux_host_class_hid_client_report = input_report_descriptor; + client_report.ux_host_class_hid_client_report_buffer = report_buffer_decompressed; + client_report.ux_host_class_hid_client_report_actual_length = 0; + + ignore_errors = 1; + + /* Request compression. This should fail. */ + UX_TEST_CHECK_NOT_SUCCESS(_ux_host_class_hid_report_compress(hid, &client_report, report_buffer_compressed, sizeof(report_buffer_compressed))); + + ignore_errors = 0; + + /** Test usage too small. **/ + + /* Get the first input report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + UX_TEST_CHECK_SUCCESS(ux_host_class_hid_report_id_get(hid, &report_id)); + input_report_descriptor = report_id.ux_host_class_hid_report_get_report; + + /* Add unknown usage. */ + report_buffer_decompressed[0] = 0x00070000; + report_buffer_decompressed[1] = 0x0; + + /* Fill out the request for the compress api. */ + client_report.ux_host_class_hid_client_report = input_report_descriptor; + client_report.ux_host_class_hid_client_report_buffer = report_buffer_decompressed; + client_report.ux_host_class_hid_client_report_actual_length = 0; + + ignore_errors = 1; + + /* Request compression. This should fail. */ + UX_TEST_CHECK_NOT_SUCCESS(_ux_host_class_hid_report_compress(hid, &client_report, report_buffer_compressed, sizeof(report_buffer_compressed))); + + ignore_errors = 0; + + /* 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_hid_report_descriptor_compress_test.c b/test/regression/usbx_hid_report_descriptor_compress_test.c new file mode 100644 index 00000000..e83b8170 --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_compress_test.c @@ -0,0 +1,463 @@ +/* This test concentrates on the report compress api. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static UCHAR input_report_buffer_compressed[1024]; +static SLONG input_report_buffer_decompressed_original[1024]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + + /* First field */ + 0x09, 0x01, // USAGE (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* Second field */ + 0x19, 0x02, // USAGE_MINIMUM (2) + 0x29, 0x04, // USAGE_MAXIMUM (4) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* Third field */ + 0x0a, 0xcd, 0xab, // USAGE (0xabcd) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* Fourth field */ + 0x19, 0x06, // USAGE_MINIMUM (6) + 0x29, 0x08, // USAGE_MAXIMUM (8) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x03, // REPORT_COUNT (3) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* Fifth field */ + 0x09, 0x01, // USAGE (1) + 0x75, 0x09, // REPORT_SIZE (9) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* Sixth field */ + 0x19, 0x0a, // USAGE_MINIMUM (10) + 0x29, 0x0c, // USAGE_MAXIMUM (12) + 0x75, 0x09, // REPORT_SIZE (9) + 0x95, 0x03, // REPORT_COUNT (3) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* Seventh field */ + 0x09, 0x0d, // USAGE (13) + 0x75, 0x1f, // REPORT_SIZE (31) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* Eigth field */ + 0x09, 0x0e, // USAGE (14) + 0x75, 0x20, // REPORT_SIZE (32) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* USBX expects keyboards to have at least one output report, otherwise it's an error. */ + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + + 0xc0, // END_COLLECTION +}; +#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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_compress_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 Decompress 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; +UX_HOST_CLASS_HID_CLIENT_REPORT client_report; +UX_HOST_CLASS_HID_REPORT *input_report_descriptor; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the first input report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + input_report_descriptor = report_id.ux_host_class_hid_report_get_report; + if (input_report_descriptor -> ux_host_class_hid_report_id != 0) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* First field */ + + input_report_buffer_decompressed_original[0] = 0x00010001; + input_report_buffer_decompressed_original[1] = 0x01; + + /* Second field */ + + input_report_buffer_decompressed_original[2] = 0x00010002; + input_report_buffer_decompressed_original[3] = 0x01; + + input_report_buffer_decompressed_original[4] = 0x00010003; + input_report_buffer_decompressed_original[5] = 0x00; + + input_report_buffer_decompressed_original[6] = 0x00010004; + input_report_buffer_decompressed_original[7] = 0x01; + + /* Third field */ + + input_report_buffer_decompressed_original[8] = 0x0001abcd; + input_report_buffer_decompressed_original[9] = 0x30; + + /* Fourth field */ + + input_report_buffer_decompressed_original[10] = 0x00010006; + input_report_buffer_decompressed_original[11] = 0x52; + + input_report_buffer_decompressed_original[12] = 0x00010007; + input_report_buffer_decompressed_original[13] = 0x74; + + input_report_buffer_decompressed_original[14] = 0x00010008; + input_report_buffer_decompressed_original[15] = 0x96; + + /* Fifth field */ + + input_report_buffer_decompressed_original[16] = 0x00010001; + input_report_buffer_decompressed_original[17] = 0x0b8; + + /* Sixth field */ + + input_report_buffer_decompressed_original[18] = 0x0001000a; + input_report_buffer_decompressed_original[19] = 0x06d; + + input_report_buffer_decompressed_original[20] = 0x0001000b; + input_report_buffer_decompressed_original[21] = 0x1bf; + + input_report_buffer_decompressed_original[22] = 0x0001000c; + input_report_buffer_decompressed_original[23] = 0x003; + + /* Seventh field */ + + input_report_buffer_decompressed_original[24] = 0x0001000d; + input_report_buffer_decompressed_original[25] = 0x09674523; + + /* Eigth field */ + + input_report_buffer_decompressed_original[26] = 0x0001000e; + input_report_buffer_decompressed_original[27] = 0x03df9b57; + + /* Fill out the request for the decompress api. */ + client_report.ux_host_class_hid_client_report = input_report_descriptor; + client_report.ux_host_class_hid_client_report_buffer = input_report_buffer_decompressed_original; + client_report.ux_host_class_hid_client_report_actual_length = 0; + + /* Request compression. */ + status = _ux_host_class_hid_report_compress(hid, &client_report, input_report_buffer_compressed, 17); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Check output of report compression. */ + if ( + input_report_buffer_compressed[0] != 0x0b || + input_report_buffer_compressed[1] != 0x23 || + input_report_buffer_compressed[2] != 0x45 || + input_report_buffer_compressed[3] != 0x67 || + input_report_buffer_compressed[4] != 0x89 || + input_report_buffer_compressed[5] != 0xab || + input_report_buffer_compressed[6] != 0xcd || + input_report_buffer_compressed[7] != 0xef || + input_report_buffer_compressed[8] != 0x01 || + input_report_buffer_compressed[9] != 0x23 || + input_report_buffer_compressed[10] != 0x45 || + input_report_buffer_compressed[11] != 0x67 || + input_report_buffer_compressed[12] != 0x89 || + input_report_buffer_compressed[13] != 0xab || + input_report_buffer_compressed[14] != 0xcd || + input_report_buffer_compressed[15] != 0xef || + input_report_buffer_compressed[16] != 0x01 + ) + { + + printf("Error on line %d\n", __LINE__); + 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_hid_report_descriptor_decompress_array_test.c b/test/regression/usbx_hid_report_descriptor_decompress_array_test.c new file mode 100644 index 00000000..ca232756 --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_decompress_array_test.c @@ -0,0 +1,367 @@ +/* This test concentrates on the report decompression api when the report contains an array item. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static UCHAR report_buffer_compressed[1024]; +static SLONG report_buffer_decompressed[1024]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x06, // REPORT_COUNT (6) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + + /* USBX expects keyboards to have at least one output report, otherwise it's an error. */ + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + + 0xc0, // END_COLLECTION +}; +#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 + }; + + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_decompress_array_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 Decompress Array 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; +UX_HOST_CLASS_HID_CLIENT_REPORT input_report_request; +UX_HOST_CLASS_HID_REPORT *input_report_descriptor; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the first input report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + input_report_descriptor = report_id.ux_host_class_hid_report_get_report; + if (input_report_descriptor -> ux_host_class_hid_report_id != 0) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Fill out the request for the decompress api. */ + input_report_request.ux_host_class_hid_client_report = input_report_descriptor; + input_report_request.ux_host_class_hid_client_report_buffer = report_buffer_decompressed; + input_report_request.ux_host_class_hid_client_report_length = input_report_descriptor -> ux_host_class_hid_report_byte_length; + input_report_request.ux_host_class_hid_client_report_actual_length = 0; + input_report_request.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_DECOMPRESSED; + + /* Fill out report. */ + report_buffer_compressed[0] = 0x00; + report_buffer_compressed[1] = 0x10; + report_buffer_compressed[2] = 0x23; + report_buffer_compressed[3] = 0x37; + report_buffer_compressed[4] = 0x43; + report_buffer_compressed[5] = 0x65; + + /* Request decompression. */ + status = _ux_host_class_hid_report_decompress(hid, &input_report_request, report_buffer_compressed, 6); + + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Check output of decompression of report. */ + if ( + report_buffer_decompressed[0] != 0x00010000 || + report_buffer_decompressed[1] != 0x00 || + report_buffer_decompressed[2] != 0x00010010 || + report_buffer_decompressed[3] != 0x10 || + report_buffer_decompressed[4] != 0x00010023 || + report_buffer_decompressed[5] != 0x23 || + report_buffer_decompressed[6] != 0x00010037 || + report_buffer_decompressed[7] != 0x37 || + report_buffer_decompressed[8] != 0x00010043 || + report_buffer_decompressed[9] != 0x43 || + report_buffer_decompressed[10] != 0x00010065 || + report_buffer_decompressed[11] != 0x65 + ) + { + + printf("Error on line %d\n", __LINE__); + 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_hid_report_descriptor_decompress_test.c b/test/regression/usbx_hid_report_descriptor_decompress_test.c new file mode 100644 index 00000000..ad8a94f5 --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_decompress_test.c @@ -0,0 +1,500 @@ +/* This test concentrates on the report decompress api. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static UCHAR report_buffer_compressed_original[1024]; +static UCHAR report_buffer_compressed[1024]; +static SLONG report_buffer_decompressed[1024]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + + /* First field */ + 0x09, 0x01, // USAGE (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* Second field */ + 0x19, 0x02, // USAGE_MINIMUM (2) + 0x29, 0x04, // USAGE_MAXIMUM (4) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* Third field */ + 0x0a, 0xcd, 0xab, // USAGE (0xabcd) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* Fourth field */ + 0x19, 0x06, // USAGE_MINIMUM (6) + 0x29, 0x08, // USAGE_MAXIMUM (8) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x03, // REPORT_COUNT (3) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* Fifth field */ + 0x09, 0x01, // USAGE (1) + 0x75, 0x09, // REPORT_SIZE (9) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* Sixth field */ + 0x19, 0x0a, // USAGE_MINIMUM (10) + 0x29, 0x0c, // USAGE_MAXIMUM (12) + 0x75, 0x09, // REPORT_SIZE (9) + 0x95, 0x03, // REPORT_COUNT (3) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* Seventh field */ + 0x09, 0x0d, // USAGE (13) + 0x75, 0x1f, // REPORT_SIZE (31) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* Eigth field */ + 0x09, 0x0e, // USAGE (14) + 0x75, 0x20, // REPORT_SIZE (32) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* bits: 1 + 3 + 8 + 24 + 9 + 27 + 31 + 32 = 135; 17 bytes overall */ + + /* USBX expects keyboards to have at least one output report, otherwise it's an error. */ + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + + 0xc0, // END_COLLECTION +}; +#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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_decompress_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 Decompress 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_get_id; +UX_HOST_CLASS_HID_CLIENT_REPORT client_report; +UX_HOST_CLASS_HID_REPORT *hid_report; + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the first input report descriptor. */ + report_get_id.ux_host_class_hid_report_get_report = UX_NULL; + report_get_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = ux_host_class_hid_report_id_get(hid, &report_get_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + hid_report = report_get_id.ux_host_class_hid_report_get_report; + if (hid_report -> ux_host_class_hid_report_id != 0) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Fill out the request for the decompress api. */ + client_report.ux_host_class_hid_client_report = hid_report; + client_report.ux_host_class_hid_client_report_buffer = report_buffer_decompressed; + client_report.ux_host_class_hid_client_report_length = hid_report -> ux_host_class_hid_report_byte_length; + client_report.ux_host_class_hid_client_report_actual_length = 0; + + /* Fill out report. */ + report_buffer_compressed_original[0] = 0x0b; // [0] bits 1-8: 0000 1011 + report_buffer_compressed_original[1] = 0x23; // [1] bits 9-16: 0010 0011 + report_buffer_compressed_original[2] = 0x45; // [2] bits 17-24: 0100 0101 + report_buffer_compressed_original[3] = 0x67; // [3] bits 25-32: 0110 0111 + report_buffer_compressed_original[4] = 0x89; // [4] bits 33-40: 1000 1001 + report_buffer_compressed_original[5] = 0xab; // [5] bits 41-48: 1010 1011 + report_buffer_compressed_original[6] = 0xcd; // [6] bits 49-56: 1100 1101 + report_buffer_compressed_original[7] = 0xef; // [7] bits 57-64: 1110 1111 + report_buffer_compressed_original[8] = 0x01; // [8] bits 65-72: 0000 0001 + report_buffer_compressed_original[9] = 0x23; // [9] bits 73-80: 0010 0011 + report_buffer_compressed_original[10] = 0x45; // [10] bits 81-88: 0100 0101 + report_buffer_compressed_original[11] = 0x67; // [11] bits 89-96: 0110 0111 + report_buffer_compressed_original[12] = 0x89; // [12] bits 97-104: 1000 1001 + report_buffer_compressed_original[13] = 0xab; // [13] bits 105-112: 1010 1011 + report_buffer_compressed_original[14] = 0xcd; // [14] bits 113-120: 1100 1101 + report_buffer_compressed_original[15] = 0xef; // [15] bits 121-128: 1110 1111 + report_buffer_compressed_original[16] = 0x01; // [16] bits 129-136: 0000 0001 + + /* Request decompression. */ + status = _ux_host_class_hid_report_decompress(hid, &client_report, report_buffer_compressed_original, 17); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Check output of decompression of report. */ + if ( + /* First field */ + + /* bit 1 */ + report_buffer_decompressed[0] != 0x00010001 || + report_buffer_decompressed[1] != 0x01 || + + /* Second field */ + + /* bit 2 */ + report_buffer_decompressed[2] != 0x00010002 || + report_buffer_decompressed[3] != 0x01 || + + /* bit 3 */ + report_buffer_decompressed[4] != 0x00010003 || + report_buffer_decompressed[5] != 0x00 || + + /* bit 4 */ + report_buffer_decompressed[6] != 0x00010004 || + report_buffer_decompressed[7] != 0x01 || + + /* Third field */ + + /* bits 5-12 */ + report_buffer_decompressed[8] != 0x0001abcd || + report_buffer_decompressed[9] != 0x30 || + + /* Fourth field */ + + /* bits 13-20 */ + report_buffer_decompressed[10] != 0x00010006 || + report_buffer_decompressed[11] != 0x52 || + + /* bits 21-28 */ + report_buffer_decompressed[12] != 0x00010007 || + report_buffer_decompressed[13] != 0x74 || + + /* bits 29-36 */ + report_buffer_decompressed[14] != 0x00010008 || + report_buffer_decompressed[15] != 0x96 || + + /* Fifth field */ + + /* bits 37-45 */ + report_buffer_decompressed[16] != 0x00010001 || + report_buffer_decompressed[17] != 0x0b8 || + + /* Sixth field */ + + /* bits 46-54 - 0 0110 1101 */ + report_buffer_decompressed[18] != 0x0001000a || + report_buffer_decompressed[19] != 0x06d || + + /* bits 55-63 - 1 1011 1111 */ + report_buffer_decompressed[20] != 0x0001000b || + report_buffer_decompressed[21] != 0x1bf || + + /* bits 64-72 - 0 0000 0011 */ + report_buffer_decompressed[22] != 0x0001000c || + report_buffer_decompressed[23] != 0x003 || + + /* Seventh field */ + + /* bits 73-103 - 000 1001 0110 0111 0100 0101 0010 0011 */ + report_buffer_decompressed[24] != 0x0001000d || + report_buffer_decompressed[25] != 0x09674523 || + + /* Eigth field */ + + /* bits 104-135 - 0000 0011 1101 1111 1001 1011 0101 0111 */ + report_buffer_decompressed[26] != 0x0001000e || + report_buffer_decompressed[27] != 0x03df9b57 + ) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + +#if 0 + /* Now perform the inverse: compression. */ + status = _ux_host_class_hid_report_compress(hid, &client_report, report_buffer_compressed, 28); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* These should be the same (god help us). */ + if(ux_utility_memory_compare(report_buffer_compressed, report_buffer_compressed_original, 17) != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } +#endif + + /* 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_hid_report_descriptor_delimiter_nested_close_test.c b/test/regression/usbx_hid_report_descriptor_delimiter_nested_close_test.c new file mode 100644 index 00000000..e3110d30 --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_delimiter_nested_close_test.c @@ -0,0 +1,304 @@ +/* This test ensures that the parser generates an error upon encountering an invalid close delimiter tag. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static UINT callback_error_code; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0xa9, 0x01, // DELIMITER (Open) + 0x0b, 0x20, 0x00, 0x05, 0x00, // USAGE (Gaming Controls:Point of View) + 0x0b, 0x39, 0x00, 0x01, 0x00, // USAGE (Generic Desktop:Hat switch) + 0x0b, 0x20, 0x00, 0x05, 0x00, // USAGE (Gaming Controls:Point of View) + 0xa9, 0x00, // DELIMITER (Close) + /* Add an extra invalid delimiter close tag. */ + 0xa9, 0x00, // DELIMITER (Close) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x03, // LOGICAL_MAXIMUM (3) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x46, 0x0e, 0x01, // PHYSICAL_MAXIMUM (270) + 0x65, 0x14, // UNIT (Eng Rot:Angular Pos) + 0x55, 0x00, // UNIT_EXPONENT (0) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_HOST_CLASS_HID_DELIMITER_ERROR && + 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_hid_report_descriptor_delimiter_nested_close_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 Delimiter Nested Close 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); + } + + /* 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); +} \ No newline at end of file diff --git a/test/regression/usbx_hid_report_descriptor_delimiter_nested_open_test.c b/test/regression/usbx_hid_report_descriptor_delimiter_nested_open_test.c new file mode 100644 index 00000000..cce8d21b --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_delimiter_nested_open_test.c @@ -0,0 +1,305 @@ +/* This test ensures that the parser generates an error upon encountering a nested delimiter. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static UINT callback_error_code; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0xa9, 0x01, // DELIMITER (Open) + /* Add a nested delimiter tag. */ + 0xa9, 0x01, // DELIMITER (Open) + 0x0b, 0x20, 0x00, 0x05, 0x00, // USAGE (Gaming Controls:Point of View) + 0x0b, 0x39, 0x00, 0x01, 0x00, // USAGE (Generic Desktop:Hat switch) + 0x0b, 0x20, 0x00, 0x05, 0x00, // USAGE (Gaming Controls:Point of View) + 0xa9, 0x00, // DELIMITER (Close) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x03, // LOGICAL_MAXIMUM (3) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x46, 0x0e, 0x01, // PHYSICAL_MAXIMUM (270) + 0x65, 0x14, // UNIT (Eng Rot:Angular Pos) + 0x55, 0x00, // UNIT_EXPONENT (0) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_HOST_CLASS_HID_DELIMITER_ERROR && + 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_hid_report_descriptor_delimiter_nested_open_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 Delimiter Nested Open 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); + } + + /* 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); +} \ No newline at end of file diff --git a/test/regression/usbx_hid_report_descriptor_delimiter_test.c b/test/regression/usbx_hid_report_descriptor_delimiter_test.c new file mode 100644 index 00000000..23113312 --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_delimiter_test.c @@ -0,0 +1,337 @@ +/* This test ensures that the parser handles the delimiter item. At the time this test was written, + the parser only sets a flag indicating that a delimiter item has been encountered, but does nothing + else with the flag. */ + +#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) + 0xa9, 0x01, // DELIMITER (Open) + 0x0b, 0x20, 0x00, 0x05, 0x00, // USAGE (Gaming Controls:Point of View) + 0x0b, 0x39, 0x00, 0x01, 0x00, // USAGE (Generic Desktop:Hat switch) + 0x0b, 0x20, 0x00, 0x05, 0x00, // USAGE (Gaming Controls:Point of View) + 0xa9, 0x00, // DELIMITER (Close) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x03, // LOGICAL_MAXIMUM (3) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x46, 0x0e, 0x01, // PHYSICAL_MAXIMUM (270) + 0x65, 0x14, // UNIT (Eng Rot:Angular Pos) + 0x55, 0x00, // UNIT_EXPONENT (0) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* USBX expects keyboards to have at least one output report, otherwise it's an error. */ + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + + 0xc0 // END_COLLECTION +}; +#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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_delimiter_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 Delimiter 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; +UX_HOST_CLASS_HID_FIELD *report_field; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the input report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Check the field in the report. */ + report_field = report_id.ux_host_class_hid_report_get_report -> ux_host_class_hid_report_field; + if( + report_field -> ux_host_class_hid_field_logical_min != 0 || + report_field -> ux_host_class_hid_field_logical_max != 3 || + report_field -> ux_host_class_hid_field_physical_min != 0 || + report_field -> ux_host_class_hid_field_physical_max != 270 || + report_field -> ux_host_class_hid_field_unit != 0x14 || + report_field -> ux_host_class_hid_field_unit_expo != 0 || + report_field -> ux_host_class_hid_field_report_id != 0 || + report_field -> ux_host_class_hid_field_report_count != 1 || + report_field -> ux_host_class_hid_field_report_size != 4 + ) + { + printf("Error on line %d\n", __LINE__); + 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); +} \ No newline at end of file diff --git a/test/regression/usbx_hid_report_descriptor_delimiter_unknown_test.c b/test/regression/usbx_hid_report_descriptor_delimiter_unknown_test.c new file mode 100644 index 00000000..0e0382bd --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_delimiter_unknown_test.c @@ -0,0 +1,304 @@ +/* This test ensures that the parser generates an error upon encountering an unknown delimiter tag. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static UINT callback_error_code; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + /* Use an unknown delimiter value (0x02). */ + 0xa9, 0x02, // DELIMITER (???) + 0x0b, 0x20, 0x00, 0x05, 0x00, // USAGE (Gaming Controls:Point of View) + 0x0b, 0x39, 0x00, 0x01, 0x00, // USAGE (Generic Desktop:Hat switch) + 0x0b, 0x20, 0x00, 0x05, 0x00, // USAGE (Gaming Controls:Point of View) + 0xa9, 0x00, // DELIMITER (Close) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x03, // LOGICAL_MAXIMUM (3) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x46, 0x0e, 0x01, // PHYSICAL_MAXIMUM (270) + 0x65, 0x14, // UNIT (Eng Rot:Angular Pos) + 0x55, 0x00, // UNIT_EXPONENT (0) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +static void tx_demo_thread_host_simulation_entry(ULONG arg); + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_HOST_CLASS_HID_DELIMITER_ERROR && + 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_hid_report_descriptor_delimiter_unknown_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 Delimiter Unknown 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); + } + + /* 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); +} \ No newline at end of file diff --git a/test/regression/usbx_hid_report_descriptor_end_collection_error_test.c b/test/regression/usbx_hid_report_descriptor_end_collection_error_test.c new file mode 100644 index 00000000..76b4b3d5 --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_end_collection_error_test.c @@ -0,0 +1,294 @@ +/* This test ensures that the parser fails when too many end collections are used. */ + +#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 + + /* Extra end collection. */ + 0xc0, // END_COLLECTION +}; +#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 + }; + + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + 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_hid_report_descriptor_end_collection_error_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 End Collection Error 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); + } + + /* 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_hid_report_descriptor_example_andisplay_test.c b/test/regression/usbx_hid_report_descriptor_example_andisplay_test.c new file mode 100644 index 00000000..72a2a992 --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_example_andisplay_test.c @@ -0,0 +1,364 @@ +/* This test ensures that the parser handles the example andisplay report descriptor + from the USB HID report descriptor tool. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x14, // USAGE_PAGE (Alphnumeric Display) + 0x09, 0x01, // USAGE (Alphanumeric Display) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0xa1, 0x02, // COLLECTION (Logical) + 0x09, 0x20, // USAGE (Display Attributes Report) + 0xa1, 0x02, // COLLECTION (Logical) + 0x09, 0x35, // USAGE (Rows) + 0x09, 0x36, // USAGE (Columns) + 0x09, 0x3d, // USAGE (Character Width) + 0x09, 0x3e, // USAGE (Character Height) + 0x85, 0x01, // REPORT_ID (1) + 0x25, 0x1f, // LOGICAL_MAXIMUM (31) + 0x75, 0x05, // REPORT_SIZE (5) + 0x95, 0x04, // REPORT_COUNT (4) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x09, 0x21, // USAGE (ASCII Character Set) + 0x09, 0x22, // USAGE (Data Read Back) + 0x09, 0x29, // USAGE (Vertical Scroll) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0xc0, // END_COLLECTION + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x25, 0x02, // LOGICAL_MAXIMUM (2) + 0x09, 0x2d, // USAGE (Display Status) + 0xa1, 0x02, // COLLECTION (Logical) + 0x09, 0x2e, // USAGE (Stat Not Ready) + 0x09, 0x2f, // USAGE (Stat Ready) + 0x09, 0x30, // USAGE (Err Not a loadable character) + 0x81, 0x40, // INPUT (Data,Ary,Abs,Null) + 0xc0, // END_COLLECTION + 0x09, 0x32, // USAGE (Cursor Position Report) + 0xa1, 0x02, // COLLECTION (Logical) + 0x85, 0x02, // REPORT_ID (2) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x25, 0x0f, // LOGICAL_MAXIMUM (15) + 0x09, 0x34, // USAGE (Column) + 0xb1, 0x22, // FEATURE (Data,Var,Abs,NPrf) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x09, 0x33, // USAGE (Row) + 0xb1, 0x22, // FEATURE (Data,Var,Abs,NPrf) + 0xc0, // END_COLLECTION + 0x09, 0x2b, // USAGE (Character Report) + 0xa1, 0x02, // COLLECTION (Logical) + 0x85, 0x03, // REPORT_ID (3) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x04, // REPORT_COUNT (4) + 0x25, 0x7e, // LOGICAL_MAXIMUM (126) + 0x09, 0x2c, // USAGE (Display Data) + 0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf) + 0xc0, // END_COLLECTION + 0x85, 0x04, // REPORT_ID (4) + 0x09, 0x3b, // USAGE (Font Report) + 0xa1, 0x02, // COLLECTION (Logical) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x7e, // LOGICAL_MAXIMUM (126) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x09, 0x2c, // USAGE (Display Data) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x09, 0x3c, // USAGE (Font Data) + 0x92, 0x02, 0x01, // OUTPUT (Data,Var,Abs,Buf) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* USBX currently doesn't support this device. However, USBX parses the report descriptor before searching for clients, so this isn't a waste of time. */ + if (error_code != UX_HOST_CLASS_HID_UNKNOWN) + { + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_example_andisplay_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 Example andisplay 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); + } + + /* 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the input report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Do minimal error-checking. */ + if (report_id.ux_host_class_hid_report_get_report == UX_NULL) + { + + printf("Error on line %d\n", __LINE__); + 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_hid_report_descriptor_example_delimit_test.c b/test/regression/usbx_hid_report_descriptor_example_delimit_test.c new file mode 100644 index 00000000..cf0aad6b --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_example_delimit_test.c @@ -0,0 +1,362 @@ +/* This test ensures that the parser handles the example delmit report descriptor + from the USB HID report descriptor tool. */ + +#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, 0x04, // USAGE (Joystick) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x02, // USAGE_PAGE (Simulation Controls) + 0x09, 0xbb, // USAGE (Throttle) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xa9, 0x01, // DELIMITER (Open) + 0x09, 0x20, // USAGE (Flight Control Stick) + 0x0b, 0x01, 0x00, 0x01, 0x00, // USAGE (Generic Desktop:Pointer) + 0xa9, 0x00, // DELIMITER (Close) + 0xa1, 0x00, // COLLECTION (Physical) + 0x0b, 0x30, 0x00, 0x01, 0x00, // USAGE (Generic Desktop:X) + 0x0b, 0x31, 0x00, 0x01, 0x00, // USAGE (Generic Desktop:Y) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION + 0xa9, 0x01, // DELIMITER (Open) + 0x0b, 0x20, 0x00, 0x05, 0x00, // USAGE (Gaming Controls:Point of View) + 0x0b, 0x39, 0x00, 0x01, 0x00, // USAGE (Generic Desktop:Hat switch) + 0xa9, 0x00, // DELIMITER (Close) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x03, // LOGICAL_MAXIMUM (3) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x46, 0x0e, 0x01, // PHYSICAL_MAXIMUM (270) + 0x65, 0x14, // UNIT (Eng Rot:Angular Pos) + 0x55, 0x00, // UNIT_EXPONENT (0) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xa9, 0x01, // DELIMITER (Open) + 0x0b, 0x01, 0x00, 0x09, 0x00, // USAGE (Button:Button 1) + 0x09, 0xc0, // USAGE (Trigger) + 0xa9, 0x00, // DELIMITER (Close) + 0xa9, 0x01, // DELIMITER (Open) + 0x0b, 0x02, 0x00, 0x09, 0x00, // USAGE (Button:Button 2) + 0x09, 0xc2, // USAGE (Weapons Select) + 0xa9, 0x00, // DELIMITER (Close) + 0xa9, 0x01, // DELIMITER (Open) + 0x0b, 0x03, 0x00, 0x09, 0x00, // USAGE (Button:Button 3) + 0x09, 0xb7, // USAGE (Electronic Counter Measures) + 0x09, 0xbd, // USAGE (Flare Release) + 0xa9, 0x00, // DELIMITER (Close) + 0xa9, 0x01, // DELIMITER (Open) + 0x0b, 0x04, 0x00, 0x09, 0x00, // USAGE (Button:Button 4) + 0x09, 0xbe, // USAGE (Landing Gear) + 0x09, 0xb4, // USAGE (Chaff Release) + 0xa9, 0x00, // DELIMITER (Close) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x45, 0x01, // PHYSICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x04, // REPORT_COUNT (4) + 0x65, 0x00, // UNIT (None) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* USBX currently doesn't support this device. However, USBX parses the report descriptor before searching for clients, so this isn't a waste of time. */ + if (error_code != UX_HOST_CLASS_HID_UNKNOWN) + { + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_example_delimit_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running HID Report Descriptor Example delimit 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the input report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Do minimal error-checking. */ + if (report_id.ux_host_class_hid_report_get_report == UX_NULL) + { + + printf("Error on line %d\n", __LINE__); + 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_hid_report_descriptor_example_digit_test.c b/test/regression/usbx_hid_report_descriptor_example_digit_test.c new file mode 100644 index 00000000..ff79f675 --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_example_digit_test.c @@ -0,0 +1,396 @@ +/* This test ensures that the parser handles the example digit report descriptor + from the USB HID report descriptor tool. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x0d, // USAGE_PAGE (Digitizers) + 0x09, 0x01, // USAGE (Digitizer) + 0xa1, 0x01, // COLLECTION (Application) + 0x85, 0x01, // REPORT_ID (1) + 0x09, 0x21, // USAGE (Puck) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x75, 0x10, // REPORT_SIZE (16) + 0x95, 0x02, // REPORT_COUNT (2) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xe0, 0x2e, // LOGICAL_MAXIMUM (12000) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x45, 0x0c, // PHYSICAL_MAXIMUM (12) + 0x65, 0x13, // UNIT (Eng Lin:Distance) + 0x55, 0x00, // UNIT_EXPONENT (0) + 0xa4, // PUSH + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x05, 0x0d, // USAGE_PAGE (Digitizers) + 0x09, 0x32, // USAGE (In Range) + 0x09, 0x44, // USAGE (Barrel Switch) + 0x09, 0x42, // USAGE (Tip Switch) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x45, 0x01, // PHYSICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x65, 0x00, // UNIT (None) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0xc0, // END_COLLECTION + 0x85, 0x02, // REPORT_ID (2) + 0x09, 0x20, // USAGE (Stylus) + 0xa1, 0x00, // COLLECTION (Physical) + 0xb4, // POP + 0xa4, // PUSH + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x05, 0x0d, // USAGE_PAGE (Digitizers) + 0x09, 0x32, // USAGE (In Range) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x45, 0x01, // PHYSICAL_MAXIMUM (1) + 0x65, 0x00, // UNIT (None) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x00, // USAGE_MINIMUM (No Buttons Pressed) + 0x29, 0x10, // USAGE_MAXIMUM (Button 16) + 0x25, 0x10, // LOGICAL_MAXIMUM (16) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x40, // INPUT (Data,Ary,Abs,Null) + 0x75, 0x02, // REPORT_SIZE (2) + 0x81, 0x01, // INPUT (Cnst,Ary,Abs) + 0xc0, // END_COLLECTION + 0x85, 0x03, // REPORT_ID (3) + 0x05, 0x0d, // USAGE_PAGE (Digitizers) + 0x09, 0x20, // USAGE (Stylus) + 0xa1, 0x00, // COLLECTION (Physical) + 0xb4, // POP + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x05, 0x0d, // USAGE_PAGE (Digitizers) + 0x09, 0x32, // USAGE (In Range) + 0x09, 0x44, // USAGE (Barrel Switch) + 0x75, 0x01, // REPORT_SIZE (1) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x45, 0x01, // PHYSICAL_MAXIMUM (1) + 0x65, 0x00, // UNIT (None) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x09, 0x30, // USAGE (Tip Pressure) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x45, 0x2d, // PHYSICAL_MAXIMUM (45) + 0x67, 0x11, 0xe1, 0x00, 0x00, // UNIT (SI Lin:Force) + 0x55, 0x04, // UNIT_EXPONENT (4) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x12, // INPUT (Data,Var,Abs,NLin) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* USBX currently doesn't support this device. However, USBX parses the report descriptor before searching for clients, so this isn't a waste of time. */ + if (error_code != UX_HOST_CLASS_HID_UNKNOWN) + { + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_example_digit_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 Example digit 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the input report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Do minimal error-checking. */ + if (report_id.ux_host_class_hid_report_get_report == UX_NULL) + { + + printf("Error on line %d\n", __LINE__); + 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_hid_report_descriptor_example_display_test.c b/test/regression/usbx_hid_report_descriptor_example_display_test.c new file mode 100644 index 00000000..7e3aee15 --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_example_display_test.c @@ -0,0 +1,372 @@ +/* This test ensures that the parser handles the example display report descriptor + from the USB HID report descriptor tool. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x14, // USAGE_PAGE (Alphnumeric Display) + 0x09, 0x01, // USAGE (Alphanumeric Display) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0xa1, 0x02, // COLLECTION (Logical) + 0x09, 0x20, // USAGE (Display Attributes Report) + 0xa1, 0x02, // COLLECTION (Logical) + 0x09, 0x35, // USAGE (Rows) + 0x09, 0x36, // USAGE (Columns) + 0x09, 0x3d, // USAGE (Character Width) + 0x09, 0x3e, // USAGE (Character Height) + 0x85, 0x01, // REPORT_ID (1) + 0x25, 0x1f, // LOGICAL_MAXIMUM (31) + 0x75, 0x05, // REPORT_SIZE (5) + 0x95, 0x04, // REPORT_COUNT (4) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x09, 0x21, // USAGE (ASCII Character Set) + 0x09, 0x22, // USAGE (Data Read Back) + 0x09, 0x29, // USAGE (Vertical Scroll) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x95, 0x03, // REPORT_COUNT (3) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0xc0, // END_COLLECTION + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x25, 0x02, // LOGICAL_MAXIMUM (2) + 0x09, 0x2d, // USAGE (Display Status) + 0xa1, 0x02, // COLLECTION (Logical) + 0x09, 0x2e, // USAGE (Stat Not Ready) + 0x09, 0x2f, // USAGE (Stat Ready) + 0x09, 0x30, // USAGE (Err Not a loadable character) + 0x81, 0x40, // INPUT (Data,Ary,Abs,Null) + 0xc0, // END_COLLECTION + 0x09, 0x32, // USAGE (Cursor Position Report) + 0xa1, 0x02, // COLLECTION (Logical) + 0x85, 0x02, // REPORT_ID (2) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x25, 0x0f, // LOGICAL_MAXIMUM (15) + 0x09, 0x34, // USAGE (Column) + 0xb1, 0x22, // FEATURE (Data,Var,Abs,NPrf) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x09, 0x33, // USAGE (Row) + 0xb1, 0x22, // FEATURE (Data,Var,Abs,NPrf) + 0xc0, // END_COLLECTION + 0x09, 0x2b, // USAGE (Character Report) + 0xa1, 0x02, // COLLECTION (Logical) + 0x85, 0x03, // REPORT_ID (3) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x04, // REPORT_COUNT (4) + 0x25, 0x7e, // LOGICAL_MAXIMUM (126) + 0x09, 0x2c, // USAGE (Display Data) + 0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf) + 0xc0, // END_COLLECTION + 0x85, 0x04, // REPORT_ID (4) + 0x09, 0x3b, // USAGE (Font Report) + 0xa1, 0x02, // COLLECTION (Logical) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x7e, // LOGICAL_MAXIMUM (126) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x09, 0x2c, // USAGE (Display Data) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x09, 0x3c, // USAGE (Font Data) + 0x92, 0x02, 0x01, // OUTPUT (Data,Var,Abs,Buf) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* USBX currently doesn't support this device. However, USBX parses the report descriptor before searching for clients, so this isn't a waste of time. */ + if (error_code != UX_HOST_CLASS_HID_UNKNOWN) + { + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_example_display_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running HID Report Descriptor Example display 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the input report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Do minimal error-checking. */ + if (report_id.ux_host_class_hid_report_get_report == UX_NULL) + { + + printf("Error on line %d\n", __LINE__); + 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_hid_report_descriptor_example_joystk_test.c b/test/regression/usbx_hid_report_descriptor_example_joystk_test.c new file mode 100644 index 00000000..0af02746 --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_example_joystk_test.c @@ -0,0 +1,342 @@ +/* This test ensures that the parser handles the example joystk report descriptor + from the USB HID report descriptor tool. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x09, 0x04, // USAGE (Joystick) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x02, // USAGE_PAGE (Simulation Controls) + 0x09, 0xbb, // USAGE (Throttle) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION + 0x09, 0x39, // USAGE (Hat switch) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x03, // LOGICAL_MAXIMUM (3) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x46, 0x0e, 0x01, // PHYSICAL_MAXIMUM (270) + 0x65, 0x14, // UNIT (Eng Rot:Angular Pos) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x04, // USAGE_MAXIMUM (Button 4) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x04, // REPORT_COUNT (4) + 0x55, 0x00, // UNIT_EXPONENT (0) + 0x65, 0x00, // UNIT (None) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* USBX currently doesn't support this device. However, USBX parses the report descriptor before searching for clients, so this isn't a waste of time. */ + if (error_code != UX_HOST_CLASS_HID_UNKNOWN) + { + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_example_joystk_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 Example joystk 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the input report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Do minimal error-checking. */ + if (report_id.ux_host_class_hid_report_get_report == UX_NULL) + { + + printf("Error on line %d\n", __LINE__); + 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); +} \ No newline at end of file diff --git a/test/regression/usbx_hid_report_descriptor_example_keybrd_test.c b/test/regression/usbx_hid_report_descriptor_example_keybrd_test.c new file mode 100644 index 00000000..5391e0d7 --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_example_keybrd_test.c @@ -0,0 +1,329 @@ +/* This test ensures that the parser handles the example keybrd report descriptor + from the USB HID report descriptor tool. */ + +#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) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_example_keybrd_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 Example keybrd 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the input report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Do minimal error-checking. */ + if (report_id.ux_host_class_hid_report_get_report == UX_NULL) + { + + printf("Error on line %d\n", __LINE__); + 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_hid_report_descriptor_example_monitor_test.c b/test/regression/usbx_hid_report_descriptor_example_monitor_test.c new file mode 100644 index 00000000..1cc78fc2 --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_example_monitor_test.c @@ -0,0 +1,347 @@ +/* This test ensures that the parser handles the example monitor report descriptor + from the USB HID report descriptor tool. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x80, // USAGE_PAGE (Monitor) + 0x09, 0x01, // USAGE (Monitor Control) + 0xa1, 0x01, // COLLECTION (Application) + 0x85, 0x01, // REPORT_ID (1) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x80, // REPORT_COUNT (128) + 0x09, 0x02, // USAGE (EDID Information) + 0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf) + 0x85, 0x02, // REPORT_ID (2) + 0x95, 0xf3, // REPORT_COUNT (243) + 0x09, 0x03, // USAGE (VDIF Information) + 0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf) + 0x85, 0x03, // REPORT_ID (3) + 0x05, 0x82, // USAGE_PAGE (VESA Virtual Controls) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x10, // REPORT_SIZE (16) + 0x26, 0xc8, 0x00, // LOGICAL_MAXIMUM (200) + 0x09, 0x10, // USAGE (Brightness) + 0xb1, 0x02, // FEATURE (Data,Var,Abs) + 0x85, 0x04, // REPORT_ID (4) + 0x25, 0x64, // LOGICAL_MAXIMUM (100) + 0x09, 0x12, // USAGE (Contrast) + 0xb1, 0x02, // FEATURE (Data,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x09, 0x16, // USAGE (Video Gain Red) + 0x09, 0x18, // USAGE (Video Gain Green) + 0x09, 0x1a, // USAGE (Video Gain Blue) + 0x09, 0x6c, // USAGE (Video Black Level Red) + 0x09, 0x6e, // USAGE (Video Black Level Green) + 0x09, 0x70, // USAGE (Video Black Level Blue) + 0xb1, 0x02, // FEATURE (Data,Var,Abs) + 0x85, 0x05, // REPORT_ID (5) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x09, 0x20, // USAGE (Horizontal Position ) + 0x09, 0x22, // USAGE (Horizontal Size ) + 0x09, 0x30, // USAGE (Vertical Position ) + 0x09, 0x32, // USAGE (Vertical Size ) + 0x09, 0x42, // USAGE (Trapezoidal Distortion) + 0x09, 0x44, // USAGE (Tilt) + 0xb1, 0x02, // FEATURE (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* USBX currently doesn't support this device. However, USBX parses the report descriptor before searching for clients, so this isn't a waste of time. */ + if (error_code != UX_HOST_CLASS_HID_UNKNOWN) + { + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_example_monitor_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 Example monitor 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d. ERROR 0\n", __LINE__); + test_control_return(1); + } + + /* Get the input report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_FEATURE; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d. ERROR 1\n", __LINE__); + test_control_return(1); + } + + /* Do minimal error-checking. */ + if (report_id.ux_host_class_hid_report_get_report == UX_NULL) + { + + printf("Error on line %d. ERROR 2\n", __LINE__); + 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_hid_report_descriptor_example_mouse_test.c b/test/regression/usbx_hid_report_descriptor_example_mouse_test.c new file mode 100644 index 00000000..c25cc0dc --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_example_mouse_test.c @@ -0,0 +1,324 @@ +/* This test ensures that the parser handles the example mouse report descriptor + from the USB HID report descriptor tool. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_mouse.h" + + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_example_mouse_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 Example mouse 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_mouse_name, ux_host_class_hid_mouse_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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the input report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Do minimal error-checking. */ + if (report_id.ux_host_class_hid_report_get_report == UX_NULL) + { + + printf("Error on line %d\n", __LINE__); + 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_hid_report_descriptor_example_pwr_test.c b/test/regression/usbx_hid_report_descriptor_example_pwr_test.c new file mode 100644 index 00000000..db557d5b --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_example_pwr_test.c @@ -0,0 +1,729 @@ +/* This test ensures that the parser handles the example pwr report descriptor + from the USB HID report descriptor tool. Why direct: the device's control transfer + data buffer's default size (256 bytes) is not large enough for this report + descriptor (over 800 bytes); thus, we reallocate the buffer with a larger size. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x84, // USAGE_PAGE (Power Device) + 0x09, 0x04, // USAGE (UPS) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x1e, // USAGE (Flow) + 0xa1, 0x02, // COLLECTION (Logical) + 0x85, 0x01, // REPORT_ID (1) + 0x09, 0x1f, // USAGE (FlowID) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x0f, // LOGICAL_MAXIMUM (15) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x09, 0x01, // USAGE (iName) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x09, 0x40, // USAGE (ConfigVoltage) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x67, 0x21, 0xd1, 0xf0, 0x00, // UNIT (SI Lin:Volts) + 0x55, 0x07, // UNIT_EXPONENT (7) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xfa, 0x00, // LOGICAL_MAXIMUM (250) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x09, 0x42, // USAGE (ConfigFrequency) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x66, 0x01, 0xf0, // UNIT (SI Lin:Hertz) + 0x55, 0x00, // UNIT_EXPONENT (0) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x3c, // LOGICAL_MAXIMUM (60) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x65, 0x00, // UNIT (None) + 0xc0, // END_COLLECTION + 0x09, 0x1e, // USAGE (Flow) + 0xa1, 0x02, // COLLECTION (Logical) + 0x85, 0x02, // REPORT_ID (2) + 0x09, 0x1f, // USAGE (FlowID) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x0f, // LOGICAL_MAXIMUM (15) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x09, 0x01, // USAGE (iName) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x09, 0x40, // USAGE (ConfigVoltage) + 0x75, 0x10, // REPORT_SIZE (16) + 0x95, 0x01, // REPORT_COUNT (1) + 0x67, 0x21, 0xd1, 0xf0, 0x00, // UNIT (SI Lin:Volts) + 0x55, 0x05, // UNIT_EXPONENT (5) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x27, 0xfe, 0xff, 0x00, 0x00, // LOGICAL_MAXIMUM (65534) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x09, 0x42, // USAGE (ConfigFrequency) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x66, 0x01, 0xf0, // UNIT (SI Lin:Hertz) + 0x55, 0x00, // UNIT_EXPONENT (0) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x60, // LOGICAL_MAXIMUM (96) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x65, 0x00, // UNIT (None) + 0xc0, // END_COLLECTION + 0x09, 0x1e, // USAGE (Flow) + 0xa1, 0x02, // COLLECTION (Logical) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x0f, // LOGICAL_MAXIMUM (15) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x09, 0x01, // USAGE (iName) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x09, 0x40, // USAGE (ConfigVoltage) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x67, 0x21, 0xd1, 0xf0, 0x00, // UNIT (SI Lin:Volts) + 0x55, 0x07, // UNIT_EXPONENT (7) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xfa, 0x00, // LOGICAL_MAXIMUM (250) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x09, 0x42, // USAGE (ConfigFrequency) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x66, 0x01, 0xf0, // UNIT (SI Lin:Hertz) + 0x55, 0x00, // UNIT_EXPONENT (0) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x3c, // LOGICAL_MAXIMUM (60) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x09, 0x43, // USAGE (ConfigApparentPower) + 0x75, 0x10, // REPORT_SIZE (16) + 0x95, 0x01, // REPORT_COUNT (1) + 0x66, 0x21, 0xd1, // UNIT (SI Lin:Power) + 0x55, 0x07, // UNIT_EXPONENT (7) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x27, 0xfe, 0xff, 0x00, 0x00, // LOGICAL_MAXIMUM (65534) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x65, 0x00, // UNIT (None) + 0xc0, // END_COLLECTION + 0x09, 0x10, // USAGE (BatterySystem) + 0xa1, 0x02, // COLLECTION (Logical) + 0x85, 0x04, // REPORT_ID (4) + 0x09, 0x11, // USAGE (BatterySystemID) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x0f, // LOGICAL_MAXIMUM (15) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x09, 0x1a, // USAGE (Input) + 0xa1, 0x02, // COLLECTION (Logical) + 0x09, 0x1b, // USAGE (InputID) + 0x09, 0x1f, // USAGE (FlowID) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x02, // REPORT_COUNT (2) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x0f, // LOGICAL_MAXIMUM (15) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x09, 0x02, // USAGE (PresentStatus) + 0xa1, 0x02, // COLLECTION (Logical) + 0x09, 0x6d, // USAGE (Used) + 0x09, 0x61, // USAGE (Good) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x02, // REPORT_COUNT (2) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0xc0, // END_COLLECTION + 0x09, 0x03, // USAGE (ChangedStatus) + 0xa1, 0x02, // COLLECTION (Logical) + 0x09, 0x6d, // USAGE (Used) + 0x09, 0x61, // USAGE (Good) + 0x75, 0x02, // REPORT_SIZE (2) + 0x95, 0x02, // REPORT_COUNT (2) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION + 0x09, 0x14, // USAGE (Charger) + 0xa1, 0x02, // COLLECTION (Logical) + 0x85, 0x05, // REPORT_ID (5) + 0x09, 0x15, // USAGE (ChargerID) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x0f, // LOGICAL_MAXIMUM (15) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0xc0, // END_COLLECTION + 0x09, 0x1c, // USAGE (Output) + 0xa1, 0x02, // COLLECTION (Logical) + 0x09, 0x1d, // USAGE (OutputID) + 0x09, 0x1f, // USAGE (FlowID) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x02, // REPORT_COUNT (2) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x0f, // LOGICAL_MAXIMUM (15) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0xc0, // END_COLLECTION + 0x09, 0x12, // USAGE (Battery) + 0xa1, 0x02, // COLLECTION (Logical) + 0x85, 0x06, // REPORT_ID (6) + 0x09, 0x13, // USAGE (BatteryID) + 0x85, 0x04, // REPORT_ID (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x0f, // LOGICAL_MAXIMUM (15) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x05, 0x85, // USAGE_PAGE (Battery System) + 0x09, 0x2c, // USAGE (CapacityMode) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x01, // REPORT_COUNT (1) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x75, 0x03, // REPORT_SIZE (3) + 0x95, 0x01, // REPORT_COUNT (1) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x09, 0x83, // USAGE (DesignCapacity) + 0x75, 0x18, // REPORT_SIZE (24) + 0x95, 0x01, // REPORT_COUNT (1) + 0x67, 0x01, 0x10, 0x10, 0x00, // UNIT (SI Lin:Battery Capacity) + 0x55, 0x00, // UNIT_EXPONENT (0) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x27, 0xfe, 0xff, 0xff, 0x00, // LOGICAL_MAXIMUM (16777214) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x05, 0x84, // USAGE_PAGE (Power Device) + 0x09, 0x40, // USAGE (ConfigVoltage) + 0x75, 0x10, // REPORT_SIZE (16) + 0x95, 0x01, // REPORT_COUNT (1) + 0x67, 0x21, 0xd1, 0xf0, 0x00, // UNIT (SI Lin:Volts) + 0x55, 0x05, // UNIT_EXPONENT (5) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x27, 0xfe, 0xff, 0x00, 0x00, // LOGICAL_MAXIMUM (65534) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x05, 0x85, // USAGE_PAGE (Battery System) + 0x09, 0x29, // USAGE (RemainingCapacityLimit) + 0x75, 0x24, // REPORT_SIZE (36) + 0x95, 0x01, // REPORT_COUNT (1) + 0x67, 0x01, 0x10, 0x10, 0x00, // UNIT (SI Lin:Battery Capacity) + 0x55, 0x00, // UNIT_EXPONENT (0) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x27, 0xfe, 0xff, 0xff, 0x00, // LOGICAL_MAXIMUM (16777214) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x65, 0x00, // UNIT (None) + 0x05, 0x84, // USAGE_PAGE (Power Device) + 0x09, 0x02, // USAGE (PresentStatus) + 0xa1, 0x02, // COLLECTION (Logical) + 0x05, 0x85, // USAGE_PAGE (Battery System) + 0x0b, 0x61, 0x00, 0x84, 0x00, // USAGE (Power Device:Good) + 0x09, 0x42, // USAGE (BelowRemainingCapacityLimit) + 0x09, 0x44, // USAGE (Charging) + 0x09, 0x45, // USAGE (Discharging) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x04, // REPORT_COUNT (4) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0xb1, 0x02, // FEATURE (Data,Var,Abs) + 0xc0, // END_COLLECTION + 0x05, 0x84, // USAGE_PAGE (Power Device) + 0x09, 0x03, // USAGE (ChangedStatus) + 0xa1, 0x02, // COLLECTION (Logical) + 0x05, 0x85, // USAGE_PAGE (Battery System) + 0x0b, 0x61, 0x00, 0x84, 0x00, // USAGE (Power Device:Good) + 0x09, 0x42, // USAGE (BelowRemainingCapacityLimit) + 0x09, 0x44, // USAGE (Charging) + 0x09, 0x45, // USAGE (Discharging) + 0x75, 0x02, // REPORT_SIZE (2) + 0x95, 0x04, // REPORT_COUNT (4) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION + 0x05, 0x84, // USAGE_PAGE (Power Device) + 0x09, 0x16, // USAGE (PowerConverter) + 0xa1, 0x02, // COLLECTION (Logical) + 0x85, 0x08, // REPORT_ID (8) + 0x09, 0x17, // USAGE (PowerConverterID) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x0f, // LOGICAL_MAXIMUM (15) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x09, 0x1a, // USAGE (Input) + 0xa1, 0x02, // COLLECTION (Logical) + 0x09, 0x1b, // USAGE (InputID) + 0x09, 0x1f, // USAGE (FlowID) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x02, // REPORT_COUNT (2) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x0f, // LOGICAL_MAXIMUM (15) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x09, 0x02, // USAGE (PresentStatus) + 0xa1, 0x02, // COLLECTION (Logical) + 0x09, 0x6d, // USAGE (Used) + 0x09, 0x61, // USAGE (Good) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x02, // REPORT_COUNT (2) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0xb1, 0x02, // FEATURE (Data,Var,Abs) + 0xc0, // END_COLLECTION + 0x09, 0x03, // USAGE (ChangedStatus) + 0xa1, 0x02, // COLLECTION (Logical) + 0x09, 0x6d, // USAGE (Used) + 0x09, 0x61, // USAGE (Good) + 0x75, 0x02, // REPORT_SIZE (2) + 0x95, 0x02, // REPORT_COUNT (2) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION + 0x09, 0x1c, // USAGE (Output) + 0xa1, 0x02, // COLLECTION (Logical) + 0x85, 0x09, // REPORT_ID (9) + 0x09, 0x1d, // USAGE (OutputID) + 0x09, 0x1f, // USAGE (FlowID) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x02, // REPORT_COUNT (2) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x0f, // LOGICAL_MAXIMUM (15) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x09, 0x35, // USAGE (PercentLoad) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x09, 0x02, // USAGE (PresentStatus) + 0xa1, 0x02, // COLLECTION (Logical) + 0x09, 0x6d, // USAGE (Used) + 0x09, 0x61, // USAGE (Good) + 0x09, 0x64, // USAGE (FrequencyOutOfRange) + 0x09, 0x69, // USAGE (ShutdownImminent) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x04, // REPORT_COUNT (4) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0xb1, 0x02, // FEATURE (Data,Var,Abs) + 0xc0, // END_COLLECTION + 0x09, 0x03, // USAGE (ChangedStatus) + 0xa1, 0x02, // COLLECTION (Logical) + 0x09, 0x6d, // USAGE (Used) + 0x09, 0x61, // USAGE (Good) + 0x09, 0x64, // USAGE (FrequencyOutOfRange) + 0x09, 0x69, // USAGE (ShutdownImminent) + 0x75, 0x02, // REPORT_SIZE (2) + 0x95, 0x04, // REPORT_COUNT (4) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION + 0x09, 0x1a, // USAGE (Input) + 0xa1, 0x02, // COLLECTION (Logical) + 0x85, 0x0a, // REPORT_ID (10) + 0x09, 0x1b, // USAGE (InputID) + 0x09, 0x1f, // USAGE (FlowID) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x02, // REPORT_COUNT (2) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x0f, // LOGICAL_MAXIMUM (15) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x09, 0x02, // USAGE (PresentStatus) + 0xa1, 0x02, // COLLECTION (Logical) + 0x09, 0x6d, // USAGE (Used) + 0x09, 0x61, // USAGE (Good) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x02, // REPORT_COUNT (2) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0xb1, 0x02, // FEATURE (Data,Var,Abs) + 0xc0, // END_COLLECTION + 0x09, 0x03, // USAGE (ChangedStatus) + 0xa1, 0x02, // COLLECTION (Logical) + 0x09, 0x6d, // USAGE (Used) + 0x09, 0x61, // USAGE (Good) + 0x75, 0x02, // REPORT_SIZE (2) + 0x95, 0x02, // REPORT_COUNT (2) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION + 0x09, 0x24, // USAGE (Sink) + 0xa1, 0x02, // COLLECTION (Logical) + 0x85, 0x0b, // REPORT_ID (11) + 0x09, 0x25, // USAGE (SinkID) + 0x09, 0x1f, // USAGE (FlowID) + 0x09, 0x1d, // USAGE (OutputID) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x03, // REPORT_COUNT (3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x0f, // LOGICAL_MAXIMUM (15) + 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) + 0x09, 0x1b, // USAGE (InputID) + 0x09, 0x13, // USAGE (BatteryID) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x04, // REPORT_COUNT (4) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x0f, // LOGICAL_MAXIMUM (15) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x09, 0x35, // USAGE (PercentLoad) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x05, 0x85, // USAGE_PAGE (Battery System) + 0x09, 0x66, // USAGE (RemainingCapacity) + 0x75, 0x18, // REPORT_SIZE (24) + 0x95, 0x01, // REPORT_COUNT (1) + 0x67, 0x01, 0x10, 0x10, 0x00, // UNIT (SI Lin:Battery Capacity) + 0x55, 0x00, // UNIT_EXPONENT (0) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x27, 0xfe, 0xff, 0xff, 0x00, // LOGICAL_MAXIMUM (16777214) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x65, 0x00, // UNIT (None) + 0x09, 0x42, // USAGE (BelowRemainingCapacityLimit) + 0x09, 0x44, // USAGE (Charging) + 0x09, 0x45, // USAGE (Discharging) + 0x0b, 0x64, 0x00, 0x84, 0x00, // USAGE (Power Device:FrequencyOutOfRange) + 0x0b, 0x69, 0x00, 0x84, 0x00, // USAGE (Power Device:ShutdownImminent) + 0x75, 0x02, // REPORT_SIZE (2) + 0x95, 0x05, // REPORT_COUNT (5) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_example_pwr_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +UINT descriptor_size = HID_REPORT_LENGTH; +UX_SLAVE_TRANSFER * slave_transfer_request; + + + /* Inform user. */ + printf("Running HID Report Descriptor Example pwr 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); + } + + /* UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH defined in ux_port.h is not sufficient for this + report descriptor. We need to allocate a larger buffer. */ + + slave_transfer_request = &_ux_system_slave -> ux_system_slave_device.ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request; + + ux_utility_memory_free(slave_transfer_request -> ux_slave_transfer_request_data_pointer); + + slave_transfer_request -> ux_slave_transfer_request_data_pointer = ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY, 1024); + if(slave_transfer_request -> ux_slave_transfer_request_data_pointer == UX_NULL) + { + + 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the input report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Do minimal error-checking. */ + if (report_id.ux_host_class_hid_report_get_report == UX_NULL) + { + + printf("Error on line %d\n", __LINE__); + 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_hid_report_descriptor_example_remote_test.c b/test/regression/usbx_hid_report_descriptor_example_remote_test.c new file mode 100644 index 00000000..901328b0 --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_example_remote_test.c @@ -0,0 +1,345 @@ +/* This test ensures that the parser handles the example remote report descriptor + from the USB HID report descriptor tool. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_remote_control.h" + + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) + 0x09, 0x01, // USAGE (Consumer Control) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x02, // USAGE (Numeric Key Pad) + 0xa1, 0x02, // COLLECTION (Logical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x0a, // USAGE_MAXIMUM (Button 10) + 0x15, 0x01, // LOGICAL_MINIMUM (1) + 0x25, 0x0a, // LOGICAL_MAXIMUM (10) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0, // END_COLLECTION + 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) + 0x09, 0x86, // USAGE (Channel) + 0x09, 0xe0, // USAGE (Volume) + 0x15, 0xff, // LOGICAL_MINIMUM (-1) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x02, // REPORT_SIZE (2) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x46, // INPUT (Data,Var,Rel,Null) + 0x09, 0xe2, // USAGE (Mute) + 0x09, 0x30, // USAGE (Power) + 0x09, 0x34, // USAGE (Sleep Mode) + 0x09, 0x60, // USAGE (Data On Screen) + 0x09, 0x64, // USAGE (Broadcast Mode) + 0x09, 0x83, // USAGE (Recall Last) + 0x09, 0x81, // USAGE (Assign Selection) + 0x15, 0x01, // LOGICAL_MINIMUM (1) + 0x25, 0x07, // LOGICAL_MAXIMUM (7) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0x09, 0x80, // USAGE (Selection) + 0xa1, 0x02, // COLLECTION (Logical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x01, // LOGICAL_MINIMUM (1) + 0x25, 0x03, // LOGICAL_MAXIMUM (3) + 0x75, 0x02, // REPORT_SIZE (2) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0, // END_COLLECTION + 0x15, 0x02, // LOGICAL_MINIMUM (2) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_example_remote_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 Example remote 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_remote_control_name, ux_host_class_hid_remote_control_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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the input report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Do minimal error-checking. */ + if (report_id.ux_host_class_hid_report_get_report == UX_NULL) + { + + printf("Error on line %d\n", __LINE__); + 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_hid_report_descriptor_example_tele_test.c b/test/regression/usbx_hid_report_descriptor_example_tele_test.c new file mode 100644 index 00000000..a30b33f5 --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_example_tele_test.c @@ -0,0 +1,395 @@ +/* This test ensures that the parser handles the example tele report descriptor + from the USB HID report descriptor tool. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static UCHAR hid_report_descriptor[] = { + + 0x95, 0x01, // REPORT_COUNT (1) + 0x05, 0x0b, // USAGE_PAGE (Telephony Devices) + 0x09, 0x01, // USAGE (Phone) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x07, // USAGE (Programmable Button) + 0xa1, 0x02, // COLLECTION (Logical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x06, // USAGE_MAXIMUM (Button 6) + 0x75, 0x03, // REPORT_SIZE (3) + 0x15, 0x01, // LOGICAL_MINIMUM (1) + 0x25, 0x06, // LOGICAL_MAXIMUM (6) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0, // END_COLLECTION + 0x05, 0x0b, // USAGE_PAGE (Telephony Devices) + 0x09, 0x06, // USAGE (Telephony Key Pad) + 0xa1, 0x02, // COLLECTION (Logical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x0c, // USAGE_MAXIMUM (Button 12) + 0x25, 0x0c, // LOGICAL_MAXIMUM (12) + 0x75, 0x04, // REPORT_SIZE (4) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0, // END_COLLECTION + 0x05, 0x0b, // USAGE_PAGE (Telephony Devices) + 0x09, 0x20, // USAGE (Hook Switch) + 0x09, 0x29, // USAGE (Alternate Function) + 0x09, 0x2c, // USAGE (Conference) + 0x09, 0x25, // USAGE (Transfer) + 0x09, 0x26, // USAGE (Drop) + 0x09, 0x23, // USAGE (Hold) + 0x09, 0x2b, // USAGE (Speaker Phone) + 0x25, 0x07, // LOGICAL_MAXIMUM (7) + 0x75, 0x03, // REPORT_SIZE (3) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) + 0x09, 0xe0, // USAGE (Volume) + 0x15, 0xff, // LOGICAL_MINIMUM (-1) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x02, // REPORT_SIZE (2) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x75, 0x04, // REPORT_SIZE (4) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x09, 0x3a, // USAGE (Usage Selected Indicator) + 0xa1, 0x02, // COLLECTION (Logical) + 0x05, 0x0b, // USAGE_PAGE (Telephony Devices) + 0x09, 0x07, // USAGE (Programmable Button) + 0xa1, 0x02, // COLLECTION (Logical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x02, // USAGE_MAXIMUM (Button 2) + 0x95, 0x02, // REPORT_COUNT (2) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x09, 0x3b, // USAGE (Usage In Use Indicator) + 0xa1, 0x02, // COLLECTION (Logical) + 0x05, 0x0b, // USAGE_PAGE (Telephony Devices) + 0x09, 0x07, // USAGE (Programmable Button) + 0xa1, 0x02, // COLLECTION (Logical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Undefined) + 0x29, 0x06, // USAGE_MAXIMUM (Undefined) + 0x95, 0x06, // REPORT_COUNT (6) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION + 0x05, 0x0b, // USAGE_PAGE (Telephony Devices) + 0x09, 0x29, // USAGE (Alternate Function) + 0x95, 0x01, // REPORT_COUNT (1) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x09, 0x3c, // USAGE (Usage Multi Mode Indicator) + 0xa1, 0x02, // COLLECTION (Logical) + 0x05, 0x0b, // USAGE_PAGE (Telephony Devices) + 0x09, 0x73, // USAGE (Message) + 0xa1, 0x02, // COLLECTION (Logical) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x09, 0x3d, // USAGE (Indicator On) + 0x09, 0x40, // USAGE (Indicator Fast Blink) + 0x09, 0x41, // USAGE (Indicator Off) + 0x75, 0x02, // REPORT_SIZE (2) + 0x91, 0x00, // OUTPUT (Data,Ary,Abs) + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* USBX currently doesn't support this device. However, USBX parses the report descriptor before searching for clients, so this isn't a waste of time. */ + if (error_code != UX_HOST_CLASS_HID_UNKNOWN) + { + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_example_tele_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 Example tele 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the input report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Do minimal error-checking. */ + if (report_id.ux_host_class_hid_report_get_report == UX_NULL) + { + + printf("Error on line %d\n", __LINE__); + 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_hid_report_descriptor_extended_usages_test.c b/test/regression/usbx_hid_report_descriptor_extended_usages_test.c new file mode 100644 index 00000000..6e2fb834 --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_extended_usages_test.c @@ -0,0 +1,336 @@ +/* This test concentrates on the "extended usages" feature (page 41 of USB HID spec). */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static UCHAR report_buffer_compressed[1024]; +static SLONG report_buffer_decompressed[1024]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x0b, 0x31, 0x00, 0x04, 0x00, // USAGE (Sports:Slope) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION +}; +#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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_extended_usage_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 Extended Usages 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; +UX_HOST_CLASS_HID_CLIENT_REPORT input_report_request; +UX_HOST_CLASS_HID_REPORT *input_report_descriptor; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the first input report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + input_report_descriptor = report_id.ux_host_class_hid_report_get_report; + if (input_report_descriptor -> ux_host_class_hid_report_id != 0) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Fill out the request for the decompress api. */ + input_report_request.ux_host_class_hid_client_report = input_report_descriptor; + input_report_request.ux_host_class_hid_client_report_buffer = report_buffer_decompressed; + input_report_request.ux_host_class_hid_client_report_length = input_report_descriptor -> ux_host_class_hid_report_byte_length; + input_report_request.ux_host_class_hid_client_report_actual_length = 0; + input_report_request.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_DECOMPRESSED; + + /* Request decompression. */ + status = _ux_host_class_hid_report_decompress(hid, &input_report_request, report_buffer_compressed, 1); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Check output of decompression of report. */ + if ( + report_buffer_decompressed[0] != 0x00040031 + ) + { + + printf("Error on line %d\n", __LINE__); + 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_hid_report_descriptor_get_zero_length_item_data_test.c b/test/regression/usbx_hid_report_descriptor_get_zero_length_item_data_test.c new file mode 100644 index 00000000..7cecbabf --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_get_zero_length_item_data_test.c @@ -0,0 +1,311 @@ +/* This test hits the default case in _ux_host_class_hid_item_data_get. */ + +#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) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + /* Add a zero length item. */ + 0x28, // USAGE_MAXIMUM () + 0xc0 // END_COLLECTION +}; +#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 + }; + + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_get_zero_length_item_data_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 Get Zero Length Item Data 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\n", __LINE__); + 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_hid_report_descriptor_global_item_persist_test.c b/test/regression/usbx_hid_report_descriptor_global_item_persist_test.c new file mode 100644 index 00000000..a8fcf934 --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_global_item_persist_test.c @@ -0,0 +1,350 @@ +/* This test ensures that global items persist through main items (i.e. INPUT). */ + +#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) + 0x85, 0x33, // REPORT_ID (33) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x7f, // LOGICAL_MINIMUM (127) + 0x25, 0xff, // LOGICAL_MAXIMUM (255) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x45, 0xff, // PHYSICAL_MAXIMUM (255) + 0x65, 0x14, // UNIT (Eng Rot:Angular Pos) + 0x55, 0x67, // UNIT_EXPONENT (0) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* USBX expects keyboards to have at least one output report, otherwise it's an error. */ + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + + 0xc0 // END_COLLECTION +}; +#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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_global_item_persist_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 Global Item Persist 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; +UX_HOST_CLASS_HID_FIELD *report_field; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the input report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Check the first field in the report. */ + report_field = report_id.ux_host_class_hid_report_get_report -> ux_host_class_hid_report_field; + if( + report_field -> ux_host_class_hid_field_logical_min != 0x7f || + report_field -> ux_host_class_hid_field_logical_max != 0xff || + report_field -> ux_host_class_hid_field_physical_min != 0x00 || + report_field -> ux_host_class_hid_field_physical_max != 0xff || + report_field -> ux_host_class_hid_field_unit != 0x14 || + report_field -> ux_host_class_hid_field_unit_expo != 0x67 || + report_field -> ux_host_class_hid_field_report_id != 0x33 + ) + { + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Check the second field in the report. */ + report_field = report_field -> ux_host_class_hid_field_next_field; + if( + report_field -> ux_host_class_hid_field_logical_min != 0x7f || + report_field -> ux_host_class_hid_field_logical_max != 0xff || + report_field -> ux_host_class_hid_field_physical_min != 0x00 || + report_field -> ux_host_class_hid_field_physical_max != 0xff || + report_field -> ux_host_class_hid_field_unit != 0x14 || + report_field -> ux_host_class_hid_field_unit_expo != 0x67 || + report_field -> ux_host_class_hid_field_report_id != 0x33 + ) + { + printf("Error on line %d\n", __LINE__); + 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); +} \ No newline at end of file diff --git a/test/regression/usbx_hid_report_descriptor_global_item_test.c b/test/regression/usbx_hid_report_descriptor_global_item_test.c new file mode 100644 index 00000000..349ba67b --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_global_item_test.c @@ -0,0 +1,353 @@ +/* This test ensures that certain data-descriptive global items are correct within reports. This includes: + -LOGICAL_MINIMUM + -LOGICAL_MAXIMUM + -PHYSICAL_MINIMUM + -PHYSICAL_MAXIMUM + -UNIT + -UNIT_EXPONENT + -INPUT/OUTPUT/FEATURE bits + -We do not check usages here because they are checked in another test (via decompress). + + Reasoning: The user needs to know these in order to interpret the data in the report. + */ + +#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) + 0x85, 0x33, // REPORT_ID (33) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x7f, // LOGICAL_MINIMUM (127) + 0x25, 0xff, // LOGICAL_MAXIMUM (255) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x45, 0xff, // PHYSICAL_MAXIMUM (255) + 0x65, 0x14, // UNIT (Eng Rot:Angular Pos) + 0x55, 0x67, // UNIT_EXPONENT (0) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x82, 0xab, 0x01, // INPUT (chosen specifically for testing) + + /* USBX expects keyboards to have at least one output report, otherwise it's an error. */ + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + + 0xc0 // END_COLLECTION +}; +#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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_global_item_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 Global Item 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; +UX_HOST_CLASS_HID_FIELD *report_field; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the input report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Check the field in the report. */ + report_field = report_id.ux_host_class_hid_report_get_report -> ux_host_class_hid_report_field; + if( + report_field -> ux_host_class_hid_field_logical_min != 0x7f || + report_field -> ux_host_class_hid_field_logical_max != 0xff || + report_field -> ux_host_class_hid_field_physical_min != 0x00 || + report_field -> ux_host_class_hid_field_physical_max != 0xff || + report_field -> ux_host_class_hid_field_unit != 0x14 || + report_field -> ux_host_class_hid_field_unit_expo != 0x67 || + report_field -> ux_host_class_hid_field_report_id != 0x33 || + + (report_field -> ux_host_class_hid_field_value & UX_HOST_CLASS_HID_ITEM_CONSTANT) == 0 || + (report_field -> ux_host_class_hid_field_value & UX_HOST_CLASS_HID_ITEM_VARIABLE) == 0 || + (report_field -> ux_host_class_hid_field_value & UX_HOST_CLASS_HID_ITEM_RELATIVE) != 0 || + (report_field -> ux_host_class_hid_field_value & UX_HOST_CLASS_HID_ITEM_WRAP) == 0 || + (report_field -> ux_host_class_hid_field_value & UX_HOST_CLASS_HID_ITEM_NON_LINEAR) != 0 || + (report_field -> ux_host_class_hid_field_value & UX_HOST_CLASS_HID_ITEM_NO_PREFERRED_STATE) == 0 || + (report_field -> ux_host_class_hid_field_value & UX_HOST_CLASS_HID_ITEM_NULL_STATE) != 0 || + (report_field -> ux_host_class_hid_field_value & UX_HOST_CLASS_HID_ITEM_VOLATILE) == 0 || + (report_field -> ux_host_class_hid_field_value & UX_HOST_CLASS_HID_ITEM_BUFFERED_BYTES) == 0 + ) + { + printf("Error on line %d\n", __LINE__); + 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); +} \ No newline at end of file diff --git a/test/regression/usbx_hid_report_descriptor_incoherent_usage_min_max_test.c b/test/regression/usbx_hid_report_descriptor_incoherent_usage_min_max_test.c new file mode 100644 index 00000000..e2d25079 --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_incoherent_usage_min_max_test.c @@ -0,0 +1,293 @@ +/* This test ensures that the parser fails when the USAGE MINIMUM is greater than USAGE MAXIMUM. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x80, // USAGE_PAGE (Monitor) + 0x09, 0x01, // USAGE (Monitor Control) + 0xa1, 0x01, // COLLECTION (Application) + + /* Have a larger minimum than maximum. */ + 0x19, 0xff, // USAGE_MINIMUM (255) + 0x29, 0x00, // USAGE_MAXIMUM (0) + + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x82, 0xab, 0x01, // INPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_HOST_CLASS_HID_MIN_MAX_ERROR && + 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_hid_report_descriptor_incoherent_usage_min_max_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running HID Report Descriptor Incoherent Usage Min Max 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, error code: %d\n", __LINE__, status); + 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); + } + + /* 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); +} \ No newline at end of file diff --git a/test/regression/usbx_hid_report_descriptor_invalid_item_test.c b/test/regression/usbx_hid_report_descriptor_invalid_item_test.c new file mode 100644 index 00000000..171ce0ba --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_invalid_item_test.c @@ -0,0 +1,339 @@ +/* This test ensures that the parser handles an invalid descriptor length. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + +#include "ux_test_hcd_sim_host.h" + +static UINT callback_error_code; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0xab, // INPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; +#define HID_REPORT_LENGTH sizeof(hid_report_descriptor)/sizeof(hid_report_descriptor[0]) + +static UCHAR hid_report_descriptor_type_error[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + /*------- 0x75 -> 0x7d generate tag type error */ + 0x7d, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0xab, // INPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; +static UCHAR hid_report_descriptor_length_error[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + /*------- 0x81 -> 0x83 generate tag length error */ + 0x83, 0xab, // INPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; + + +#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, modify descriptor length <> actual length. */ + 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, modify descriptor length <> actual length. */ + 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 + }; + + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_HOST_CLASS_HID_TAG_UNSUPPORTED && + error_code != UX_DESCRIPTOR_CORRUPTED && + error_code != UX_DEVICE_ENUMERATION_FAILURE) + { + + /* Something went wrong. */ + printf("Error on line %d, code 0x%x\n", __LINE__, error_code); + test_control_return(1); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_invalid_item_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 Invalid Item Type/Length 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: 0x%x\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: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + ux_test_hcd_sim_host_disconnect(); + _ux_utility_memory_copy(hid_report_descriptor, hid_report_descriptor_type_error, sizeof(hid_report_descriptor)); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + status = demo_class_hid_get(); + if (status == UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + ux_test_hcd_sim_host_disconnect(); + _ux_utility_memory_copy(hid_report_descriptor, hid_report_descriptor_length_error, sizeof(hid_report_descriptor)); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + status = demo_class_hid_get(); + if (status == UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + 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); +} \ No newline at end of file diff --git a/test/regression/usbx_hid_report_descriptor_invalid_length_test.c b/test/regression/usbx_hid_report_descriptor_invalid_length_test.c new file mode 100644 index 00000000..83f03aee --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_invalid_length_test.c @@ -0,0 +1,291 @@ +/* This test ensures that the parser handles an invalid descriptor length. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static UINT callback_error_code; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0xab, // INPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; +#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, modify descriptor length <> actual length. */ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_REPORT_LENGTH+8), + MSB(HID_REPORT_LENGTH+8), + + /* 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, modify descriptor length <> actual length. */ + 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 + }; + + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_DESCRIPTOR_CORRUPTED && + error_code != UX_DEVICE_ENUMERATION_FAILURE) + { + + /* Something went wrong. */ + printf("Error on line %d, code 0x%x\n", __LINE__, error_code); + test_control_return(1); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_invalid_length_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 Invalid Descriptor Length 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: 0x%x\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: 0x%x\n", __LINE__, status); + 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); +} \ No newline at end of file diff --git a/test/regression/usbx_hid_report_descriptor_item_size_test.c b/test/regression/usbx_hid_report_descriptor_item_size_test.c new file mode 100644 index 00000000..151d97e0 --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_item_size_test.c @@ -0,0 +1,329 @@ +/* This test ensures that the parser handles different item sizes. */ + +#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) + + 0x15, 0xab, // LOGICAL_MINIMUM () - One byte + 0x26, 0xab, 0xcd, // LOGICAL_MAXIMUM () - Two bytes + 0x35, 0x00, // PHYSICAL_MINIMUM () + 0x47, 0xab, 0xcd, 0xef, 0x01, // PHYSICAL_MAXIMUM () - Four bytes + + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x65, 0x14, // UNIT (Eng Rot:Angular Pos) + 0x55, 0x67, // UNIT_EXPONENT (0) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0xab, // INPUT (Data,Var,Abs) + + /* USBX expects keyboards to have at least one output report, otherwise it's an error. */ + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + + 0xc0 // END_COLLECTION +}; +#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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_item_size_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 Item Size 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; +UX_HOST_CLASS_HID_FIELD *report_field; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the input report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Check the field in the report. */ + report_field = report_id.ux_host_class_hid_report_get_report -> ux_host_class_hid_report_field; + if( + report_field -> ux_host_class_hid_field_logical_min != 0xab || + report_field -> ux_host_class_hid_field_logical_max != 0xcdab || + report_field -> ux_host_class_hid_field_physical_max != 0x01efcdab + ) + { + printf("Error on line %d\n", __LINE__); + 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); +} \ No newline at end of file diff --git a/test/regression/usbx_hid_report_descriptor_max_usages_test.c b/test/regression/usbx_hid_report_descriptor_max_usages_test.c new file mode 100644 index 00000000..d9dfbd05 --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_max_usages_test.c @@ -0,0 +1,314 @@ +/* This test ensures the parser can handle the maximum number of usages. */ + +#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) + 0x19, 0x00, // USAGE_MINIMUM (0) + 0x2a, 0xff, 0x03, // USAGE_MAXIMUM (1023) + 0x75, 0x01, // REPORT_SIZE (1) + 0x96, 0xff, 0x03, // REPORT_COUNT (1024) + 0x82, 0xab, 0x01, // INPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_max_usages_test(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 Max Usages 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; +UX_HOST_CLASS_HID_FIELD *report_field; +UINT i; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the input report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the field. */ + report_field = report_id.ux_host_class_hid_report_get_report -> ux_host_class_hid_report_field; + + /* Make sure the usages are correct. */ + for (i = 0; i < 1024; i++) + { + if (report_field -> ux_host_class_hid_field_usages[i] != (0x00010000 | i)) + { + + printf("Error on line %d\n", __LINE__); + 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); +} \ No newline at end of file diff --git a/test/regression/usbx_hid_report_descriptor_multiple_collections_test.c b/test/regression/usbx_hid_report_descriptor_multiple_collections_test.c new file mode 100644 index 00000000..303bdc2f --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_multiple_collections_test.c @@ -0,0 +1,418 @@ +/* This test ensures that the parser correctly handles multiple collections. */ + +#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) + 0xa1, 0x00, // COLLECTION (Physical) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x04, // REPORT_SIZE (4) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xa1, 0x00, // COLLECTION (Physical) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x06, // REPORT_SIZE (6) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xa1, 0x00, // COLLECTION (Physical) + 0x95, 0x07, // REPORT_COUNT (7) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION + + /* USBX expects keyboards to have at least one output report, otherwise it's an error. */ + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + + 0xc0, // END_COLLECTION + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x85, 0x01, // REPORT_ID (1) + 0x95, 0x09, // REPORT_COUNT (9) + 0x75, 0x0a, // REPORT_SIZE (10) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xa1, 0x00, // COLLECTION (Physical) + 0x95, 0x0b, // REPORT_COUNT (11) + 0x75, 0x0c, // REPORT_SIZE (12) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xa1, 0x00, // COLLECTION (Physical) + 0x95, 0x0d, // REPORT_COUNT (13) + 0x75, 0x0e, // REPORT_SIZE (14) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xa1, 0x00, // COLLECTION (Physical) + 0x95, 0x0f, // REPORT_COUNT (15) + 0x75, 0x10, // REPORT_SIZE (16) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x85, 0x02, // REPORT_ID (2) + 0x95, 0x11, // REPORT_COUNT (17) + 0x75, 0x12, // REPORT_SIZE (18) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xa1, 0x00, // COLLECTION (Physical) + 0x95, 0x13, // REPORT_COUNT (19) + 0x75, 0x14, // REPORT_SIZE (20) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xa1, 0x00, // COLLECTION (Physical) + 0x95, 0x15, // REPORT_COUNT (21) + 0x75, 0x16, // REPORT_SIZE (22) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xa1, 0x00, // COLLECTION (Physical) + 0x95, 0x17, // REPORT_COUNT (23) + 0x75, 0x18, // REPORT_SIZE (24) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION +}; +#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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_multiple_collections_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 Multiple Collections 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_get_id; +UX_HOST_CLASS_HID_REPORT *input_report_descriptor; +UX_HOST_CLASS_HID_FIELD *report_field; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + report_get_id.ux_host_class_hid_report_get_report = UX_NULL; + report_get_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + + UINT report_id = 0; + UINT field = 0; + + /* Get the first input report descriptor. */ + status = ux_host_class_hid_report_id_get(hid, &report_get_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + input_report_descriptor = report_get_id.ux_host_class_hid_report_get_report; + + /* Check the reports. */ + for(report_id = 0;; report_id++) + { + + /* Check the fields */ + report_field = input_report_descriptor -> ux_host_class_hid_report_field; + for(field = 0; report_field -> ux_host_class_hid_field_next_field != UX_NULL; field++) + { + + if( + report_field -> ux_host_class_hid_field_report_id != report_id || + report_field -> ux_host_class_hid_field_report_count != (8*report_id + 2*field + 1) || + report_field -> ux_host_class_hid_field_report_size != (8*report_id + 2*field + 2) + ) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + report_field = report_field -> ux_host_class_hid_field_next_field; + } + + if (input_report_descriptor -> ux_host_class_hid_report_next_report != UX_NULL) + { + + /* Get the next input report descriptor. */ + status = ux_host_class_hid_report_id_get(hid, &report_get_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + } + else + { + break; + } + + input_report_descriptor = report_get_id.ux_host_class_hid_report_get_report; + } + + /* 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_hid_report_descriptor_multiple_fields_and_reports_test.c b/test/regression/usbx_hid_report_descriptor_multiple_fields_and_reports_test.c new file mode 100644 index 00000000..d54dab09 --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_multiple_fields_and_reports_test.c @@ -0,0 +1,346 @@ +/* This test ensures that the parser correctly handles multiple fields in different reports. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static UCHAR report_buffer_compressed[1024]; +static SLONG report_buffer_decompressed[1024]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x19, 0x01, // USAGE_MINIMUM (1) + 0x29, 0x04, // USAGE_MAXIMUM (4) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x04, // REPORT_COUNT (4) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x85, 0x01, // REPORT_ID (1) + 0x19, 0x05, // USAGE_MINIMUM (5) + 0x29, 0x07, // USAGE_MAXIMUM (7) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x03, // REPORT_COUNT (3) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x19, 0x05, // USAGE_MINIMUM (8) + 0x29, 0x07, // USAGE_MAXIMUM (10) + 0x75, 0x10, // REPORT_SIZE (16) + 0x95, 0x06, // REPORT_COUNT (6) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* USBX expects keyboards to have at least one output report, otherwise it's an error. */ + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + + 0xc0, // END_COLLECTION +}; +#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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_multiple_fields_and_reports_test(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 Multiple Fields and Reports 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; +UX_HOST_CLASS_HID_FIELD *report_field; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the second input report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status |= ux_host_class_hid_report_id_get(hid, &report_id); + status |= ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Check the first field in the report. */ + report_field = report_id.ux_host_class_hid_report_get_report -> ux_host_class_hid_report_field; + if( + report_field -> ux_host_class_hid_field_report_size != 8 || + report_field -> ux_host_class_hid_field_report_count != 3 + ) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Check the second field in the report. */ + report_field = report_field -> ux_host_class_hid_field_next_field; + if( + report_field -> ux_host_class_hid_field_report_size != 16 || + report_field -> ux_host_class_hid_field_report_count != 6 + ) + { + + printf("Error on line %d\n", __LINE__); + 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_hid_report_descriptor_multiple_fields_test.c b/test/regression/usbx_hid_report_descriptor_multiple_fields_test.c new file mode 100644 index 00000000..50b39944 --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_multiple_fields_test.c @@ -0,0 +1,386 @@ +/* This test ensures that the parser correctly handles multiple fields (i.e. multiple Input items). */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static UCHAR raw_output_report_buffer[1024]; +static SLONG decompressed_output_report_buffer[1024]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x19, 0x01, // USAGE_MINIMUM (1) + 0x29, 0x04, // USAGE_MAXIMUM (4) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x04, // REPORT_COUNT (4) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x19, 0x01, // USAGE_MINIMUM (1) + 0x29, 0x03, // USAGE_MAXIMUM (3) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x03, // REPORT_COUNT (3) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x09, 0x01, // USAGE (1) + 0x75, 0x10, // REPORT_SIZE (16) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* USBX expects keyboards to have at least one output report, otherwise it's an error. */ + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + + 0xc0, // END_COLLECTION +}; +#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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_multiple_fields_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 Multiple Fields 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; +UX_HOST_CLASS_HID_CLIENT_REPORT input_report_request; +UX_HOST_CLASS_HID_REPORT *input_report_descriptor; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the input report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the input report descriptor. */ + input_report_descriptor = report_id.ux_host_class_hid_report_get_report; + + /* Fill out the request. */ + input_report_request.ux_host_class_hid_client_report = input_report_descriptor; + input_report_request.ux_host_class_hid_client_report_buffer = decompressed_output_report_buffer; + input_report_request.ux_host_class_hid_client_report_length = input_report_descriptor -> ux_host_class_hid_report_byte_length; + input_report_request.ux_host_class_hid_client_report_actual_length = 0; + input_report_request.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_DECOMPRESSED; + + /* Fill out report to be decompressed. */ + + /* First field. */ + raw_output_report_buffer[0] = 0x01; + raw_output_report_buffer[1] = 0x23; + + /* Second field. */ + raw_output_report_buffer[2] = 0x45; + raw_output_report_buffer[3] = 0x67; + raw_output_report_buffer[4] = 0x89; + + /* Third field. */ + raw_output_report_buffer[5] = 0xab; + raw_output_report_buffer[6] = 0xcd; + + /* Request decompression. */ + status = _ux_host_class_hid_report_decompress(hid, &input_report_request, raw_output_report_buffer, 1); + + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Check output of decompression. */ + if ( + /* First field. */ + decompressed_output_report_buffer[0] != 0x00010001 || + decompressed_output_report_buffer[1] != 0x01 || + decompressed_output_report_buffer[2] != 0x00010002 || + decompressed_output_report_buffer[3] != 0x00 || + decompressed_output_report_buffer[4] != 0x00010003 || + decompressed_output_report_buffer[5] != 0x03 || + decompressed_output_report_buffer[6] != 0x00010004 || + decompressed_output_report_buffer[7] != 0x02 || + + /* Second field. */ + decompressed_output_report_buffer[8] != 0x00010001 || + decompressed_output_report_buffer[9] != 0x45 || + decompressed_output_report_buffer[10] != 0x00010002 || + decompressed_output_report_buffer[11] != 0x67 || + decompressed_output_report_buffer[12] != 0x00010003 || + decompressed_output_report_buffer[13] != 0x89 || + + /* Third field. */ + decompressed_output_report_buffer[14] != 0x00010001 || + decompressed_output_report_buffer[15] != 0xcdab + ) + { + + printf("Error on line %d\n", __LINE__); + 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_hid_report_descriptor_multiple_reports_feature_test.c b/test/regression/usbx_hid_report_descriptor_multiple_reports_feature_test.c new file mode 100644 index 00000000..35121c84 --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_multiple_reports_feature_test.c @@ -0,0 +1,480 @@ +/* This test ensures that the parser correctly handles multiple report IDs for feature reports. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static UCHAR feature_report_buffer_raw[1024]; +static SLONG feature_report_buffer_decompressed[1024]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x19, 0x01, // USAGE_MINIMUM (1) + 0x29, 0x04, // USAGE_MAXIMUM (4) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x04, // REPORT_COUNT (4) + 0xb1, 0x02, // FEATURE (Data,Var,Abs) + 0x85, 0x02, // REPORT_ID (2) + 0x19, 0x05, // USAGE_MINIMUM (5) + 0x29, 0x07, // USAGE_MAXIMUM (7) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x03, // REPORT_COUNT (3) + 0xb1, 0x02, // FEATURE (Data,Var,Abs) + 0x85, 0x04, // REPORT_ID (4) + 0x09, 0x08, // USAGE (8) + 0x75, 0x10, // REPORT_SIZE (16) + 0x95, 0x01, // REPORT_COUNT (1) + 0xb1, 0x02, // FEATURE (Data,Var,Abs) + + /* USBX requires at least one input report. */ + 0x09, 0x01, // USAGE (1) + 0x75, 0x10, // REPORT_SIZE (16) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* USBX expects keyboards to have at least one output report, otherwise it's an error. */ + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + + 0xc0, // END_COLLECTION +}; +#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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_multiple_reports_feature_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 Multiple Reports Feature 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; +UX_HOST_CLASS_HID_CLIENT_REPORT feature_report_request; +UX_HOST_CLASS_HID_REPORT *feature_report_descriptor; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the first feature report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_FEATURE; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + feature_report_descriptor = report_id.ux_host_class_hid_report_get_report; + if (feature_report_descriptor -> ux_host_class_hid_report_id != 0) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Fill out the request for the decompress api. */ + feature_report_request.ux_host_class_hid_client_report = feature_report_descriptor; + feature_report_request.ux_host_class_hid_client_report_buffer = feature_report_buffer_decompressed; + feature_report_request.ux_host_class_hid_client_report_length = feature_report_descriptor -> ux_host_class_hid_report_byte_length; + feature_report_request.ux_host_class_hid_client_report_actual_length = 0; + feature_report_request.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_DECOMPRESSED; + + /* Fill out first report. */ + feature_report_buffer_raw[0] = 0x01; + feature_report_buffer_raw[1] = 0x23; + + /* Request decompression. */ + status = _ux_host_class_hid_report_decompress(hid, &feature_report_request, feature_report_buffer_raw, 2); + + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Check output of decompression of first report. */ + if ( + feature_report_buffer_decompressed[0] != 0x00010001 || + feature_report_buffer_decompressed[1] != 0x01 || + feature_report_buffer_decompressed[2] != 0x00010002 || + feature_report_buffer_decompressed[3] != 0x00 || + feature_report_buffer_decompressed[4] != 0x00010003 || + feature_report_buffer_decompressed[5] != 0x03 || + feature_report_buffer_decompressed[6] != 0x00010004 || + feature_report_buffer_decompressed[7] != 0x02 + ) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the second feature report descriptor. */ + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + feature_report_descriptor = report_id.ux_host_class_hid_report_get_report; + if (feature_report_descriptor->ux_host_class_hid_report_id != 2) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Fill out the request for the decompress api. */ + feature_report_request.ux_host_class_hid_client_report = feature_report_descriptor; + feature_report_request.ux_host_class_hid_client_report_buffer = feature_report_buffer_decompressed; + feature_report_request.ux_host_class_hid_client_report_length = feature_report_descriptor -> ux_host_class_hid_report_byte_length; + feature_report_request.ux_host_class_hid_client_report_actual_length = 0; + feature_report_request.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_DECOMPRESSED; + + /* Fill out second report. */ + feature_report_buffer_raw[0] = 0x02; // First byte is the Report ID. + feature_report_buffer_raw[1] = 0x45; + feature_report_buffer_raw[2] = 0x67; + feature_report_buffer_raw[3] = 0x89; + + /* Request decompression. */ + status = _ux_host_class_hid_report_decompress(hid, &feature_report_request, feature_report_buffer_raw, 3); + + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Check output of decompression of second report. */ + if ( + feature_report_buffer_decompressed[0] != 0x00010005 || + feature_report_buffer_decompressed[1] != 0x45 || + feature_report_buffer_decompressed[2] != 0x00010006 || + feature_report_buffer_decompressed[3] != 0x67 || + feature_report_buffer_decompressed[4] != 0x00010007 || + feature_report_buffer_decompressed[5] != 0x89 + ) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the third feature report descriptor. */ + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + feature_report_descriptor = report_id.ux_host_class_hid_report_get_report; + if (feature_report_descriptor->ux_host_class_hid_report_id != 4) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Fill out the request for the decompress api. */ + feature_report_request.ux_host_class_hid_client_report = feature_report_descriptor; + feature_report_request.ux_host_class_hid_client_report_buffer = feature_report_buffer_decompressed; + feature_report_request.ux_host_class_hid_client_report_length = feature_report_descriptor -> ux_host_class_hid_report_byte_length; + feature_report_request.ux_host_class_hid_client_report_actual_length = 0; + feature_report_request.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_DECOMPRESSED; + + /* Fill out third report. */ + feature_report_buffer_raw[0] = 0x04; // First byte is the Report ID. + feature_report_buffer_raw[1] = 0xab; + feature_report_buffer_raw[2] = 0xcd; + + /* Request decompression. */ + status = _ux_host_class_hid_report_decompress(hid, &feature_report_request, feature_report_buffer_raw, 2); + + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Check output of decompression of third report. */ + if ( + feature_report_buffer_decompressed[0] != 0x00010008 || + feature_report_buffer_decompressed[1] != 0xcdab + ) + { + + printf("Error on line %d\n", __LINE__); + 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_hid_report_descriptor_multiple_reports_input_test.c b/test/regression/usbx_hid_report_descriptor_multiple_reports_input_test.c new file mode 100644 index 00000000..21d3545e --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_multiple_reports_input_test.c @@ -0,0 +1,476 @@ +/* This test ensures that the parser correctly handles multiple report IDs for input reports. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static UCHAR report_buffer_compressed[1024]; +static SLONG report_buffer_decompressed[1024]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x19, 0x01, // USAGE_MINIMUM (1) + 0x29, 0x04, // USAGE_MAXIMUM (4) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x04, // REPORT_COUNT (4) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x85, 0x02, // REPORT_ID (2) + 0x19, 0x05, // USAGE_MINIMUM (5) + 0x29, 0x07, // USAGE_MAXIMUM (7) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x03, // REPORT_COUNT (3) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x85, 0x04, // REPORT_ID (4) + 0x09, 0x08, // USAGE (8) + 0x75, 0x10, // REPORT_SIZE (16) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* USBX expects keyboards to have at least one output report, otherwise it's an error. */ + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + + 0xc0, // END_COLLECTION +}; +#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 + }; + + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_multiple_reports_input_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 Multiple Reports Input 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; +UX_HOST_CLASS_HID_CLIENT_REPORT input_report_request; +UX_HOST_CLASS_HID_REPORT *input_report_descriptor; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the first input report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + input_report_descriptor = report_id.ux_host_class_hid_report_get_report; + if (input_report_descriptor -> ux_host_class_hid_report_id != 0) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Fill out the request for the decompress api. */ + input_report_request.ux_host_class_hid_client_report = input_report_descriptor; + input_report_request.ux_host_class_hid_client_report_buffer = report_buffer_decompressed; + input_report_request.ux_host_class_hid_client_report_length = input_report_descriptor -> ux_host_class_hid_report_byte_length; + input_report_request.ux_host_class_hid_client_report_actual_length = 0; + input_report_request.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_DECOMPRESSED; + + /* Fill out first report. */ + report_buffer_compressed[0] = 0x01; + report_buffer_compressed[1] = 0x23; + + /* Request decompression. */ + status = _ux_host_class_hid_report_decompress(hid, &input_report_request, report_buffer_compressed, 2); + + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Check output of decompression of first report. */ + if ( + report_buffer_decompressed[0] != 0x00010001 || + report_buffer_decompressed[1] != 0x01 || + report_buffer_decompressed[2] != 0x00010002 || + report_buffer_decompressed[3] != 0x00 || + report_buffer_decompressed[4] != 0x00010003 || + report_buffer_decompressed[5] != 0x03 || + report_buffer_decompressed[6] != 0x00010004 || + report_buffer_decompressed[7] != 0x02 + ) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the second input report descriptor. */ + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + input_report_descriptor = report_id.ux_host_class_hid_report_get_report; + if (input_report_descriptor->ux_host_class_hid_report_id != 2) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Fill out the request for the decompress api. */ + input_report_request.ux_host_class_hid_client_report = input_report_descriptor; + input_report_request.ux_host_class_hid_client_report_buffer = report_buffer_decompressed; + input_report_request.ux_host_class_hid_client_report_length = input_report_descriptor -> ux_host_class_hid_report_byte_length; + input_report_request.ux_host_class_hid_client_report_actual_length = 0; + input_report_request.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_DECOMPRESSED; + + /* Fill out second report. */ + report_buffer_compressed[0] = 0x02; // First byte is the Report ID. + report_buffer_compressed[1] = 0x45; + report_buffer_compressed[2] = 0x67; + report_buffer_compressed[3] = 0x89; + + /* Request decompression. */ + status = _ux_host_class_hid_report_decompress(hid, &input_report_request, report_buffer_compressed, 3); + + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Check output of decompression of second report. */ + if ( + report_buffer_decompressed[0] != 0x00010005 || + report_buffer_decompressed[1] != 0x45 || + report_buffer_decompressed[2] != 0x00010006 || + report_buffer_decompressed[3] != 0x67 || + report_buffer_decompressed[4] != 0x00010007 || + report_buffer_decompressed[5] != 0x89 + ) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the third input report descriptor. */ + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + input_report_descriptor = report_id.ux_host_class_hid_report_get_report; + if (input_report_descriptor->ux_host_class_hid_report_id != 4) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Fill out the request for the decompress api. */ + input_report_request.ux_host_class_hid_client_report = input_report_descriptor; + input_report_request.ux_host_class_hid_client_report_buffer = report_buffer_decompressed; + input_report_request.ux_host_class_hid_client_report_length = input_report_descriptor -> ux_host_class_hid_report_byte_length; + input_report_request.ux_host_class_hid_client_report_actual_length = 0; + input_report_request.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_DECOMPRESSED; + + /* Fill out third report. */ + report_buffer_compressed[0] = 0x04; // First byte is the Report ID. + report_buffer_compressed[1] = 0xab; + report_buffer_compressed[2] = 0xcd; + + /* Request decompression. */ + status = _ux_host_class_hid_report_decompress(hid, &input_report_request, report_buffer_compressed, 2); + + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Check output of decompression of third report. */ + if ( + report_buffer_decompressed[0] != 0x00010008 || + report_buffer_decompressed[1] != 0xcdab + ) + { + + printf("Error on line %d\n", __LINE__); + 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_hid_report_descriptor_multiple_reports_output_test.c b/test/regression/usbx_hid_report_descriptor_multiple_reports_output_test.c new file mode 100644 index 00000000..61261a6b --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_multiple_reports_output_test.c @@ -0,0 +1,472 @@ +/* This test ensures that the parser correctly handles multiple report IDs for output reports. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static UCHAR output_report_buffer_raw[1024]; +static SLONG output_report_buffer_decompressed[1024]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x19, 0x01, // USAGE_MINIMUM (1) + 0x29, 0x04, // USAGE_MAXIMUM (4) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x04, // REPORT_COUNT (4) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x85, 0x02, // REPORT_ID (2) + 0x19, 0x05, // USAGE_MINIMUM (5) + 0x29, 0x07, // USAGE_MAXIMUM (7) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x03, // REPORT_COUNT (3) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x85, 0x04, // REPORT_ID (4) + 0x09, 0x08, // USAGE (8) + 0x75, 0x10, // REPORT_SIZE (16) + 0x95, 0x01, // REPORT_COUNT (1) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + + /* USBX requires at least one input report. */ + 0x09, 0x01, // USAGE (1) + 0x75, 0x10, // REPORT_SIZE (16) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + 0xc0, // END_COLLECTION +}; +#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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_multiple_reports_output_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 Multiple Reports Output 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; +UX_HOST_CLASS_HID_CLIENT_REPORT output_report_request; +UX_HOST_CLASS_HID_REPORT *output_report_descriptor; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the first output report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_OUTPUT; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + output_report_descriptor = report_id.ux_host_class_hid_report_get_report; + if (output_report_descriptor -> ux_host_class_hid_report_id != 0) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Fill out the request for the decompress api. */ + output_report_request.ux_host_class_hid_client_report = output_report_descriptor; + output_report_request.ux_host_class_hid_client_report_buffer = output_report_buffer_decompressed; + output_report_request.ux_host_class_hid_client_report_length = output_report_descriptor -> ux_host_class_hid_report_byte_length; + output_report_request.ux_host_class_hid_client_report_actual_length = 0; + output_report_request.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_DECOMPRESSED; + + /* Fill out first report. */ + output_report_buffer_raw[0] = 0x01; + output_report_buffer_raw[1] = 0x23; + + /* Request decompression. */ + status = _ux_host_class_hid_report_decompress(hid, &output_report_request, output_report_buffer_raw, 2); + + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Check output of decompression of first report. */ + if ( + output_report_buffer_decompressed[0] != 0x00010001 || + output_report_buffer_decompressed[1] != 0x01 || + output_report_buffer_decompressed[2] != 0x00010002 || + output_report_buffer_decompressed[3] != 0x00 || + output_report_buffer_decompressed[4] != 0x00010003 || + output_report_buffer_decompressed[5] != 0x03 || + output_report_buffer_decompressed[6] != 0x00010004 || + output_report_buffer_decompressed[7] != 0x02 + ) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the second output report descriptor. */ + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + output_report_descriptor = report_id.ux_host_class_hid_report_get_report; + if (output_report_descriptor->ux_host_class_hid_report_id != 2) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Fill out the request for the decompress api. */ + output_report_request.ux_host_class_hid_client_report = output_report_descriptor; + output_report_request.ux_host_class_hid_client_report_buffer = output_report_buffer_decompressed; + output_report_request.ux_host_class_hid_client_report_length = output_report_descriptor -> ux_host_class_hid_report_byte_length; + output_report_request.ux_host_class_hid_client_report_actual_length = 0; + output_report_request.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_DECOMPRESSED; + + /* Fill out second report. */ + output_report_buffer_raw[0] = 0x02; // First byte is the Report ID. + output_report_buffer_raw[1] = 0x45; + output_report_buffer_raw[2] = 0x67; + output_report_buffer_raw[3] = 0x89; + + /* Request decompression. */ + status = _ux_host_class_hid_report_decompress(hid, &output_report_request, output_report_buffer_raw, 3); + + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Check output of decompression of second report. */ + if ( + output_report_buffer_decompressed[0] != 0x00010005 || + output_report_buffer_decompressed[1] != 0x45 || + output_report_buffer_decompressed[2] != 0x00010006 || + output_report_buffer_decompressed[3] != 0x67 || + output_report_buffer_decompressed[4] != 0x00010007 || + output_report_buffer_decompressed[5] != 0x89 + ) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the third output report descriptor. */ + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + output_report_descriptor = report_id.ux_host_class_hid_report_get_report; + if (output_report_descriptor->ux_host_class_hid_report_id != 4) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Fill out the request for the decompress api. */ + output_report_request.ux_host_class_hid_client_report = output_report_descriptor; + output_report_request.ux_host_class_hid_client_report_buffer = output_report_buffer_decompressed; + output_report_request.ux_host_class_hid_client_report_length = output_report_descriptor -> ux_host_class_hid_report_byte_length; + output_report_request.ux_host_class_hid_client_report_actual_length = 0; + output_report_request.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_DECOMPRESSED; + + /* Fill out third report. */ + output_report_buffer_raw[0] = 0x04; // First byte is the Report ID. + output_report_buffer_raw[1] = 0xab; + output_report_buffer_raw[2] = 0xcd; + + /* Request decompression. */ + status = _ux_host_class_hid_report_decompress(hid, &output_report_request, output_report_buffer_raw, 2); + + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Check output of decompression of third report. */ + if ( + output_report_buffer_decompressed[0] != 0x00010008 || + output_report_buffer_decompressed[1] != 0xcdab + ) + { + + printf("Error on line %d\n", __LINE__); + 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_hid_report_descriptor_pop_underflow_test.c b/test/regression/usbx_hid_report_descriptor_pop_underflow_test.c new file mode 100644 index 00000000..bc5f1962 --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_pop_underflow_test.c @@ -0,0 +1,290 @@ +/* This test ensures that the parser generates an error upon popping more than the allowable global states. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static UINT callback_error_code; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + /* Pop when there are no global states in the stack. */ + 0xb4, // POP + 0xc0 // END_COLLECTION +}; +#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 + }; + + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_HOST_CLASS_HID_POP_UNDERFLOW && + 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_hid_report_descriptor_pop_underflow_tag_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 Pop Underflow Tag 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, error code: %d\n", __LINE__, status); + 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); + } + + /* 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); +} \ No newline at end of file diff --git a/test/regression/usbx_hid_report_descriptor_previous_report_test.c b/test/regression/usbx_hid_report_descriptor_previous_report_test.c new file mode 100644 index 00000000..a825895b --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_previous_report_test.c @@ -0,0 +1,357 @@ +/* This test ensures that the parser correctly handles reverting back to a previously used Report ID. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static UCHAR raw_output_report_buffer[1024]; +static SLONG decompressed_output_report_buffer[1024]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + /* Start with Report ID 1 */ + 0x85, 0x01, // REPORT_ID (1) + 0x19, 0x01, // USAGE_MINIMUM (1) + 0x29, 0x04, // USAGE_MAXIMUM (4) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x04, // REPORT_COUNT (4) + 0x81, 0x02, // INPUT (Data,Var,Abs) + /* Switch Report IDs */ + 0x85, 0x02, // REPORT_ID (2) + 0x19, 0x01, // USAGE_MINIMUM (1) + 0x29, 0x03, // USAGE_MAXIMUM (3) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x03, // REPORT_COUNT (3) + 0x81, 0x02, // INPUT (Data,Var,Abs) + /* Revert back to Report ID 1 */ + 0x85, 0x01, // REPORT_ID (1) + 0x09, 0x01, // USAGE (1) + 0x75, 0x10, // REPORT_SIZE (16) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION +}; +#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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_previous_report_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 Previous Report 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; +UX_HOST_CLASS_HID_REPORT *input_report_descriptor; +UX_HOST_CLASS_HID_FIELD *report_field; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the input report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + input_report_descriptor = report_id.ux_host_class_hid_report_get_report; + + /* Check the first field in the report. */ + report_field = report_id.ux_host_class_hid_report_get_report -> ux_host_class_hid_report_field; + if( + report_field -> ux_host_class_hid_field_report_id != 0x01 || + report_field -> ux_host_class_hid_field_report_count != 0x04 || + report_field -> ux_host_class_hid_field_report_size != 0x04 + ) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Is there not another field? (There should be!) */ + if (report_field -> ux_host_class_hid_field_next_field == UX_NULL) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Go to the next report field. */ + report_field = report_field -> ux_host_class_hid_field_next_field; + + /* Check the first field in the report. */ + report_field = report_id.ux_host_class_hid_report_get_report -> ux_host_class_hid_report_field; + if( + report_field -> ux_host_class_hid_field_report_id != 0x01 || + report_field -> ux_host_class_hid_field_report_count != 0x01 || + report_field -> ux_host_class_hid_field_report_size != 0x10 + ) + { + + printf("Error on line %d\n", __LINE__); + 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_hid_report_descriptor_push_overflow_test.c b/test/regression/usbx_hid_report_descriptor_push_overflow_test.c new file mode 100644 index 00000000..71f3aa2b --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_push_overflow_test.c @@ -0,0 +1,293 @@ +/* This test ensures that the parser generates an error upon pushing more than the allowable global states. */ + +#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) + /* Push more than the allowable states (4 is the max). */ + 0xa4, // PUSH + 0xa4, // PUSH + 0xa4, // PUSH + 0xa4, // PUSH + 0xa4, // PUSH + 0xc0 // END_COLLECTION +}; +#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 + }; + + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_HOST_CLASS_HID_PUSH_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_hid_report_descriptor_push_overflow_tag_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 Push Overflow Tag 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); + } + + /* 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); +} \ No newline at end of file diff --git a/test/regression/usbx_hid_report_descriptor_push_pop_test.c b/test/regression/usbx_hid_report_descriptor_push_pop_test.c new file mode 100644 index 00000000..7982fe21 --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_push_pop_test.c @@ -0,0 +1,485 @@ +/* This test ensures that the parser correctly handles pushing and popping. */ + +#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) + /* Set the global state to A */ + 0x85, 1, // REPORT_ID (1) + 0x05, 2, // USAGE_PAGE (2) + 0x15, 3, // LOGICAL_MINIMUM (3) + 0x25, 4, // LOGICAL_MAXIMUM (4) + 0x35, 5, // PHYSICAL_MINIMUM (5) + 0x45, 6, // PHYSICAL_MAXIMUM (6) + 0x65, 7, // UNIT (7) + 0x55, 8, // UNIT_EXPONENT (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x02, // REPORT_SIZE (2) + 0xa4, // PUSH + /* Set the global state to B */ + 0x85, 11, // REPORT_ID (11) + 0x05, 12, // USAGE_PAGE (12) + 0x15, 15, // LOGICAL_MINIMUM (15) + 0x25, 16, // LOGICAL_MAXIMUM (16) + 0x35, 17, // PHYSICAL_MINIMUM (17) + 0x45, 18, // PHYSICAL_MAXIMUM (18) + 0x65, 19, // UNIT (19) + 0x55, 20, // UNIT_EXPONENT (20) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x04, // REPORT_SIZE (4) + 0xa4, // PUSH + /* Set the global state to C */ + 0x85, 23, // REPORT_ID (23) + 0x05, 24, // USAGE_PAGE (24) + 0x15, 27, // LOGICAL_MINIMUM (27) + 0x25, 28, // LOGICAL_MAXIMUM (28) + 0x35, 29, // PHYSICAL_MINIMUM (29) + 0x45, 30, // PHYSICAL_MAXIMUM (30) + 0x65, 31, // UNIT (31) + 0x55, 32, // UNIT_EXPONENT (32) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x06, // REPORT_SIZE (6) + 0xa4, // PUSH + /* Set the global state to D */ + 0x85, 35, // REPORT_ID (35) + 0x05, 36, // USAGE_PAGE (36) + 0x15, 39, // LOGICAL_MINIMUM (39) + 0x25, 40, // LOGICAL_MAXIMUM (40) + 0x35, 41, // PHYSICAL_MINIMUM (41) + 0x45, 42, // PHYSICAL_MAXIMUM (42) + 0x65, 43, // UNIT (43) + 0x55, 44, // UNIT_EXPONENT (44) + 0x95, 0x07, // REPORT_COUNT (7) + 0x75, 0x08, // REPORT_SIZE (8) + 0xa4, // PUSH + /* Set the global state to E */ + 0x85, 47, // REPORT_ID (47) + 0x05, 48, // USAGE_PAGE (48) + 0x15, 51, // LOGICAL_MINIMUM (51) + 0x25, 52, // LOGICAL_MAXIMUM (52) + 0x35, 53, // PHYSICAL_MINIMUM (53) + 0x45, 54, // PHYSICAL_MAXIMUM (54) + 0x65, 55, // UNIT (55) + 0x55, 56, // UNIT_EXPONENT (56) + 0x95, 0x09, // REPORT_COUNT (9) + 0x75, 0x0a, // REPORT_SIZE (10) + /* Pop state D */ + 0xb4, // POP + 0x81, 0x02, // INPUT (Data,Var,Abs) + /* Pop state C */ + 0xb4, // POP + 0x81, 0x02, // INPUT (Data,Var,Abs) + /* Pop state B */ + 0xb4, // POP + 0x81, 0x02, // INPUT (Data,Var,Abs) + /* Pop state A */ + 0xb4, // POP + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* USBX expects keyboards to have at least one output report, otherwise it's an error. */ + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + + 0xc0 // END_COLLECTION +}; +#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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_push_pop_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 Push Pop 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; +UX_HOST_CLASS_HID_REPORT *input_report_descriptor; +UX_HOST_CLASS_HID_FIELD *report_field; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the first input report descriptor (state D). */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + input_report_descriptor = report_id.ux_host_class_hid_report_get_report; + + /* Check the field in the report. */ + report_field = report_id.ux_host_class_hid_report_get_report -> ux_host_class_hid_report_field; + if( + report_field -> ux_host_class_hid_field_logical_min != 39 || + report_field -> ux_host_class_hid_field_logical_max != 40 || + report_field -> ux_host_class_hid_field_physical_min != 41 || + report_field -> ux_host_class_hid_field_physical_max != 42 || + report_field -> ux_host_class_hid_field_unit != 43 || + report_field -> ux_host_class_hid_field_unit_expo != 44 || + report_field -> ux_host_class_hid_field_report_id != 35 || + report_field -> ux_host_class_hid_field_report_count != 7 || + report_field -> ux_host_class_hid_field_report_size != 8 + ) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the second input report descriptor (state C). */ + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + input_report_descriptor = report_id.ux_host_class_hid_report_get_report; + + /* Check the field in the report. */ + report_field = report_id.ux_host_class_hid_report_get_report -> ux_host_class_hid_report_field; + if( + report_field -> ux_host_class_hid_field_logical_min != 27 || + report_field -> ux_host_class_hid_field_logical_max != 28 || + report_field -> ux_host_class_hid_field_physical_min != 29 || + report_field -> ux_host_class_hid_field_physical_max != 30 || + report_field -> ux_host_class_hid_field_unit != 31 || + report_field -> ux_host_class_hid_field_unit_expo != 32 || + report_field -> ux_host_class_hid_field_report_id != 23 || + report_field -> ux_host_class_hid_field_report_count != 5 || + report_field -> ux_host_class_hid_field_report_size != 6 + ) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the third input report descriptor (state B). */ + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + input_report_descriptor = report_id.ux_host_class_hid_report_get_report; + + /* Check the field in the report. */ + report_field = report_id.ux_host_class_hid_report_get_report -> ux_host_class_hid_report_field; + if( + report_field -> ux_host_class_hid_field_logical_min != 15 || + report_field -> ux_host_class_hid_field_logical_max != 16 || + report_field -> ux_host_class_hid_field_physical_min != 17 || + report_field -> ux_host_class_hid_field_physical_max != 18 || + report_field -> ux_host_class_hid_field_unit != 19 || + report_field -> ux_host_class_hid_field_unit_expo != 20 || + report_field -> ux_host_class_hid_field_report_id != 11 || + report_field -> ux_host_class_hid_field_report_count != 3 || + report_field -> ux_host_class_hid_field_report_size != 4 + ) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the fourth input report descriptor (state A). */ + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + input_report_descriptor = report_id.ux_host_class_hid_report_get_report; + + /* Check the field in the report. */ + report_field = report_id.ux_host_class_hid_report_get_report -> ux_host_class_hid_report_field; + if( + report_field -> ux_host_class_hid_field_logical_min != 3 || + report_field -> ux_host_class_hid_field_logical_max != 4 || + report_field -> ux_host_class_hid_field_physical_min != 5 || + report_field -> ux_host_class_hid_field_physical_max != 6 || + report_field -> ux_host_class_hid_field_unit != 7 || + report_field -> ux_host_class_hid_field_unit_expo != 8 || + report_field -> ux_host_class_hid_field_report_id != 1 || + report_field -> ux_host_class_hid_field_report_count != 1 || + report_field -> ux_host_class_hid_field_report_size != 2 + ) + { + + printf("Error on line %d\n", __LINE__); + 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_hid_report_descriptor_report_count_overflow_test.c b/test/regression/usbx_hid_report_descriptor_report_count_overflow_test.c new file mode 100644 index 00000000..4eb98bbc --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_report_count_overflow_test.c @@ -0,0 +1,294 @@ +/* This test ensures that the parser handles generates an error upon a REPORT_COUNT tag that specifies more the maximum allowable usages. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static UINT callback_error_code; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x75, 1, // REPORT_SIZE (1) + 0x96, (UCHAR)(UX_HOST_CLASS_HID_USAGES + 1), // REPORT_COUNT (UX_HOST_CLASS_HID_USAGES + 1) + 0x82, 0xab, 0x01, // INPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_HOST_CLASS_HID_USAGE_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_hid_report_descriptor_report_count_overflow_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 Report Count Overflow 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); + } + + /* 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_hid_report_descriptor_report_size_overflow_test.c b/test/regression/usbx_hid_report_descriptor_report_size_overflow_test.c new file mode 100644 index 00000000..2ed7017d --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_report_size_overflow_test.c @@ -0,0 +1,294 @@ +/* This test ensures that the parser handles generates an error upon a REPORT_SIZE tag that specifies over 32 bits of data. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static UINT callback_error_code; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x75, (UX_HOST_CLASS_HID_REPORT_SIZE + 1), // REPORT_SIZE (UX_HOST_CLASS_HID_REPORT_SIZE + 1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x82, 0xab, 0x01, // INPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_HOST_CLASS_HID_REPORT_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_hid_report_descriptor_report_size_overflow_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 Report Size Overflow 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); + } + + /* 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_hid_report_descriptor_single_usage_multiple_data_test.c b/test/regression/usbx_hid_report_descriptor_single_usage_multiple_data_test.c new file mode 100644 index 00000000..1e5c0e2c --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_single_usage_multiple_data_test.c @@ -0,0 +1,335 @@ +/* This test ensures that the parser correctly handles the case of a single usage and multiple data. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static UCHAR raw_output_report_buffer[1024]; +static SLONG decompressed_output_report_buffer[1024]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x30, // USAGE (X) - Single usage + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x03, // REPORT_COUNT (3) - Multiple data + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION +}; +#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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_single_usage_multiple_data_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 Single Usage Multiple Data 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; +UX_HOST_CLASS_HID_CLIENT_REPORT input_report_request; +UX_HOST_CLASS_HID_REPORT *input_report_descriptor; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the input report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + input_report_descriptor = report_id.ux_host_class_hid_report_get_report; + + /* Fill out the request. */ + input_report_request.ux_host_class_hid_client_report = input_report_descriptor; + input_report_request.ux_host_class_hid_client_report_buffer = decompressed_output_report_buffer; + input_report_request.ux_host_class_hid_client_report_length = input_report_descriptor -> ux_host_class_hid_report_byte_length; + input_report_request.ux_host_class_hid_client_report_actual_length = 0; + input_report_request.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_DECOMPRESSED; + + /* Request decompression. We don't care what's in raw_input_report_buffer since the usage is not dependent on it. */ + status = _ux_host_class_hid_report_decompress(hid, &input_report_request, raw_output_report_buffer, 1); + + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Check usages of decompression. */ + if ( + decompressed_output_report_buffer[0] != 0x00010030 || + decompressed_output_report_buffer[2] != 0x00010030 || + decompressed_output_report_buffer[4] != 0x00010030 + ) + { + + printf("Error on line %d\n", __LINE__); + 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_hid_report_descriptor_unknown_global_tag_test.c b/test/regression/usbx_hid_report_descriptor_unknown_global_tag_test.c new file mode 100644 index 00000000..f67975e7 --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_unknown_global_tag_test.c @@ -0,0 +1,294 @@ +/* This test ensures that the parser generates an error upon encountering an global local tag. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static UINT callback_error_code; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + /* Use an unknown global tag (0xf9). */ + 0xf5, 0x00, // ??? + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_HOST_CLASS_HID_TAG_UNSUPPORTED && + 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_hid_report_descriptor_unknown_global_tag_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 Unknown Global Tag 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); + } + + /* 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); +} \ No newline at end of file diff --git a/test/regression/usbx_hid_report_descriptor_unknown_local_tag_test.c b/test/regression/usbx_hid_report_descriptor_unknown_local_tag_test.c new file mode 100644 index 00000000..c7bbb5ed --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_unknown_local_tag_test.c @@ -0,0 +1,293 @@ +/* This test ensures that the parser generates an error upon encountering an unknown local tag. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static UINT callback_error_code; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + /* Use an unknown local tag (0xf9). */ + 0xf9, 0x00, // ??? + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_HOST_CLASS_HID_TAG_UNSUPPORTED && + 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_hid_report_descriptor_unknown_local_tag_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running HID Report Descriptor Unknown Local Tag 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); + } + + /* 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); +} \ No newline at end of file diff --git a/test/regression/usbx_hid_report_descriptor_usages_min_max_test.c b/test/regression/usbx_hid_report_descriptor_usages_min_max_test.c new file mode 100644 index 00000000..251d0e0c --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_usages_min_max_test.c @@ -0,0 +1,349 @@ +/* This test ensures that the parser handles the USAGE MINIMUM and USAGE MAXIMUM items. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static UCHAR raw_output_report_buffer[1024]; +static SLONG decompressed_output_report_buffer[1024]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x82, 0xab, 0x01, // INPUT (Data,Var,Abs) + + /* USBX expects keyboards to have at least one output report, otherwise it's an error. */ + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + + 0xc0 // END_COLLECTION +}; +#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 + }; + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_usages_min_max_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running HID Report Descriptor Usages Min Max 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; +UX_HOST_CLASS_HID_CLIENT_REPORT input_report_request; +UX_HOST_CLASS_HID_REPORT *input_report_descriptor; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the input report with ID 1. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + input_report_descriptor = report_id.ux_host_class_hid_report_get_report; + + /* Fill out the request. */ + input_report_request.ux_host_class_hid_client_report = input_report_descriptor; + input_report_request.ux_host_class_hid_client_report_buffer = decompressed_output_report_buffer; + input_report_request.ux_host_class_hid_client_report_length = input_report_descriptor -> ux_host_class_hid_report_byte_length; + input_report_request.ux_host_class_hid_client_report_actual_length = 0; + input_report_request.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_DECOMPRESSED; + + /* Fill out raw input report buffer to parse. */ + raw_output_report_buffer[0] = 0xaa; + + /* Request decompression. */ + status = _ux_host_class_hid_report_decompress(hid, &input_report_request, raw_output_report_buffer, 1); + + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Check usages of decompression. */ + if ( + decompressed_output_report_buffer[0] != 0x000700e0 || + decompressed_output_report_buffer[2] != 0x000700e1 || + decompressed_output_report_buffer[4] != 0x000700e2 || + decompressed_output_report_buffer[6] != 0x000700e3 || + decompressed_output_report_buffer[8] != 0x000700e4 || + decompressed_output_report_buffer[10] != 0x000700e5 || + decompressed_output_report_buffer[12] != 0x000700e6 || + decompressed_output_report_buffer[14] != 0x000700e7 + ) + { + + printf("Error on line %d\n", __LINE__); + 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_hid_report_descriptor_usages_overflow_test.c b/test/regression/usbx_hid_report_descriptor_usages_overflow_test.c new file mode 100644 index 00000000..d5834deb --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_usages_overflow_test.c @@ -0,0 +1,298 @@ +/* This test ensures that the parser fails when too many usages are used. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +UINT callback_error_code; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x80, // USAGE_PAGE (Monitor) + 0x09, 0x01, // USAGE (Monitor Control) + 0xa1, 0x01, // COLLECTION (Application) + + /* Add the maximum number of usages. */ + 0x19, 0x00, // USAGE_MINIMUM (0) + 0x2a, 0xff, 0x03, // USAGE_MAXIMUM (1023) + + /* Add one more usage. */ + 0x09, 0x00, // USAGE (0) + + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x82, 0xab, 0x01, // INPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_HOST_CLASS_HID_USAGE_OVERFLOW && + error_code != UX_DESCRIPTOR_CORRUPTED) + { + + /* 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_hid_report_descriptor_usages_overflow_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running HID Report Descriptor Usages Overflow 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); + } + + /* 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_hid_report_descriptor_usages_overflow_via_max_test.c b/test/regression/usbx_hid_report_descriptor_usages_overflow_via_max_test.c new file mode 100644 index 00000000..a815cda6 --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_usages_overflow_via_max_test.c @@ -0,0 +1,295 @@ +/* This test ensures that the parser fails when too many usages are used. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +UINT callback_error_code; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x80, // USAGE_PAGE (Monitor) + 0x09, 0x01, // USAGE (Monitor Control) + 0xa1, 0x01, // COLLECTION (Application) + + /* Add the maximum number of usages. */ + 0x19, 0x00, // USAGE_MINIMUM (0) + 0x2a, 0xff, 0x04, // USAGE_MAXIMUM (1024) + + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x82, 0xab, 0x01, // INPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_HOST_CLASS_HID_USAGE_OVERFLOW && + error_code != UX_DESCRIPTOR_CORRUPTED) + { + + /* 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_hid_report_descriptor_usages_overflow_via_max_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running HID Report Descriptor Usages Overflow Via Max 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); + } + + /* 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_hid_report_descriptor_usages_single_test.c b/test/regression/usbx_hid_report_descriptor_usages_single_test.c new file mode 100644 index 00000000..e56b3d46 --- /dev/null +++ b/test/regression/usbx_hid_report_descriptor_usages_single_test.c @@ -0,0 +1,345 @@ +/* This test ensures that the parser correctly handles the USAGE item. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +static UCHAR raw_output_report_buffer[1024]; +static SLONG decompressed_output_report_buffer[1024]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x09, 0x32, // USAGE (Z) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x03, // REPORT_COUNT (3) + 0x81, 0x06, // INPUT (Data,Var,Rel) + + /* USBX expects keyboards to have at least one output report, otherwise it's an error. */ + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + + 0xc0, // END_COLLECTION +}; +#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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_descriptor_usages_single_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running HID Report Descriptor Usages Single 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; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; +UX_HOST_CLASS_HID_CLIENT_REPORT input_report_request; +UX_HOST_CLASS_HID_REPORT *input_report_descriptor; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the input report with ID 1. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + input_report_descriptor = report_id.ux_host_class_hid_report_get_report; + + /* Fill out the request. */ + input_report_request.ux_host_class_hid_client_report = input_report_descriptor; + input_report_request.ux_host_class_hid_client_report_buffer = decompressed_output_report_buffer; + input_report_request.ux_host_class_hid_client_report_length = input_report_descriptor -> ux_host_class_hid_report_byte_length; + input_report_request.ux_host_class_hid_client_report_actual_length = 0; + input_report_request.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_DECOMPRESSED; + + /* Request decompression. We don't care what's in raw_input_report_buffer since the usage is not dependent on it. */ + status = _ux_host_class_hid_report_decompress(hid, &input_report_request, raw_output_report_buffer, 1); + + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Check usages of decompression. */ + if ( + decompressed_output_report_buffer[0] != 0x00010030 || + decompressed_output_report_buffer[2] != 0x00010031 || + decompressed_output_report_buffer[4] != 0x00010032 + ) + { + + printf("Error on line %d\n", __LINE__); + 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_hid_report_multiple_reports_ids_test.c b/test/regression/usbx_hid_report_multiple_reports_ids_test.c new file mode 100644 index 00000000..18503506 --- /dev/null +++ b/test/regression/usbx_hid_report_multiple_reports_ids_test.c @@ -0,0 +1,603 @@ +/* This test ensures that the parser correctly handles multiple report IDs for input reports. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + +#define TEST_LOG_N 8 + +static TX_SEMAPHORE test_semaphore_host_wakes_device; + +static ULONG test_log_count = 0; +static ULONG test_log_index = 0; +static INT test_log_report_id[TEST_LOG_N] = {-1}; +static UCHAR test_log_report_data[TEST_LOG_N][32]; +static ULONG test_log_report_data_len[TEST_LOG_N]; + +static UCHAR test_device_report_id = 0; +static UCHAR test_device_report_count = 1; +static UCHAR test_device_report_fill = 0x5A; +static UCHAR test_device_report_len = 1; /* Without ID */ + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + + /* 0: 4 x 1-bit values */ + 0x19, 0x01, // USAGE_MINIMUM (1) + 0x29, 0x04, // USAGE_MAXIMUM (4) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x04, // REPORT_COUNT (4) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* 2: 3 x bytes */ + 0x85, 0x02, // REPORT_ID (2) + 0x19, 0x05, // USAGE_MINIMUM (5) + 0x29, 0x07, // USAGE_MAXIMUM (7) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x03, // REPORT_COUNT (3) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* 4: 1 x 16-bit value */ + 0x85, 0x04, // REPORT_ID (4) + 0x09, 0x08, // USAGE (8) + 0x75, 0x10, // REPORT_SIZE (16) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + /* USBX expects keyboards to have at least one output report, otherwise it's an error. */ + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + + 0xc0, // END_COLLECTION +}; +#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 + }; + + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + /* Fine, HID client not registered. */ + if (error_code == UX_HOST_CLASS_HID_UNKNOWN) + return; + + /* Failed test. */ + printf("Error on line %d, system_level: %x, system_context: %x, error code: %x\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_report_multiple_reports_ids_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 Multiple Reports IDs 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); + } + + /* 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; + /* Report ID not inserted from event field, we manage buffer by ourselvs. */ + hid_parameter.ux_device_class_hid_parameter_report_id = UX_FALSE; + + /* 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); + } + + UX_TEST_CHECK_SUCCESS(ux_utility_semaphore_create(&test_semaphore_host_wakes_device, "test_semaphore_host_wakes_device", 0)); + + /* 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); + } + + /* Create the main device thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, 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 inline void test_log_reset(UCHAR data_fill) +{ +ULONG i; + test_log_count = 0; + test_log_index = 0; + for (i = 0; i < TEST_LOG_N; i ++) + test_log_report_id[i] = -1; + ux_utility_memory_set(test_log_report_data_len, 0, sizeof(test_log_report_data_len)); + ux_utility_memory_set(test_log_report_data, 0, sizeof(test_log_report_data)); +} +static inline void test_log_add(UCHAR report_id, UCHAR *data_buf, ULONG data_size) +{ + test_log_count ++; + if (test_log_index < TEST_LOG_N) + { + test_log_report_id[test_log_index] = report_id; + test_log_report_data_len[test_log_index] = data_size; + if (data_size) + ux_utility_memory_copy(test_log_report_data[test_log_index], data_buf, data_size); + test_log_index ++; + } +} + +static VOID demo_host_class_hid_report0_callback(UX_HOST_CLASS_HID_REPORT_CALLBACK *callback) +{ + test_log_add(0, callback->ux_host_class_hid_report_callback_buffer,callback->ux_host_class_hid_report_callback_actual_length); +} +static VOID demo_host_class_hid_report2_callback(UX_HOST_CLASS_HID_REPORT_CALLBACK *callback) +{ + test_log_add(2, callback->ux_host_class_hid_report_callback_buffer,callback->ux_host_class_hid_report_callback_actual_length); +} +static VOID demo_host_class_hid_report4_callback(UX_HOST_CLASS_HID_REPORT_CALLBACK *callback) +{ + test_log_add(4, callback->ux_host_class_hid_report_callback_buffer,callback->ux_host_class_hid_report_callback_actual_length); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; +UX_HOST_CLASS_HID_CLIENT_REPORT input_report_request; +UX_HOST_CLASS_HID_REPORT *input_report_descriptor; +UX_HOST_CLASS_HID_REPORT_CALLBACK call_back; +ULONG c, i; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Start periodic report transfer. */ + _ux_host_class_hid_periodic_report_start(hid); + + /* Reset logs. */ + test_log_reset(0); + + /* Trigger device events. */ + test_device_report_id = 1; + test_device_report_count = 2; + test_device_report_fill = 0xef; /* 0xef, 0xf0 */ + test_device_report_len = 3; /* ... */ + UX_TEST_CHECK_SUCCESS(ux_utility_semaphore_put(&test_semaphore_host_wakes_device)); + + /* Check received callbacks. */ + tx_thread_sleep(50); + UX_TEST_ASSERT(test_log_count == 0); + + /* Get the first input report descriptor. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + input_report_descriptor = report_id.ux_host_class_hid_report_get_report; + if (input_report_descriptor -> ux_host_class_hid_report_id != 0) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Register callback for the report descriptor. */ + call_back.ux_host_class_hid_report_callback_id = input_report_descriptor -> ux_host_class_hid_report_id; + call_back.ux_host_class_hid_report_callback_function = demo_host_class_hid_report0_callback; + call_back.ux_host_class_hid_report_callback_flags = UX_HOST_CLASS_HID_REPORT_RAW; + call_back.ux_host_class_hid_report_callback_buffer = UX_NULL; + call_back.ux_host_class_hid_report_callback_length = 0; + status = _ux_host_class_hid_report_callback_register(hid, &call_back); + + /* Reset logs. */ + test_log_reset(0); + + /* Trigger device events. */ + test_device_report_id = 0; + test_device_report_count = 3; + test_device_report_fill = 0x30; /* 0x30, 0x31, 0x32 */ + test_device_report_len = 1; /* 4 x 1-bit value. */ + UX_TEST_CHECK_SUCCESS(ux_utility_semaphore_put(&test_semaphore_host_wakes_device)); + + /* Check received callbacks. */ + tx_thread_sleep(50); + UX_TEST_ASSERT(test_log_count == 3); + for (c = 0; c < 3; c ++) + { + UX_TEST_ASSERT(test_log_report_id[c] == 0); + UX_TEST_ASSERT(test_log_report_data_len[c] == 2); + UX_TEST_ASSERT(test_log_report_data[c][0] == 0); + UX_TEST_ASSERT(test_log_report_data[c][1] == (0x30 + c)); + } + + /* Get the second input report descriptor. */ + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + input_report_descriptor = report_id.ux_host_class_hid_report_get_report; + if (input_report_descriptor->ux_host_class_hid_report_id != 2) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Register callback for the report descriptor. */ + call_back.ux_host_class_hid_report_callback_id = input_report_descriptor -> ux_host_class_hid_report_id; + call_back.ux_host_class_hid_report_callback_function = demo_host_class_hid_report2_callback; + call_back.ux_host_class_hid_report_callback_flags = UX_HOST_CLASS_HID_REPORT_RAW; + call_back.ux_host_class_hid_report_callback_buffer = UX_NULL; + call_back.ux_host_class_hid_report_callback_length = 0; + status = _ux_host_class_hid_report_callback_register(hid, &call_back); + + /* Reset logs. */ + test_log_reset(0); + + /* Trigger device events. */ + test_device_report_id = 2; + test_device_report_count = 5; + test_device_report_fill = 0x52; /* 0x52 .. 0x56 */ + test_device_report_len = 3; /* 3 x bytes. */ + UX_TEST_CHECK_SUCCESS(ux_utility_semaphore_put(&test_semaphore_host_wakes_device)); + + /* Check received callbacks. */ + tx_thread_sleep(50); + UX_TEST_ASSERT(test_log_count == test_device_report_count); + for (c = 0; c < test_device_report_count; c ++) + { + UX_TEST_ASSERT(test_log_report_id[c] == test_device_report_id); + UX_TEST_ASSERT(test_log_report_data_len[c] == test_device_report_len+1); + UX_TEST_ASSERT(test_log_report_data[c][0] == test_device_report_id); + for (i = 0; i < test_device_report_len; i ++) + UX_TEST_ASSERT(test_log_report_data[c][1 + i] == + (test_device_report_fill + c)); + } + + + /* Get the third input report descriptor. */ + status = ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + input_report_descriptor = report_id.ux_host_class_hid_report_get_report; + if (input_report_descriptor->ux_host_class_hid_report_id != 4) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Register callback for the report descriptor. */ + call_back.ux_host_class_hid_report_callback_id = input_report_descriptor -> ux_host_class_hid_report_id; + call_back.ux_host_class_hid_report_callback_function = demo_host_class_hid_report4_callback; + call_back.ux_host_class_hid_report_callback_flags = UX_HOST_CLASS_HID_REPORT_RAW; + call_back.ux_host_class_hid_report_callback_buffer = UX_NULL; + call_back.ux_host_class_hid_report_callback_length = 0; + status = _ux_host_class_hid_report_callback_register(hid, &call_back); + + /* Reset logs. */ + test_log_reset(0); + + /* Trigger device events. */ + test_device_report_id = 4; + test_device_report_count = 7; + test_device_report_fill = 0x77; /* 0x77 .. 0x7D */ + test_device_report_len = 2; /* 1 x 16-bit value. */ + UX_TEST_CHECK_SUCCESS(ux_utility_semaphore_put(&test_semaphore_host_wakes_device)); + + /* Check received callbacks. */ + tx_thread_sleep(50); + UX_TEST_ASSERT(test_log_count == test_device_report_count); + for (c = 0; c < test_device_report_count; c ++) + { + UX_TEST_ASSERT(test_log_report_id[c] == test_device_report_id); + UX_TEST_ASSERT(test_log_report_data_len[c] == test_device_report_len+1); + UX_TEST_ASSERT(test_log_report_data[c][0] == test_device_report_id); + for (i = 0; i < test_device_report_len; i ++) + UX_TEST_ASSERT(test_log_report_data[c][1 + i] == + (test_device_report_fill + c)); + } + + + /* 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); +} + +static void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + +UX_SLAVE_DEVICE *device; +UX_SLAVE_INTERFACE *interface; +UX_SLAVE_CLASS_HID *hid; +UX_SLAVE_CLASS_HID_EVENT hid_event; +ULONG i; + + /* Get the pointer to the device. */ + device = &_ux_system_slave -> ux_system_slave_device; + + /* reset the HID event structure. */ + ux_utility_memory_set(&hid_event, 0, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + + while (1) + { + + /* Is the device configured ? */ + while (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED) + + /* Then wait. */ + tx_thread_sleep(10); + + /* Until the device stays configured. */ + while (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED) + { + + /* Get the interface. We use the first interface, this is a simple device. */ + interface = device -> ux_slave_device_first_interface; + + /* From that interface, derive the HID owner. */ + hid = interface -> ux_slave_interface_class_instance; + + /* Wait for host to trigger. */ + UX_TEST_CHECK_SUCCESS(ux_utility_semaphore_get(&test_semaphore_host_wakes_device, UX_WAIT_FOREVER)); + + for (i = 0; i < test_device_report_count; i ++) + { + + /* Build the event to test. */ + + /* Set length of event. */ + hid_event.ux_device_class_hid_event_length = test_device_report_len + 1; + + /* Set ID. */ + hid_event.ux_device_class_hid_event_buffer[0] = test_device_report_id; + + /* Set fills. */ + ux_utility_memory_set(&hid_event.ux_device_class_hid_event_buffer[1], + test_device_report_fill + i, + test_device_report_len); + + /* Set the mouse event. */ + ux_device_class_hid_event_set(hid, &hid_event); + } + } + } +} \ No newline at end of file diff --git a/test/regression/usbx_hid_transfer_request_completed_decompressed_test.c b/test/regression/usbx_hid_transfer_request_completed_decompressed_test.c new file mode 100644 index 00000000..fd889602 --- /dev/null +++ b/test/regression/usbx_hid_transfer_request_completed_decompressed_test.c @@ -0,0 +1,481 @@ +/* This test concentrates on _ux_host_class_hid_transfer_request_completed()'s decompressed handling. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" +#include "ux_host_class_hid_mouse.h" + + +static UX_HOST_CLASS_HID_MOUSE *mouse; +static UINT callback_error_code; +static UINT num_callbacks; + + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 52 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00, + 0x00, + + /* HID descriptor */ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH), + MSB(HID_MOUSE_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 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_MOUSE_REPORT_LENGTH), + MSB(HID_MOUSE_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 + }; + + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* @BUG_FIX_PENDING: ux_dcd_sim_slave_function.c doesn't support transfer aborts, which happen during device unregistration of a class. */ + if (error_code != UX_FUNCTION_NOT_SUPPORTED) + { + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_transfer_request_completed_decompressed_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running HID Transfer Request Completed Decompressed 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_mouse_name, ux_host_class_hid_mouse_entry); + if (status != UX_SUCCESS) + { + + printf("Error on line %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 on line %d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the hid class parameters for a mouse. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_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); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, 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); + } + +} + + +VOID dummy_transfer_request_callback(UX_HOST_CLASS_HID_REPORT_CALLBACK *callback) +{ + +static INT expected_button_value = -1; +static INT expected_x_value = -1; +static INT expected_y_value = -1; +static INT expected_mouse_wheel_value = -1; +INT actual_button_value; +INT actual_x_value; +INT actual_y_value; +INT actual_mouse_wheel_value; +ULONG *buffer; + + + buffer = callback->ux_host_class_hid_report_callback_buffer; + + actual_button_value = ( + buffer[1] << 0 | + buffer[3] << 1 | + buffer[5] << 2 + ); + + actual_x_value = buffer[9]; + actual_y_value = buffer[11]; + actual_mouse_wheel_value = buffer[13]; + + /* If uninitialized, initialize expected_value. */ + if (expected_button_value == -1) + { + + expected_button_value = actual_button_value; + expected_x_value = actual_x_value; + expected_y_value = actual_y_value; + expected_mouse_wheel_value = actual_mouse_wheel_value; + } + + if (actual_button_value != expected_button_value || + actual_x_value != expected_x_value || + actual_y_value != expected_y_value || + actual_mouse_wheel_value != expected_mouse_wheel_value) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + expected_button_value = (0x7 & (expected_button_value + 1)); + expected_x_value++; + expected_y_value++; + expected_mouse_wheel_value++; + + num_callbacks++; +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_REPORT_CALLBACK callback; +UCHAR buffer[1024]; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the mouse instance */ + mouse = (UX_HOST_CLASS_HID_MOUSE *)hid_client -> ux_host_class_hid_client_local_instance; + + /* Initialize the report callback. */ + callback.ux_host_class_hid_report_callback_id = 0; + callback.ux_host_class_hid_report_callback_function = dummy_transfer_request_callback; + callback.ux_host_class_hid_report_callback_buffer = buffer; + callback.ux_host_class_hid_report_callback_flags = UX_HOST_CLASS_HID_REPORT_DECOMPRESSED; + callback.ux_host_class_hid_report_callback_length = sizeof(buffer); + + status = ux_host_class_hid_report_callback_register(hid, &callback); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Wait until callback has been invoked at least 16 times. */ + while(num_callbacks < 16) + tx_thread_sleep(10); + + /* 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); +} + +static void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + +UX_SLAVE_DEVICE *device; +UX_SLAVE_INTERFACE *interface; +UX_SLAVE_CLASS_HID *hid; +UX_SLAVE_CLASS_HID_EVENT hid_event; + + /* Get the pointer to the device. */ + device = &_ux_system_slave -> ux_system_slave_device; + + /* reset the HID event structure. */ + ux_utility_memory_set(&hid_event, 0, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + + /* Set length of event. */ + hid_event.ux_device_class_hid_event_length = 4; + + /* Set initial value for buttons. The first three bits are for buttons, the rest are padding. */ + hid_event.ux_device_class_hid_event_buffer[0] = 1; + + /* Set initial value for x and y positions. */ + hid_event.ux_device_class_hid_event_buffer[1] = 2; + hid_event.ux_device_class_hid_event_buffer[2] = 3; + + /* Set initial value for mouse wheel. */ + hid_event.ux_device_class_hid_event_buffer[3] = 4; + + while (1) + { + + /* Is the device configured ? */ + while (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED) + + /* Then wait. */ + tx_thread_sleep(10); + + /* Until the device stays configured. */ + while (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED) + { + + /* Get the interface. We use the first interface, this is a simple device. */ + interface = device -> ux_slave_device_first_interface; + + /* From that interface, derive the HID owner. */ + hid = interface -> ux_slave_interface_class_instance; + + /* Sleep for 1 second. */ + ux_utility_thread_sleep(10); + + /* Set the mouse event. */ + ux_device_class_hid_event_set(hid, &hid_event); + + /* Increment. */ + hid_event.ux_device_class_hid_event_buffer[0] = (0x7 & hid_event.ux_device_class_hid_event_buffer[0] + 1); + hid_event.ux_device_class_hid_event_buffer[1]++; + hid_event.ux_device_class_hid_event_buffer[2]++; + hid_event.ux_device_class_hid_event_buffer[3]++; + } + } +} \ No newline at end of file diff --git a/test/regression/usbx_hid_transfer_request_completed_raw_test.c b/test/regression/usbx_hid_transfer_request_completed_raw_test.c new file mode 100644 index 00000000..5461c541 --- /dev/null +++ b/test/regression/usbx_hid_transfer_request_completed_raw_test.c @@ -0,0 +1,457 @@ +/* This test concentrates on _ux_host_class_hid_transfer_request_completed()'s raw process handling. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + +#include "ux_host_class_hid_mouse.h" + + +static UX_HOST_CLASS_HID_MOUSE *mouse; +static UINT callback_error_code; +static UINT num_callbacks; + + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 52 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00, + 0x00, + + /* HID descriptor */ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH), + MSB(HID_MOUSE_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 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_MOUSE_REPORT_LENGTH), + MSB(HID_MOUSE_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 + }; + + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_BUFFER_OVERFLOW) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + callback_error_code = error_code; +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_transfer_request_completed_raw_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running HID Transfer Request Completed Raw 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_mouse_name, ux_host_class_hid_mouse_entry); + if (status != UX_SUCCESS) + { + + printf("Error on line %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 on line %d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the hid class parameters for a mouse. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_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); + } + + + /* 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); + } + + /* 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); + } + + /* 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); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, 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); + } + +} + +#define MAX_NUM_CALLBACKS 16 + +VOID dummy_transfer_request_callback_successful(UX_HOST_CLASS_HID_REPORT_CALLBACK *callback) +{ + + static INT expected_value = -1; + ULONG actual_value; + + actual_value = *((ULONG *)callback->ux_host_class_hid_report_callback_buffer); + + /* If uninitialized, initialize expected_value. */ + if (expected_value == -1) + expected_value = actual_value; + + if (actual_value != expected_value) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + expected_value++; + num_callbacks++; +} + +VOID dummy_transfer_request_callback_failure(UX_HOST_CLASS_HID_REPORT_CALLBACK *callback) +{ + +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_REPORT_CALLBACK callback; +UCHAR buffer[1024]; + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /**************************************************/ + /** Test case: successful raw report callback. **/ + /**************************************************/ + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the mouse instance */ + mouse = (UX_HOST_CLASS_HID_MOUSE *)hid_client -> ux_host_class_hid_client_local_instance; + + /* Initialize the report callback. */ + callback.ux_host_class_hid_report_callback_id = 0; + callback.ux_host_class_hid_report_callback_function = dummy_transfer_request_callback_successful; + callback.ux_host_class_hid_report_callback_buffer = buffer; + callback.ux_host_class_hid_report_callback_flags = UX_HOST_CLASS_HID_REPORT_RAW; + callback.ux_host_class_hid_report_callback_length = sizeof(buffer); + + ux_host_class_hid_report_callback_register(hid, &callback); + + /* Wait until callback has been invoked at least MAX_NUM_CALLBACKS times. */ + while(num_callbacks < MAX_NUM_CALLBACKS) + tx_thread_sleep(10); +#if 0 /* User buffer is not assigned on initialize, see USBX-283 */ + /**************************************************/ + /** Test case: callback buffer too small. **/ + /**************************************************/ + + /* Change the length to a small value. */ + callback.ux_host_class_hid_report_callback_function = dummy_transfer_request_callback_failure; + callback.ux_host_class_hid_report_callback_length = 1; + + ux_host_class_hid_report_callback_register(hid, &callback); + + /* Wait until we receive the expected error. */ + while(callback_error_code != UX_BUFFER_OVERFLOW) + tx_thread_sleep(10); +#endif + /* 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); +} + +static void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + +UX_SLAVE_DEVICE *device; +UX_SLAVE_INTERFACE *interface; +UX_SLAVE_CLASS_HID *hid; +UX_SLAVE_CLASS_HID_EVENT hid_event; +UINT i; + + /* Get the pointer to the device. */ + device = &_ux_system_slave -> ux_system_slave_device; + + /* reset the HID event structure. */ + ux_utility_memory_set(&hid_event, 0, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + + /* Set length of event. */ + hid_event.ux_device_class_hid_event_length = 4; + + *((ULONG *)hid_event.ux_device_class_hid_event_buffer) = 0; + + while (1) + { + + /* Is the device configured ? */ + while (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED) + + /* Then wait. */ + tx_thread_sleep(10); + + /* Get the interface. We use the first interface, this is a simple device. */ + interface = device->ux_slave_device_first_interface; + + /* From that interface, derive the HID owner. */ + hid = interface->ux_slave_interface_class_instance; + + for (i = 0; i < MAX_NUM_CALLBACKS; i++) + { + + /* Sleep for 1 second. */ + ux_utility_thread_sleep(10); + + /* Set the mouse event. */ + ux_device_class_hid_event_set(hid, &hid_event); + + /* Increment. */ + *((ULONG *)hid_event.ux_device_class_hid_event_buffer) += 1; + } + } +} \ No newline at end of file diff --git a/test/regression/usbx_hid_transfer_request_completed_test.c b/test/regression/usbx_hid_transfer_request_completed_test.c new file mode 100644 index 00000000..786c8c07 --- /dev/null +++ b/test/regression/usbx_hid_transfer_request_completed_test.c @@ -0,0 +1,513 @@ +/* This test concentrates on failed hid transfer requests and ensuring they're resent and received correctly. + * Note: USBX HID has a thread for polling the device. Upon completion, ux_host_class_hid_transfer_request_completed is called, + * and if the transfer request status is set to unsuccessful, ux_host_class_hid_transfer_request_completed retries the transfer request. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_mouse.h" +#include "ux_test.h" + + +static UX_HOST_CLASS_HID_MOUSE *mouse; +static TX_SEMAPHORE test_semaphore_host_wakes_slave; + + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 52 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00, + 0x00, + + /* HID descriptor */ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH), + MSB(HID_MOUSE_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 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_MOUSE_REPORT_LENGTH), + MSB(HID_MOUSE_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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_transfer_request_completed_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; + + + /* Inform user. */ + printf("Running HID Transfer Request Completed 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_mouse_name, ux_host_class_hid_mouse_entry); + if (status != UX_SUCCESS) + { + + printf("Error on line %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 on line %d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the hid class parameters for a mouse. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_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); + } + + UX_TEST_CHECK_SUCCESS(ux_utility_semaphore_create(&test_semaphore_host_wakes_slave, "test_semaphore_host_wakes_slave", 0)); + + /* 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); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, 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); + } +} + + +UINT num_transfer_requests; + +static UINT ux_hcd_sim_host_entry_filter(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; + UX_TRANSFER *transfer_request; + + if (function == UX_HCD_TRANSFER_REQUEST) + { + + transfer_request = (UX_TRANSFER *)parameter; + /* Fail every three times. */ + if(transfer_request -> ux_transfer_request_completion_function == _ux_host_class_hid_transfer_request_completed && + (num_transfer_requests++ % 3) == 0) + { + + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_ERROR; + transfer_request -> ux_transfer_request_completion_function(transfer_request); + + status = transfer_request -> ux_transfer_request_completion_code; + } + else + { + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + } + } + else + { + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + } + + return status; +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UINT max_num_loops; +UINT num_loops; +SLONG cur_mouse_wheel_movement; +SLONG next_mouse_wheel_movement; +SLONG cur_mouse_x_position; +SLONG cur_mouse_y_position; +SLONG next_mouse_x_position; +SLONG next_mouse_y_position; +ULONG cur_mouse_buttons; +UCHAR next_mouse_buttons; +UX_HCD *hcd; + + + /* Initilize max loop value. */ + max_num_loops = 16; + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the mouse instance */ + mouse = (UX_HOST_CLASS_HID_MOUSE *)hid_client -> ux_host_class_hid_client_local_instance; + + /* Change the hcd entry function to our filter function. */ + hcd = UX_DEVICE_HCD_GET(hid -> ux_host_class_hid_device); + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter; + + /* Set number of successful loops to execute. */ + num_loops = 0; + max_num_loops = 16; + + /* Set initial mouse button values. */ + next_mouse_buttons = 0x01; + + /* Set initial mouse position values. */ + next_mouse_x_position = -8; + next_mouse_y_position = -8; + + /* Set initial mouse wheel value. */ + next_mouse_wheel_movement = -8; + + while (num_loops++ != max_num_loops) + { + + /* Wait for device to send. */ + tx_thread_sleep(50); + + UX_TEST_CHECK_SUCCESS(ux_host_class_hid_mouse_buttons_get(mouse, &cur_mouse_buttons)); + UX_TEST_CHECK_SUCCESS(ux_host_class_hid_mouse_position_get(mouse, &cur_mouse_x_position, &cur_mouse_y_position)); + UX_TEST_CHECK_SUCCESS(ux_host_class_hid_mouse_wheel_get(mouse, &cur_mouse_wheel_movement)); + + /* Ensure these are the expected values. */ + UX_TEST_ASSERT(cur_mouse_buttons == next_mouse_buttons && + cur_mouse_x_position == next_mouse_x_position && + cur_mouse_y_position == next_mouse_y_position && + cur_mouse_wheel_movement == next_mouse_wheel_movement); + + /* Increment values. */ + next_mouse_buttons = 0x07 & (next_mouse_buttons + 1); + next_mouse_x_position++; + next_mouse_y_position++; + next_mouse_wheel_movement++; + + /* Tell the device to send the next. */ + UX_TEST_CHECK_SUCCESS(ux_utility_semaphore_put(&test_semaphore_host_wakes_slave)); + } + + /* 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); +} + +static void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + +UX_SLAVE_DEVICE *device; +UX_SLAVE_INTERFACE *interface; +UX_SLAVE_CLASS_HID *hid; +UX_SLAVE_CLASS_HID_EVENT hid_event; + + /* Get the pointer to the device. */ + device = &_ux_system_slave -> ux_system_slave_device; + + /* reset the HID event structure. */ + ux_utility_memory_set(&hid_event, 0, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + + /* Set length of event. */ + hid_event.ux_device_class_hid_event_length = 4; + + /* Set initial value for buttons. The first three bits are for buttons, the rest are padding. */ + hid_event.ux_device_class_hid_event_buffer[0] = 1; + + /* Set initial value for x and y positions. */ + hid_event.ux_device_class_hid_event_buffer[1] = -8; + hid_event.ux_device_class_hid_event_buffer[2] = -8; + + /* Set initial value for mouse wheel. */ + hid_event.ux_device_class_hid_event_buffer[3] = -8; + + while (1) + { + + /* Is the device configured ? */ + while (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED) + + /* Then wait. */ + tx_thread_sleep(10); + + /* Until the device stays configured. */ + while (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED) + { + + /* Get the interface. We use the first interface, this is a simple device. */ + interface = device -> ux_slave_device_first_interface; + + /* From that interface, derive the HID owner. */ + hid = interface -> ux_slave_interface_class_instance; + + /* Set the mouse event. */ + ux_device_class_hid_event_set(hid, &hid_event); + + /* Change the buttons. */ + hid_event.ux_device_class_hid_event_buffer[0] = (0x7 & hid_event.ux_device_class_hid_event_buffer[0] + 1); + + /* Change the x, y, and wheel positions. These are relative values. */ + hid_event.ux_device_class_hid_event_buffer[1] = 1; + hid_event.ux_device_class_hid_event_buffer[2] = 1; + hid_event.ux_device_class_hid_event_buffer[3] = 1; + + /* Wait for host to receive. */ + UX_TEST_CHECK_SUCCESS(ux_utility_semaphore_get(&test_semaphore_host_wakes_slave, UX_WAIT_FOREVER)); + } + } +} \ No newline at end of file diff --git a/test/regression/usbx_host_class_hub_port_change_connection_process_coverage_test.c b/test/regression/usbx_host_class_hub_port_change_connection_process_coverage_test.c new file mode 100644 index 00000000..51288b59 --- /dev/null +++ b/test/regression/usbx_host_class_hub_port_change_connection_process_coverage_test.c @@ -0,0 +1,117 @@ +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" +#include "ux_test.h" +#include "ux_host_class_hub.h" +#include "ux_test_utility_sim.h" + + +static UINT count = 0; +static UINT hcd_entry_function(UX_HCD *hcd_ptr, UINT request, VOID *_transfer_request) +{ +USHORT *port_status; +USHORT *port_change; +UX_TRANSFER *transfer_request = (UX_TRANSFER*)_transfer_request; + if (request == UX_HCD_CREATE_ENDPOINT || request == UX_HCD_DESTROY_ENDPOINT) + return(UX_SUCCESS); + + if(transfer_request -> ux_transfer_request_function == UX_HOST_CLASS_HUB_GET_STATUS) + { + port_status = (USHORT*)(transfer_request -> ux_transfer_request_data_pointer); + port_change = (USHORT*)(transfer_request -> ux_transfer_request_data_pointer + 2); + + *port_change = UX_HOST_CLASS_HUB_PORT_CHANGE_RESET; + if (count != 1) + *port_status = UX_HOST_CLASS_HUB_PORT_STATUS_CONNECTION; + else + *port_status = 0; + count++; + transfer_request -> ux_transfer_request_actual_length = 4; + } + + return UX_SUCCESS; +} + +static UINT change_function(ULONG status, UX_HOST_CLASS *host_class_ptr, VOID* ptr) +{ + return (UX_SUCCESS); +} + +static UX_HOST_CLASS_HUB hub; +static UX_DEVICE hub_device; +static UX_DEVICE device1, device2; +extern UX_SYSTEM_HOST *_ux_system_host; +static UX_SYSTEM_HOST ux_system_host; +static UX_HCD ux_hcd; +static UX_ENDPOINT transfer_request_endpoint; +#define USB_MEMORY_POOL_SIZE (16*1024) +#define USB_CACHE_SAFE_MEMORY_POOL_SIZE (16*1024) +static ULONG usb_memory_pool_area[USB_MEMORY_POOL_SIZE / sizeof(ULONG)]; +static ULONG usb_cache_safe_memory_pool_area[USB_CACHE_SAFE_MEMORY_POOL_SIZE / sizeof(ULONG)]; +static UX_DEVICE device_array[2]; +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_host_class_hub_port_change_connection_process_coverage_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status = 0; +UINT port = 0; +UINT port_status; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; + + + /* Inform user. */ + printf("Running USB host Class Hub Port Change Coverage Test ............... "); + + ux_system_initialize(usb_memory_pool_area, USB_MEMORY_POOL_SIZE, + usb_cache_safe_memory_pool_area, USB_CACHE_SAFE_MEMORY_POOL_SIZE); + + + _ux_system_host = &ux_system_host; + ux_system_host.ux_system_host_hcd_array = &ux_hcd; + ux_system_host.ux_system_host_device_array = device_array; + device1.ux_device_handle = UX_UNUSED; + device2.ux_device_handle = UX_UNUSED; + ux_hcd.ux_hcd_entry_function = hcd_entry_function; + hub.ux_host_class_hub_device = &hub_device; +#if UX_MAX_HCD > 1 + hub_device.ux_device_hcd = &ux_hcd; +#endif + port_status = UX_HOST_CLASS_HUB_PORT_STATUS_CONNECTION; + hub.ux_host_class_hub_port_state = 0; + control_endpoint = &hub_device.ux_device_control_endpoint; + transfer_request = &control_endpoint -> ux_endpoint_transfer_request; + transfer_request -> ux_transfer_request_endpoint = &transfer_request_endpoint; + transfer_request_endpoint.ux_endpoint_device = &hub_device; + transfer_request_endpoint.ux_endpoint_descriptor.bEndpointAddress = UX_ENDPOINT_OUT | 1; + hub_device.ux_device_state = UX_DEVICE_ATTACHED; + + /* Test line 150 */ + _ux_host_class_hub_port_change_connection_process(&hub, 1, 1); + + /* Test line 167 and 228*/ + hub_device.ux_device_power_source = UX_DEVICE_BUS_POWERED; +#if UX_MAX_HCD > 1 + ux_system_host.ux_system_host_max_devices = 2; +#endif + ux_system_host.ux_system_host_change_function = UX_NULL; + _ux_host_class_hub_port_change_connection_process(&hub, 1, 1); + + /* Test line 228 */ + ux_system_host.ux_system_host_change_function = change_function; + _ux_host_class_hub_port_change_connection_process(&hub, 1, 1); + + + + printf(" Passed\n"); + + + test_control_return(0); + return; +} diff --git a/test/regression/usbx_host_class_storage_entry_coverage_test.c b/test/regression/usbx_host_class_storage_entry_coverage_test.c new file mode 100644 index 00000000..2cdcac66 --- /dev/null +++ b/test/regression/usbx_host_class_storage_entry_coverage_test.c @@ -0,0 +1,38 @@ +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" +#include "ux_test.h" +#include "ux_host_class_storage.h" +#include "ux_test_utility_sim.h" + + +static UX_HOST_CLASS_COMMAND command; + + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_host_class_storage_entry_overage_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status = 0; + + + /* Inform user. */ + printf("Running USB host Class Storage Entry Coverage Test ................. "); + + command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_ACTIVATE_WAIT; + status = _ux_host_class_storage_entry(&command); + + if (status == UX_STATE_NEXT) + printf(" Passed\n"); + else + printf(" Failure\n"); + + test_control_return(0); + return; +} diff --git a/test/regression/usbx_host_class_storage_max_lun_get_coverage_test.c b/test/regression/usbx_host_class_storage_max_lun_get_coverage_test.c new file mode 100644 index 00000000..ece69bc8 --- /dev/null +++ b/test/regression/usbx_host_class_storage_max_lun_get_coverage_test.c @@ -0,0 +1,55 @@ +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" +#include "ux_test.h" +#include "ux_test_utility_sim.h" +#include "ux_host_class_storage.h" +#include "ux_host_stack.h" + + +static UX_HOST_CLASS_STORAGE storage; +extern UINT _ux_host_class_storage_max_lun_get(UX_HOST_CLASS_STORAGE*); +static UX_DEVICE ux_device; +static UX_SYSTEM test_ux_system; +static UX_DEVICE endpoint_device; +static UX_ENDPOINT ux_endpoint; +#ifdef UX_HOST_CLASS_STORAGE_INCLUDE_LEGACY_PROTOCOL_SUPPORT +static UX_INTERFACE storage_interface; +#endif +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_host_class_storage_max_lun_get_coverage_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status = 0; + + printf("Running USB host Class Storage Max Lun Get Coverage T............... "); +#ifndef UX_HOST_STANDALONE + _ux_system = &test_ux_system; + _ux_system->ux_system_thread_lowest_priority = 10; + storage.ux_host_class_storage_device = &ux_device; + +#ifdef UX_HOST_CLASS_STORAGE_INCLUDE_LEGACY_PROTOCOL_SUPPORT + storage.ux_host_class_storage_interface = &storage_interface; + storage_interface.ux_interface_descriptor.bInterfaceProtocol = UX_HOST_CLASS_STORAGE_PROTOCOL_BO; +#endif + ux_device.ux_device_control_endpoint.ux_endpoint_device = &endpoint_device; + + status = _ux_host_class_storage_max_lun_get(&storage); + + if (status == TX_SEMAPHORE_ERROR) + printf(" Passed\n"); + else + printf(" Failure\n"); +#else + + printf(" N/A\n"); +#endif + test_control_return(0); + return; +} diff --git a/test/regression/usbx_host_stack_class_unregister_coverage_test.c b/test/regression/usbx_host_stack_class_unregister_coverage_test.c new file mode 100644 index 00000000..12002e5b --- /dev/null +++ b/test/regression/usbx_host_stack_class_unregister_coverage_test.c @@ -0,0 +1,51 @@ +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" +#include "ux_test.h" +#include "ux_test_utility_sim.h" + +static UINT class_entry_func(struct UX_HOST_CLASS_COMMAND_STRUCT* command_ptr) +{ + return 0; + +} + +static UX_HOST_CLASS host_class_array[2]; + +extern UX_SYSTEM_HOST *_ux_system_host; +static UX_SYSTEM_HOST ux_host; + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_host_stack_class_unregister_coverage_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status = 0; + + + /* Inform user. */ + printf("Running USB host Stack Class Unregister Coverage Test .............. "); +#if UX_MAX_CLASS_DRIVER > 1 + _ux_system_host = &ux_host; + _ux_system_host -> ux_system_host_max_class = 2; + _ux_system_host -> ux_system_host_class_array = host_class_array; + host_class_array[0].ux_host_class_entry_function = UX_NULL; + host_class_array[1].ux_host_class_entry_function = UX_NULL; + + status = _ux_host_stack_class_unregister(class_entry_func); + + if (status == UX_NO_CLASS_MATCH) + printf(" Passed\n"); + else + printf(" Failure\n"); +#else + printf(" N/A\n"); +#endif + test_control_return(0); + return; +} diff --git a/test/regression/usbx_host_stack_new_endpoint_create_coverage_test.c b/test/regression/usbx_host_stack_new_endpoint_create_coverage_test.c new file mode 100644 index 00000000..0ec5f3ea --- /dev/null +++ b/test/regression/usbx_host_stack_new_endpoint_create_coverage_test.c @@ -0,0 +1,53 @@ +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" +#include "ux_test.h" +#include "ux_test_utility_sim.h" + + +extern UINT _ux_host_stack_new_endpoint_create(UX_INTERFACE *ux_interface, UCHAR * interface_endpoint); + +#define UX_TEST_MEMORY_SIZE (32 * 1024) +static UX_INTERFACE test_interface; +static struct UX_CONFIGURATION_STRUCT test_configuration; +static UCHAR test_interface_data[] = { + /* --------------------------------- Endpoint Descriptor */ + /* 0 bLength, bDescriptorType */ 0x04, 0x01, + /* 2 bEndpintAddress, bmAttributes */ 0x00, 0x03, + /* 4 wMaxPacketSize, */ 0x00, 0x04, + /* 6 bInterval */ 0x00}; +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_host_stack_new_endpoint_create_overage_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status = 0; +UX_INTERFACE *usbx_interface = &test_interface; + UCHAR* interface_endpoint = test_interface_data; + VOID* memory_pointer; + + /* Inform user. */ + printf("Running USB host Stack New Endpoint Create Coverage Test ........... "); + + memory_pointer = first_unused_memory; + + /* Initialize USBX Memory. */ + status = ux_system_initialize(memory_pointer, UX_TEST_MEMORY_SIZE, UX_NULL, 0); + + test_interface.ux_interface_configuration = &test_configuration; + + status = _ux_host_stack_new_endpoint_create(usbx_interface, interface_endpoint); + + if (status == UX_DESCRIPTOR_CORRUPTED) + printf(" Passed\n"); + else + printf(" Failure\n"); + + test_control_return(0); + return; +} diff --git a/test/regression/usbx_hub_basic_memory_test.c b/test/regression/usbx_hub_basic_memory_test.c new file mode 100644 index 00000000..f4ae08cc --- /dev/null +++ b/test/regression/usbx_hub_basic_memory_test.c @@ -0,0 +1,248 @@ +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_device_stack.h" +#include "ux_host_class_hub.h" +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" +#include "ux_test.h" +#include "ux_test_actions.h" +#include "ux_device_class_dummy_hub.h" +#include "ux_dcd_sim_slave.h" +#include "usbx_ux_test_hub.h" + +static ULONG set_addr_counter; + +static ULONG rsc_mem_alloc_cnt_on_set_addr; +static ULONG rsc_sem_on_set_addr; +static ULONG rsc_sem_get_on_set_addr; +static ULONG rsc_mutex_on_set_addr; + +static ULONG rsc_enum_sem_usage; +static ULONG rsc_enum_sem_get_count; +static ULONG rsc_enum_mutex_usage; +static ULONG rsc_enum_mem_alloc_count; + +static ULONG rsc_cdc_sem_usage; +static ULONG rsc_cdc_sem_get_count; +static ULONG rsc_cdc_mutex_usage; +static ULONG rsc_cdc_mem_alloc_count; + +static ULONG error_callback_counter; + +static UX_TEST_SETUP _SetAddress = UX_TEST_SETUP_SetAddress; +static VOID ux_test_hcd_entry_set_addr(UX_TEST_ACTION *action, VOID *_params) +{ + + set_addr_counter ++; + + rsc_mem_alloc_cnt_on_set_addr = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_addr = ux_test_utility_sim_sem_create_count(); + rsc_sem_get_on_set_addr = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_addr = ux_test_utility_sim_mutex_create_count(); +} +static UX_TEST_HCD_SIM_ACTION log_on_SetAddr[] = { +{ .function = UX_HCD_TRANSFER_REQUEST, + .req_setup = &_SetAddress, + .req_action = UX_TEST_SETUP_MATCH_REQ, + .action_func = ux_test_hcd_entry_set_addr, + .no_return = UX_TRUE +}, /* Invoke callback & continue */ +{ 0 } +}; + +static void count_error_callback(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ +UX_TEST_ERROR_CALLBACK_PARAMS *error = (UX_TEST_ERROR_CALLBACK_PARAMS *)params; + + // printf("error trap: 0x%x, 0x%x, 0x%x\n", error->system_level, error->system_context, error->error_code); + error_callback_counter ++; +} + +static UX_TEST_HCD_SIM_ACTION count_on_error_trap[] = { +{ .usbx_function = UX_TEST_OVERRIDE_ERROR_CALLBACK, + .action_func = count_error_callback, +}, +{ 0 } +}; + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_basic_memory_test_application_define(void *first_unused_memory) +#endif +{ + +CHAR *memory_pointer = first_unused_memory; + + /* Inform user. */ + printf("Running Hub Basic Memory Functionality Test......................... "); + + stepinfo("\n"); + + /* Override error trap. */ + ux_test_link_hooks_from_array(count_on_error_trap); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + initialize_hub(first_unused_memory); +} + +static void post_init_host() +{ + +ULONG mem_free; +ULONG test_n; + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_disconnect_slave(); + ux_test_disconnect_host_wait_for_enum_completion(); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_count_reset(); + ux_test_utility_sim_mutex_create_count_reset(); + ux_test_utility_sim_sem_create_count_reset(); + ux_test_utility_sim_sem_get_count_reset(); + ux_test_hcd_sim_host_set_actions(log_on_SetAddr); + + /* Save free memory usage. */ + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + stepinfo(">>>>>>>>>>>>>>>>>>> Test connect\n"); + /* Connect. */ + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + class_hub_get(); + + /* Log create counts for further tests. */ + rsc_enum_mutex_usage = rsc_mutex_on_set_addr; + rsc_enum_sem_usage = rsc_sem_on_set_addr; + rsc_enum_mem_alloc_count = rsc_mem_alloc_cnt_on_set_addr; + /* Log create counts when instances active for further tests. */ + rsc_cdc_mutex_usage = ux_test_utility_sim_mutex_create_count() - rsc_enum_mutex_usage; + rsc_cdc_sem_usage = ux_test_utility_sim_sem_create_count() - rsc_enum_sem_usage; + rsc_cdc_mem_alloc_count = ux_test_utility_sim_mem_alloc_count() - rsc_enum_mem_alloc_count; + + /* Lock log base for tests. */ + ux_test_utility_sim_mem_alloc_log_lock(); + + /* Simulate detach and attach for FS enumeration, + and check if there is memory error in normal enumeration. + */ + stepinfo(">>>>>>>>>>>>>>>>>>> Enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < 3; test_n++) + { + stepinfo("%4ld / 2\n", test_n); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on error. */ + ux_test_breakable_sleep(200, sleep_break_on_error); + + /* Check */ + if (g_hub_host_from_system_change_function == UX_NULL) + { + + printf("ERROR #%d.%ld: Enumeration fail\n", __LINE__, test_n); + test_control_return(1); + } + } + + stepinfo("enum mem: %ld\n", rsc_enum_mem_alloc_count); + stepinfo("cdc mem : %ld\n", rsc_cdc_mem_alloc_count); + stepinfo("mem free: %ld, %ld\n", _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); + + /* Simulate detach and attach for FS enumeration, + and test possible memory allocation error handlings. + */ + if (rsc_cdc_mem_alloc_count) stepinfo(">>>>>>>>>>>>>>>>>>> Memory errors enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_cdc_mem_alloc_count; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_cdc_mem_alloc_count - 1); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Set memory error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n + rsc_enum_mem_alloc_count); + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on errors. */ + ux_test_breakable_sleep(200, sleep_break_on_error); + + /* Check error */ + if (g_hub_host_from_system_change_function != UX_NULL) + { + + printf("ERROR #%d.%ld: device detected when there is memory error\n", __LINE__, test_n); + test_control_return(1); + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + } + ux_test_utility_sim_mem_alloc_error_generation_stop(); + if (rsc_cdc_mem_alloc_count) stepinfo("\n"); +} + +static void post_init_device(ULONG input) +{ +} \ No newline at end of file diff --git a/test/regression/usbx_hub_basic_test.c b/test/regression/usbx_hub_basic_test.c new file mode 100644 index 00000000..5aaf289a --- /dev/null +++ b/test/regression/usbx_hub_basic_test.c @@ -0,0 +1,69 @@ +/* This is a basic test for the host hub class. Note that there is no device hub + class, so we create a barebones dummy one. We also test a device connected + to the hub; for this, we use the DPUMP class since it is very simple. Note + that we only test enumeration of the DPUMP device, since it is rather difficult + and unnecessary to do test the DPUMP device behind the hub. */ + +#include "usbx_ux_test_hub.h" + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_basic_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Hub Basic Functionality Test................................ "); + + stepinfo("\n"); + + initialize_hub(first_unused_memory); +} + +static void post_init_host() +{ + + /* Let's initialize the memory test. */ + ux_test_disconnect_slave_and_host_wait_for_enum_completion(); + ux_test_memory_test_initialize(); + ux_test_connect_slave_and_host_wait_for_enum_completion(); + class_hub_get(); + UX_TEST_ASSERT(g_hub_device != UX_NULL); + + /* Now, let's tell the host that there's a device connection. */ + connect_device_to_hub(); +#if UX_MAX_DEVICES > 1 + /* Now wait for the device hub to tell us the DPUMP device has been connected. */ + class_dpump_get(); + + /* The host enumerated the DPUMP device. Awesome. Now let's disconnect and reconnect + to test that we can reconnect. */ + /* Let's also test the case of null change function. */ + _ux_system_host->ux_system_host_change_function = UX_NULL; + ux_test_disconnect_slave_and_host_wait_for_enum_completion(); + ux_test_connect_slave_and_host_wait_for_enum_completion(); + /* Let's also test the case where the port data is 2 bytes instead of 1. */ + connect_device_to_hub_short_with_hub(); + class_dpump_get(); + /* Let's re-add the system change function. */ + _ux_system_host->ux_system_host_change_function = system_change_function; + + /* The host enumerated the DPUMP device. Awesome. Now let's disconnect and reconnect + to test that we can reconnect and stuff. */ + ux_test_disconnect_slave_and_host_wait_for_enum_completion(); + /* Ensure everything is cleared. */ + UX_TEST_ASSERT(g_hub_device == UX_NULL); + UX_TEST_ASSERT(g_hub_host_from_system_change_function == UX_NULL); + ux_test_connect_slave_and_host_wait_for_enum_completion(); + connect_device_to_hub(); + class_dpump_get(); +#endif + /* We're done. */ +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_hub_full_speed_hub_device_test.c b/test/regression/usbx_hub_full_speed_hub_device_test.c new file mode 100644 index 00000000..9012911a --- /dev/null +++ b/test/regression/usbx_hub_full_speed_hub_device_test.c @@ -0,0 +1,35 @@ +/* This tests the case where the hub device is full speed. The specific test case + is in ux_host_class_hub_port_change_connection_process.c. */ + +#include "usbx_ux_test_hub.h" + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_full_speed_hub_device_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Hub Full Speed Hub Device Test.............................. "); + + stepinfo("\n"); + + initialize_hub(first_unused_memory); +} + +static void post_init_host() +{ +#if UX_MAX_DEVICES > 1 + /* Tell the host that there's a device connection. */ + connect_device_to_hub_speed(UX_TEST_HUB_PORT_STATUS_FULL_SPEED); + class_dpump_get(); + ux_test_wait_for_enum_thread_completion(); +#endif +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_hub_full_speed_hub_test.c b/test/regression/usbx_hub_full_speed_hub_test.c new file mode 100644 index 00000000..3a9530be --- /dev/null +++ b/test/regression/usbx_hub_full_speed_hub_test.c @@ -0,0 +1,81 @@ +/* This tests the case where the hub is a full-speed hub. Specific test case + is in ux_host_class_hub_descriptor_get.c. */ + +#include "usbx_ux_test_hub.h" + +static unsigned char framework_full_speed_hub[] = { + + /* Device Descriptor */ + 0x12, /* bLength */ + 0x01, /* bDescriptorType */ + 0x00, 0x02, /* bcdUSB */ + 0x09, /* bDeviceClass - Hub */ + 0x00, /* bDeviceSubClass */ + 0x00, /* bDeviceProtocol - full-speed */ + 0x40, /* bMaxPacketSize0 */ + 0x24, 0x04, /* idVendor */ + 0x12, 0x24, /* idProduct */ + 0xb2, 0x0b, /* bcdDevice */ + 0x00, /* iManufacturer */ + 0x00, /* iProduct */ + 0x00, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ + + /* Configuration Descriptor */ + 0x09, /* bLength */ + 0x02, /* bDescriptorType */ + 0x19, 0x00, /* wTotalLength */ + 0x01, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xe0, /* bmAttributes - Self-powered */ + 0x01, /* bMaxPower */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x09, /* bInterfaceClass - Hub */ + 0x00, /* bInterfaceSubClass */ + 0x00, /* bInterfaceProtocol */ + 0x00, /* iInterface */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x81, /* bEndpointAddress */ + 0x03, /* bmAttributes - Interrupt */ + 0x02, 0x00, /* wMaxPacketSize */ + 0x0c, /* bInterval */ + +}; + +static DEVICE_INIT_DATA device_init_data = { + .framework = framework_full_speed_hub, + .framework_length = sizeof(framework_full_speed_hub), +}; + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_full_speed_hub_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Hub Full Speed Hub Test..................................... "); + + stepinfo("\n"); + + initialize_hub_with_device_init_data(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_hub_get_hub_status_fails_during_hub_device_enum_test.c b/test/regression/usbx_hub_get_hub_status_fails_during_hub_device_enum_test.c new file mode 100644 index 00000000..e4a09fc8 --- /dev/null +++ b/test/regression/usbx_hub_get_hub_status_fails_during_hub_device_enum_test.c @@ -0,0 +1,58 @@ +/* This tests the case where the get hub status commmand fails + when a device connected to the hub is being enumerated. The specific test case + is in ux_host_class_hub_port_change_process.c. */ + +#include "usbx_ux_test_hub.h" + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_get_hub_status_fails_during_hub_device_enumeration_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Hub Get Hub Status Fails During Hub Device Enum Test........ "); + + stepinfo("\n"); + + initialize_hub(first_unused_memory); +} + +static void post_init_host() +{ +#if UX_MAX_DEVICES > 1 + /* Make get port status fail action. */ + + UX_TEST_SETUP get_port_status_setup = {0}; + get_port_status_setup.ux_test_setup_request = UX_HOST_CLASS_HUB_GET_STATUS; + get_port_status_setup.ux_test_setup_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_OTHER; + + UX_TEST_ACTION get_port_status_fail_action = {0}; + get_port_status_fail_action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + get_port_status_fail_action.function = UX_HCD_TRANSFER_REQUEST; + get_port_status_fail_action.req_action = UX_TEST_SETUP_MATCH_REQUEST; + get_port_status_fail_action.req_setup = &get_port_status_setup; + get_port_status_fail_action.no_return = 0; + get_port_status_fail_action.status = UX_ERROR; + + /* Add action. */ + ux_test_add_action_to_main_list(get_port_status_fail_action); + + /* Tell the host that there's a device connection. */ + connect_device_to_hub(); + + /* Wait for empty actions. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_empty_actions()); + ux_test_wait_for_enum_thread_completion(); + + /* Ensure it failed. */ + UX_TEST_ASSERT(g_dpump_host_from_system_change_function == UX_NULL); +#endif +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_hub_get_hub_status_fails_during_port_reset_test.c b/test/regression/usbx_hub_get_hub_status_fails_during_port_reset_test.c new file mode 100644 index 00000000..fb3529c8 --- /dev/null +++ b/test/regression/usbx_hub_get_hub_status_fails_during_port_reset_test.c @@ -0,0 +1,71 @@ +/* This tests the case where the get hub status commmand fails when a port is being reset. + The specific test case is in ux_host_class_hub_port_reset.c. */ + +#include "usbx_ux_test_hub.h" + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_get_hub_status_fails_during_port_reset_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Hub Get Hub Status Fails During Port Reset Test............. "); + + stepinfo("\n"); + + initialize_hub(first_unused_memory); +} + +static void post_init_host() +{ +#if UX_MAX_DEVICES > 1 + /* Make get port status fail action. */ + + UX_TEST_SETUP get_port_status_setup = {0}; + get_port_status_setup.ux_test_setup_request = UX_HOST_CLASS_HUB_GET_STATUS; + get_port_status_setup.ux_test_setup_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_OTHER; + + UX_TEST_ACTION get_port_status_fail_action = {0}; + get_port_status_fail_action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + get_port_status_fail_action.function = UX_HCD_TRANSFER_REQUEST; + get_port_status_fail_action.req_action = UX_TEST_SETUP_MATCH_REQUEST; + get_port_status_fail_action.req_setup = &get_port_status_setup; + get_port_status_fail_action.no_return = 0; + get_port_status_fail_action.status = UX_ERROR; + + /* The host actually gets the port status three times - first is initial + port status check, second is during port reset (the one we want to fail), third is necessary since + we retry enumeration. */ + UX_TEST_ACTION get_port_status_match_action = {0}; + get_port_status_match_action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + get_port_status_match_action.function = UX_HCD_TRANSFER_REQUEST; + get_port_status_match_action.req_action = UX_TEST_SETUP_MATCH_REQUEST; + get_port_status_match_action.req_setup = &get_port_status_setup; + get_port_status_match_action.no_return = 1; + + /* Add them. */ + ux_test_add_action_to_main_list(get_port_status_match_action); + ux_test_add_action_to_main_list(get_port_status_fail_action); + + /* Tell the host that there's a device connection. */ + connect_device_to_hub(); + + /* Wait for empty actions. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_empty_actions()); + ux_test_wait_for_enum_thread_completion(); + + /* Ensure it failed. */ + UX_TEST_ASSERT(g_dpump_host_from_system_change_function == UX_NULL); + + /* USBX still thinks there's a device connected (since there is, technically), so it will try to remove it, but fail. */ + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ENUMERATOR, UX_DEVICE_HANDLE_UNKNOWN)); +#endif +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_hub_get_port_status_fails_during_hub_device_enum_test.c b/test/regression/usbx_hub_get_port_status_fails_during_hub_device_enum_test.c new file mode 100644 index 00000000..0e99c1e9 --- /dev/null +++ b/test/regression/usbx_hub_get_port_status_fails_during_hub_device_enum_test.c @@ -0,0 +1,72 @@ +/* This tests the case where the get port status commmand fails + when a device connected to the hub is being enumerated. The specific test case + is in ux_host_class_hub_port_change_connection_process.c. */ + +#include "usbx_ux_test_hub.h" + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_get_port_status_fails_during_hub_device_enumeration_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Hub Get Port Status Fails During Hub Device Enum Test....... "); + + stepinfo("\n"); + + initialize_hub(first_unused_memory); +} + +static void post_init_host() +{ +#if UX_MAX_DEVICES > 1 + /* Make get port status fail action. */ + + UX_TEST_SETUP get_port_status_setup = {0}; + get_port_status_setup.ux_test_setup_request = UX_HOST_CLASS_HUB_GET_STATUS; + get_port_status_setup.ux_test_setup_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_OTHER; + + UX_TEST_ACTION get_port_status_fail_action = {0}; + get_port_status_fail_action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + get_port_status_fail_action.function = UX_HCD_TRANSFER_REQUEST; + get_port_status_fail_action.req_action = UX_TEST_SETUP_MATCH_REQUEST; + get_port_status_fail_action.req_setup = &get_port_status_setup; + get_port_status_fail_action.no_return = 0; + get_port_status_fail_action.status = UX_ERROR; + + /* The host actually gets the port status three times - first is initial + port status check, second is during port reset, third is necessary since + we retry enumeration. */ + UX_TEST_ACTION get_port_status_match_action = {0}; + get_port_status_match_action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + get_port_status_match_action.function = UX_HCD_TRANSFER_REQUEST; + get_port_status_match_action.req_action = UX_TEST_SETUP_MATCH_REQUEST; + get_port_status_match_action.req_setup = &get_port_status_setup; + get_port_status_match_action.no_return = 1; + + /* Add them. */ + ux_test_add_action_to_main_list(get_port_status_match_action); + ux_test_add_action_to_main_list(get_port_status_match_action); + ux_test_add_action_to_main_list(get_port_status_fail_action); + + /* Tell the host that there's a device connection. */ + connect_device_to_hub(); + + /* Wait for empty actions. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_empty_actions()); + ux_test_wait_for_enum_thread_completion(); + + /* When enumeration fails, USBX still reports the device on the port, so it + will try to remove the device when the the upper-test-layer disconnects the hub. + This will result in an error that we want to ignore. */ + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ENUMERATOR, UX_DEVICE_HANDLE_UNKNOWN)); +#endif +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_hub_get_status_fails_during_configuration_test.c b/test/regression/usbx_hub_get_status_fails_during_configuration_test.c new file mode 100644 index 00000000..f5004133 --- /dev/null +++ b/test/regression/usbx_hub_get_status_fails_during_configuration_test.c @@ -0,0 +1,66 @@ +/* This tests the case where the GET_STATUS request has an invalid actual length. */ + +#include "usbx_ux_test_hub.h" + +static DEVICE_INIT_DATA device_init_data = { + .dont_enumerate = 1 +}; + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_get_status_fails_during_configuration_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Hub Get Status Fails During Configuration Test.............. "); + + stepinfo("\n"); + + initialize_hub_with_device_init_data(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ + +int i; + + /* Setup setup for matching the GET_STATUS request. */ + UX_TEST_SETUP setup = {0}; + setup.ux_test_setup_request = UX_GET_STATUS; + setup.ux_test_setup_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + setup.ux_test_setup_value = 0; + setup.ux_test_setup_index = 0; + + /* Make action to make transfer fail. */ + UX_TEST_ACTION action = {0}; + action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + action.function = UX_HCD_TRANSFER_REQUEST; + action.req_action = UX_TEST_SETUP_MATCH_REQUEST | UX_TEST_SIM_REQ_ANSWER; + action.req_setup = &setup; + action.req_ep_address = 0x81; + action.req_actual_len = 1; + action.no_return = 0; + action.status = UX_SUCCESS; + + /* We expect error to happen multiple times. */ + for (i = 0; i < UX_RH_ENUMERATION_RETRY; i++) + { + ux_test_add_action_to_main_list(action); + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HUB, UX_CONNECTION_INCOMPATIBLE)); + } + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE)); + + /* Enumerate. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + ux_test_wait_for_enum_thread_completion(); + + /* Ensure all expected actions occurred. */ + UX_TEST_ASSERT(ux_test_check_actions_empty()); + UX_TEST_ASSERT(g_hub_host_from_system_change_function == UX_NULL); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_hub_hub_device_connect_test.c b/test/regression/usbx_hub_hub_device_connect_test.c new file mode 100644 index 00000000..9658ed09 --- /dev/null +++ b/test/regression/usbx_hub_hub_device_connect_test.c @@ -0,0 +1,130 @@ +/* This tests the case where the device connected to the hub is disconnected. + The specific test case is in ux_host_class_hub_port_change_connection_process.c. */ + +#include "usbx_ux_test_hub.h" + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_hub_device_connect_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Hub Device connect Test..................................... "); + + stepinfo("\n"); + + initialize_hub(first_unused_memory); +} + +static void post_init_host() +{ +#if UX_MAX_DEVICES > 1 +UX_DEVICE *device; +ULONG temp; + + /* >>>>>>>>>> Test connect and enumerate. */ + g_host_change_count = 0; + connect_device_to_hub(); + class_dpump_get(); + + /* 2 events expected. */ + UX_TEST_ASSERT(g_host_change_count == 2); + + /* 1st event : dpump class activated. */ + UX_TEST_ASSERT(g_host_change_logs[0].event == UX_DEVICE_INSERTION); + UX_TEST_ASSERT(g_host_change_logs[0].class != UX_NULL); + UX_TEST_ASSERT(g_host_change_logs[0].instance != UX_NULL); + + /* 2nd event : device enumerated (connected). */ + UX_TEST_ASSERT(g_host_change_logs[1].event == UX_DEVICE_CONNECTION); + UX_TEST_ASSERT(g_host_change_logs[1].class == UX_NULL); + UX_TEST_ASSERT(g_host_change_logs[1].instance != UX_NULL); + + /* >>>>>>>>>> Now we need to disconnect the device. */ + g_host_change_count = 0; + disconnect_device_from_hub(); + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_null((VOID**)&g_dpump_host_from_system_change_function)); + ux_test_wait_for_enum_thread_completion(); + + /* 2 events expected. */ + UX_TEST_ASSERT(g_host_change_count == 2); + + /* 1st event : dpump class deactivated. */ + UX_TEST_ASSERT(g_host_change_logs[0].event == UX_DEVICE_REMOVAL); + UX_TEST_ASSERT(g_host_change_logs[0].class != UX_NULL); + UX_TEST_ASSERT(g_host_change_logs[0].instance != UX_NULL); + + /* 2nd event : device disconnected. */ + UX_TEST_ASSERT(g_host_change_logs[1].event == UX_DEVICE_DISCONNECTION); + UX_TEST_ASSERT(g_host_change_logs[1].class == UX_NULL); + UX_TEST_ASSERT(g_host_change_logs[1].instance != UX_NULL); + + /* >>>>>>>>>> Now test case : UX_TOO_MANY_DEVICES. */ + ux_test_ignore_all_errors(); + g_host_change_count = 0; + temp = _ux_system_host -> ux_system_host_max_devices; + _ux_system_host -> ux_system_host_max_devices = 1; + connect_device_to_hub(); + + /* One event expected. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_ulong(&g_host_change_count, 1)); + + /* event : device connected but no instance. */ + UX_TEST_ASSERT(g_host_change_logs[0].event == UX_DEVICE_CONNECTION); + UX_TEST_ASSERT(g_host_change_logs[0].class == UX_NULL); + UX_TEST_ASSERT(g_host_change_logs[0].instance == UX_NULL); + + g_host_change_count = 0; + disconnect_device_from_hub(); + ux_test_wait_for_enum_thread_completion(); + + /* There is no change notification since no device instance allocated. */ + UX_TEST_ASSERT(g_host_change_count == 0); + + /* Restore. */ + _ux_system_host -> ux_system_host_max_devices = temp; + ux_test_unignore_all_errors(); + + /* >>>>>>>>>> Now test case : UX_NO_CLASS_MATCH. */ + ux_test_ignore_all_errors(); + + /* Unregister DPUMP. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_class_unregister(ux_host_class_dpump_entry)); + g_host_change_count = 0; + connect_device_to_hub(); + + /* One event expected. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_ulong(&g_host_change_count, 1)); + + /* event : device connected but not configured. */ + UX_TEST_ASSERT(g_host_change_logs[0].event == UX_DEVICE_CONNECTION); + UX_TEST_ASSERT(g_host_change_logs[0].class == UX_NULL); + UX_TEST_ASSERT(g_host_change_logs[0].instance != UX_NULL); + device = (UX_DEVICE*)g_host_change_logs[0].instance; + UX_TEST_ASSERT(device->ux_device_state == UX_DEVICE_ADDRESSED); + + g_host_change_count = 0; + disconnect_device_from_hub(); + + /* One event expected. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_ulong(&g_host_change_count, 1)); + + ux_test_wait_for_enum_thread_completion(); + + /* event : device disconnected but not configured. */ + UX_TEST_ASSERT(g_host_change_logs[0].event == UX_DEVICE_DISCONNECTION); + UX_TEST_ASSERT(g_host_change_logs[0].class == UX_NULL); + UX_TEST_ASSERT(g_host_change_logs[0].instance == (VOID*)device); + + ux_test_unignore_all_errors(); + +#endif +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_hub_hub_device_disconnect_test.c b/test/regression/usbx_hub_hub_device_disconnect_test.c new file mode 100644 index 00000000..66b80033 --- /dev/null +++ b/test/regression/usbx_hub_hub_device_disconnect_test.c @@ -0,0 +1,39 @@ +/* This tests the case where the device connected to the hub is disconnected. + The specific test case is in ux_host_class_hub_port_change_connection_process.c. */ + +#include "usbx_ux_test_hub.h" + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_hub_device_disconnect_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Hub Device Disconnect Test.................................. "); + + stepinfo("\n"); + + initialize_hub(first_unused_memory); +} + +static void post_init_host() +{ +#if UX_MAX_DEVICES > 1 + /* Now, let's tell the host that there's a device connection, and wait for host to enumerate it. */ + connect_device_to_hub(); + class_dpump_get(); + + /* Now we need to disconnect the device. */ + disconnect_device_from_hub(); + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_null((VOID**)&g_dpump_host_from_system_change_function)); + ux_test_wait_for_enum_thread_completion(); +#endif +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_hub_hub_device_enumeration_keeps_failing_test.c b/test/regression/usbx_hub_hub_device_enumeration_keeps_failing_test.c new file mode 100644 index 00000000..01e2348c --- /dev/null +++ b/test/regression/usbx_hub_hub_device_enumeration_keeps_failing_test.c @@ -0,0 +1,57 @@ +/* This tests the case where the hub device's enumeration keeps failing. The + specific test case is in ux_host_class_hub_port_change_connection_process.c. */ + +#include "usbx_ux_test_hub.h" + +static UINT num_insertions; +static UINT num_removals; + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_hub_device_enumeration_keeps_failing_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Hub Hub Device Enumeration Kepps Failing Test............... "); + + stepinfo("\n"); + + initialize_hub(first_unused_memory); +} + +static void post_init_host() +{ +#if UX_MAX_DEVICES > 1 +int i; + + /* We do this by having the semaphore create for EP0 fail multiple times. */ + + /* Create action to make semaphore creation fail. */ + UX_TEST_ACTION sem_create_fail_action = {0}; + sem_create_fail_action.usbx_function = UX_TEST_OVERRIDE_TX_SEMAPHORE_CREATE; + sem_create_fail_action.semaphore_name = "ux_host_endpoint0_semaphore"; + sem_create_fail_action.no_return = 0; + sem_create_fail_action.status = UX_ERROR; + + for (i = 0; i < UX_HOST_CLASS_HUB_ENUMERATION_RETRY; i++) + { + ux_test_add_action_to_main_list(sem_create_fail_action); + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_UTILITY, UX_ERROR)); + } + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE)); + + /* Tell the host that there's a device connection. */ + connect_device_to_hub(); + + /* Wait for empty actions. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_empty_actions()); +#endif +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_hub_hub_status_get_invalid_length_test.c b/test/regression/usbx_hub_hub_status_get_invalid_length_test.c new file mode 100644 index 00000000..bb924cd1 --- /dev/null +++ b/test/regression/usbx_hub_hub_status_get_invalid_length_test.c @@ -0,0 +1,48 @@ +/* This tests the case where the transfer length of the GetHubStatus request is invalid. + The specific test case is in ux_host_class_hub_status_get.c. */ + +#include "usbx_ux_test_hub.h" + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_hub_status_get_invalid_length_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Hub Hub Status Get Invalid Length Test...................... "); + + stepinfo("\n"); + + initialize_hub(first_unused_memory); +} + +static void post_init_host() +{ +#if UX_MAX_DEVICES > 1 + UX_TEST_SETUP get_port_status_setup = {0}; + get_port_status_setup.ux_test_setup_request = UX_HOST_CLASS_HUB_GET_STATUS; + get_port_status_setup.ux_test_setup_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_OTHER; + + UX_TEST_ACTION get_port_status_match_action = {0}; + get_port_status_match_action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + get_port_status_match_action.function = UX_HCD_TRANSFER_REQUEST; + get_port_status_match_action.req_action = UX_TEST_SETUP_MATCH_REQUEST | UX_TEST_SIM_REQ_ANSWER; + get_port_status_match_action.req_setup = &get_port_status_setup; + get_port_status_match_action.req_actual_len = 3; /* valid length is supposed to be 4. */ + get_port_status_match_action.no_return = 0; + get_port_status_match_action.status = UX_SUCCESS; + + ux_test_add_action_to_main_list(get_port_status_match_action); + + connect_device_to_hub(); + tx_thread_sleep(100); + ux_test_wait_for_enum_thread_completion(); + UX_TEST_ASSERT(g_dpump_host_from_system_change_function == UX_NULL); +#endif +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_hub_interrupt_out_endpoint_test.c b/test/regression/usbx_hub_interrupt_out_endpoint_test.c new file mode 100644 index 00000000..b9c78e7c --- /dev/null +++ b/test/regression/usbx_hub_interrupt_out_endpoint_test.c @@ -0,0 +1,90 @@ +/* This tests the case where the hub's only endpoint is an interrupt OUT (supposed to be IN). Specific test case is in + ux_host_class_hub_interrupt_endpoint_start.c. */ + +#include "usbx_ux_test_hub.h" + +static unsigned char framework_only_interrupt_out_endpoint[] = { + + /* Device Descriptor */ + 0x12, /* bLength */ + 0x01, /* bDescriptorType */ + 0x00, 0x02, /* bcdUSB */ + 0x09, /* bDeviceClass - Hub */ + 0x00, /* bDeviceSubClass */ + 0x01, /* bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 */ + 0x24, 0x04, /* idVendor */ + 0x12, 0x24, /* idProduct */ + 0xb2, 0x0b, /* bcdDevice */ + 0x00, /* iManufacturer */ + 0x00, /* iProduct */ + 0x00, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ + + /* Configuration Descriptor */ + 0x09, /* bLength */ + 0x02, /* bDescriptorType */ + 0x19, 0x00, /* wTotalLength */ + 0x01, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xe0, /* bmAttributes - Self-powered */ + 0x01, /* bMaxPower */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x09, /* bInterfaceClass - Hub */ + 0x00, /* bInterfaceSubClass */ + 0x00, /* bInterfaceProtocol */ + 0x00, /* iInterface */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x01, /* bEndpointAddress - OUT and not IN */ + 0x03, /* bmAttributes - Interrupt */ + 0x02, 0x00, /* wMaxPacketSize */ + 0x0c, /* bInterval */ + +}; + +static DEVICE_INIT_DATA device_init_data = { + .dont_enumerate = 1, + .framework = framework_only_interrupt_out_endpoint, + .framework_length = sizeof(framework_only_interrupt_out_endpoint), +}; + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_interrupt_out_endpoint_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Hub Interrupt Out Endpoint Test............................. "); + + stepinfo("\n"); + + initialize_hub_with_device_init_data(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ + + ux_test_add_action_to_main_list_multiple(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HUB, UX_ENDPOINT_HANDLE_UNKNOWN), 3); + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE)); + + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + ux_test_wait_for_enum_thread_completion(); + + UX_TEST_ASSERT(ux_test_check_actions_empty() == UX_TRUE); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_hub_invalid_device_protocol_test.c b/test/regression/usbx_hub_invalid_device_protocol_test.c new file mode 100644 index 00000000..80e65747 --- /dev/null +++ b/test/regression/usbx_hub_invalid_device_protocol_test.c @@ -0,0 +1,100 @@ +/* This tests the case where the hub reports an invalid device protocol. Specific + test case is in ux_host_class_hub_descriptor_get.c. */ + +#include "usbx_ux_test_hub.h" + +static unsigned char framework_invalid_device_protocol[] = { + + /* Device Descriptor */ + 0x12, /* bLength */ + 0x01, /* bDescriptorType */ + 0x00, 0x02, /* bcdUSB */ + 0x09, /* bDeviceClass - Hub */ + 0x00, /* bDeviceSubClass */ + 0x03, /* bDeviceProtocol - invalid device protocl */ + 0x40, /* bMaxPacketSize0 */ + 0x24, 0x04, /* idVendor */ + 0x12, 0x24, /* idProduct */ + 0xb2, 0x0b, /* bcdDevice */ + 0x00, /* iManufacturer */ + 0x00, /* iProduct */ + 0x00, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ + + /* Configuration Descriptor */ + 0x09, /* bLength */ + 0x02, /* bDescriptorType */ + 0x19, 0x00, /* wTotalLength */ + 0x01, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xe0, /* bmAttributes - Self-powered */ + 0x01, /* bMaxPower */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x09, /* bInterfaceClass - Hub */ + 0x00, /* bInterfaceSubClass */ + 0x00, /* bInterfaceProtocol */ + 0x00, /* iInterface */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x81, /* bEndpointAddress */ + 0x03, /* bmAttributes - Interrupt */ + 0x02, 0x00, /* wMaxPacketSize */ + 0x0c, /* bInterval */ + +}; + +static DEVICE_INIT_DATA device_init_data = { + .dont_enumerate = 1, + .framework = framework_invalid_device_protocol, + .framework_length = sizeof(framework_invalid_device_protocol), +}; + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_invalid_device_protocol_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Hub Invalid Device Protocol Test............................ "); + + stepinfo("\n"); + + initialize_hub_with_device_init_data(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ +#if UX_MAX_DEVICES > 1 +int i; + + /* We expect error to happen multiple times. */ + for (i = 0; i < UX_RH_ENUMERATION_RETRY; i++) + { + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HUB, UX_DESCRIPTOR_CORRUPTED)); + } + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE)); + + /* Enumerate. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + ux_test_wait_for_enum_thread_completion(); + + /* Ensure all expected actions occurred. */ + UX_TEST_ASSERT(ux_test_check_actions_empty()); + UX_TEST_ASSERT(g_hub_host_from_system_change_function == UX_NULL); +#endif +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_hub_invalid_hub_descriptor_length_test.c b/test/regression/usbx_hub_invalid_hub_descriptor_length_test.c new file mode 100644 index 00000000..607e720a --- /dev/null +++ b/test/regression/usbx_hub_invalid_hub_descriptor_length_test.c @@ -0,0 +1,67 @@ +/* This tests the case where the length of the hub descriptor is invalid. The + exact test case is in ux_host_class_hub_descriptor_get.c. */ + +#include "usbx_ux_test_hub.h" + +static DEVICE_INIT_DATA device_init_data = { + .dont_enumerate = 1 +}; + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_invalid_hub_descriptor_length_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Hub Invalid Hub Descriptor Length Test...................... "); + + stepinfo("\n"); + + initialize_hub_with_device_init_data(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ + +int i; + + /* Setup setup for matching the GET_DESCRIPTOR for hub request. */ + UX_TEST_SETUP setup = {0}; + setup.ux_test_setup_request = UX_HOST_CLASS_HUB_GET_DESCRIPTOR; + setup.ux_test_setup_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_DEVICE; + setup.ux_test_setup_value = (UX_HUB_DESCRIPTOR_ITEM << 8); + setup.ux_test_setup_index = 0; + + /* Make action to make the length invalid. */ + UX_TEST_ACTION action = {0}; + action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + action.function = UX_HCD_TRANSFER_REQUEST; + action.req_action = UX_TEST_SETUP_MATCH_REQUEST | UX_TEST_SIM_REQ_ANSWER; + action.req_setup = &setup; + action.req_ep_address = 0x81; + action.req_actual_len = 1; /* Invalid length. */ + action.no_return = 0; + action.status = UX_SUCCESS; + + /* We expect error to happen multiple times. */ + for (i = 0; i < UX_RH_ENUMERATION_RETRY; i++) + { + ux_test_add_action_to_main_list(action); + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HUB, UX_DESCRIPTOR_CORRUPTED)); + } + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE)); + + /* Enumerate. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + ux_test_wait_for_enum_thread_completion(); + + /* Ensure all expected actions occurred. */ + UX_TEST_ASSERT(ux_test_check_actions_empty()); + UX_TEST_ASSERT(g_hub_host_from_system_change_function == UX_NULL); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_hub_low_speed_hub_device_test.c b/test/regression/usbx_hub_low_speed_hub_device_test.c new file mode 100644 index 00000000..bdf3882b --- /dev/null +++ b/test/regression/usbx_hub_low_speed_hub_device_test.c @@ -0,0 +1,35 @@ +/* This tests the case where the hub device is low speed. The specific test case + is in ux_host_class_hub_port_change_connection_process.c. */ + +#include "usbx_ux_test_hub.h" + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_low_speed_hub_device_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Hub Low Speed Hub Device Test............................... "); + + stepinfo("\n"); + + initialize_hub(first_unused_memory); +} + +static void post_init_host() +{ +#if UX_MAX_DEVICES > 1 + /* Tell the host that there's a device connection. */ + connect_device_to_hub_speed(UX_HOST_CLASS_HUB_PORT_STATUS_LOW_SPEED); + class_dpump_get(); + ux_test_wait_for_enum_thread_completion(); +#endif +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_hub_multiple_tt_test.c b/test/regression/usbx_hub_multiple_tt_test.c new file mode 100644 index 00000000..ae0b3080 --- /dev/null +++ b/test/regression/usbx_hub_multiple_tt_test.c @@ -0,0 +1,81 @@ +/* This tests the case where the hub has multiple TTs. Specific test case + is in ux_host_class_hub_descriptor_get.c. */ + +#include "usbx_ux_test_hub.h" + +static unsigned char framework_multiple_tts[] = { + + /* Device Descriptor */ + 0x12, /* bLength */ + 0x01, /* bDescriptorType */ + 0x00, 0x02, /* bcdUSB */ + 0x09, /* bDeviceClass - Hub */ + 0x00, /* bDeviceSubClass */ + 0x02, /* bDeviceProtocol - multiple TTs */ + 0x40, /* bMaxPacketSize0 */ + 0x24, 0x04, /* idVendor */ + 0x12, 0x24, /* idProduct */ + 0xb2, 0x0b, /* bcdDevice */ + 0x00, /* iManufacturer */ + 0x00, /* iProduct */ + 0x00, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ + + /* Configuration Descriptor */ + 0x09, /* bLength */ + 0x02, /* bDescriptorType */ + 0x19, 0x00, /* wTotalLength */ + 0x01, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xe0, /* bmAttributes - Self-powered */ + 0x01, /* bMaxPower */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x09, /* bInterfaceClass - Hub */ + 0x00, /* bInterfaceSubClass */ + 0x01, /* bInterfaceProtocol */ + 0x00, /* iInterface */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x81, /* bEndpointAddress */ + 0x03, /* bmAttributes - Interrupt */ + 0x02, 0x00, /* wMaxPacketSize */ + 0x0c, /* bInterval */ + +}; + +static DEVICE_INIT_DATA device_init_data = { + .framework = framework_multiple_tts, + .framework_length = sizeof(framework_multiple_tts), +}; + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_multiple_tt_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Hub With Multiple TT Test................................... "); + + stepinfo("\n"); + + initialize_hub_with_device_init_data(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_hub_multiple_tt_too_many_hub_ports_test.c b/test/regression/usbx_hub_multiple_tt_too_many_hub_ports_test.c new file mode 100644 index 00000000..d591887b --- /dev/null +++ b/test/regression/usbx_hub_multiple_tt_too_many_hub_ports_test.c @@ -0,0 +1,116 @@ +/* This tests the case where the hub reports an invalid device protocol. Specific + test case is in ux_host_class_hub_descriptor_get.c. */ + +#include "usbx_ux_test_hub.h" + +static unsigned char framework_invalid_device_protocol[] = { + + /* Device Descriptor */ + 0x12, /* bLength */ + 0x01, /* bDescriptorType */ + 0x00, 0x02, /* bcdUSB */ + 0x09, /* bDeviceClass - Hub */ + 0x00, /* bDeviceSubClass */ + 0x02, /* bDeviceProtocol - multiple */ + 0x40, /* bMaxPacketSize0 */ + 0x24, 0x04, /* idVendor */ + 0x12, 0x24, /* idProduct */ + 0xb2, 0x0b, /* bcdDevice */ + 0x00, /* iManufacturer */ + 0x00, /* iProduct */ + 0x00, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ + + /* Configuration Descriptor */ + 0x09, /* bLength */ + 0x02, /* bDescriptorType */ + 0x19, 0x00, /* wTotalLength */ + 0x01, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xe0, /* bmAttributes - Self-powered */ + 0x01, /* bMaxPower */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x09, /* bInterfaceClass - Hub */ + 0x00, /* bInterfaceSubClass */ + 0x01, /* bInterfaceProtocol */ + 0x00, /* iInterface */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x81, /* bEndpointAddress */ + 0x03, /* bmAttributes - Interrupt */ + 0x02, 0x00, /* wMaxPacketSize */ + 0x0c, /* bInterval */ + +}; + +static unsigned char hub_descriptor_too_many_ports[] = { + + /* Hub Descriptor */ + 0x09, /* bLength */ + 0x29, /* bDescriptorType */ + 100, /* bNbrPorts */ + 0x09, 0x00, /* wHubCharacteristics */ + 0x32, /* bPwrOn2PwrGood */ + 0x01, /* bHubContrCurrent */ + 0x00, /* DeviceRemovable */ + 0xff, /* PortPwrCtrlMask */ + +}; + +static DEVICE_INIT_DATA device_init_data = { + .dont_enumerate = 1, + .framework = framework_invalid_device_protocol, + .framework_length = sizeof(framework_invalid_device_protocol), + .hub_descriptor = hub_descriptor_too_many_ports, + .hub_descriptor_length = sizeof(hub_descriptor_too_many_ports), +}; + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_too_many_hub_ports_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Hub Too Many Hub Ports Test................................. "); + + stepinfo("\n"); + + initialize_hub_with_device_init_data(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ +#if UX_MAX_DEVICES > 1 +int i; + + /* We expect error to happen multiple times. */ + for (i = 0; i < UX_RH_ENUMERATION_RETRY; i++) + { + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HUB, UX_TOO_MANY_HUB_PORTS)); + } + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE)); + + /* Enumerate. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + ux_test_wait_for_enum_thread_completion(); + + /* Ensure all expected actions occurred. */ + UX_TEST_ASSERT(ux_test_check_actions_empty()); + UX_TEST_ASSERT(g_hub_host_from_system_change_function == UX_NULL); +#endif +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_hub_no_endpoints_test.c b/test/regression/usbx_hub_no_endpoints_test.c new file mode 100644 index 00000000..9f885532 --- /dev/null +++ b/test/regression/usbx_hub_no_endpoints_test.c @@ -0,0 +1,82 @@ +/* This tests the case where there are no endpoints. Specific test case is in + ux_host_class_hub_interrupt_endpoint_start.c. */ + +#include "usbx_ux_test_hub.h" + +static unsigned char framework_no_endpoints_test[] = { + + /* Device Descriptor */ + 0x12, /* bLength */ + 0x01, /* bDescriptorType */ + 0x00, 0x02, /* bcdUSB */ + 0x09, /* bDeviceClass - Hub */ + 0x00, /* bDeviceSubClass */ + 0x01, /* bDeviceProtocol - multiple TTs */ + 0x40, /* bMaxPacketSize0 */ + 0x24, 0x04, /* idVendor */ + 0x12, 0x24, /* idProduct */ + 0xb2, 0x0b, /* bcdDevice */ + 0x00, /* iManufacturer */ + 0x00, /* iProduct */ + 0x00, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ + + /* Configuration Descriptor */ + 0x09, /* bLength */ + 0x02, /* bDescriptorType */ + 0x12, 0x00, /* wTotalLength */ + 0x01, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xe0, /* bmAttributes - Self-powered */ + 0x01, /* bMaxPower */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + 0x09, /* bInterfaceClass - Hub */ + 0x00, /* bInterfaceSubClass */ + 0x00, /* bInterfaceProtocol */ + 0x00, /* iInterface */ + +}; + +static DEVICE_INIT_DATA device_init_data = { + .dont_enumerate = 1, + .framework = framework_no_endpoints_test, + .framework_length = sizeof(framework_no_endpoints_test), +}; + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_no_endpoints_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Hub No Endpoints Test....................................... "); + + stepinfo("\n"); + + initialize_hub_with_device_init_data(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ + + ux_test_add_action_to_main_list_multiple(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ENUMERATOR, UX_ENDPOINT_HANDLE_UNKNOWN), 3); + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE)); + + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + ux_test_wait_for_enum_thread_completion(); + + UX_TEST_ASSERT(ux_test_check_actions_empty() == UX_TRUE); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_hub_no_power_switching_test.c b/test/regression/usbx_hub_no_power_switching_test.c new file mode 100644 index 00000000..d4f70e62 --- /dev/null +++ b/test/regression/usbx_hub_no_power_switching_test.c @@ -0,0 +1,72 @@ +/* This tests the case where the hub has no power switching. Specific test case + is in ux_host_class_hub_ports_power.c. */ + +#include "usbx_ux_test_hub.h" + +static unsigned char hub_descriptor_no_power_switching[] = { + + /* Hub Descriptor */ + 0x09, /* bLength */ + 0x29, /* bDescriptorType */ + 0x02, /* bNbrPorts */ + 0x09 | UX_HOST_CLASS_HUB_NO_POWER_SWITCHING, 0x00, /* wHubCharacteristics - no power switching */ + 0x32, /* bPwrOn2PwrGood */ + 0x01, /* bHubContrCurrent */ + 0x00, /* DeviceRemovable */ + 0xff, /* PortPwrCtrlMask */ + +}; + +static DEVICE_INIT_DATA device_init_data = { + .dont_enumerate = 1, + .hub_descriptor = hub_descriptor_no_power_switching, + .hub_descriptor_length = sizeof(hub_descriptor_no_power_switching), +}; + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_no_power_switching_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Hub No Power Switching Test................................. "); + + stepinfo("\n"); + + initialize_hub_with_device_init_data(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ + + /* Add action to match PORT_POWER request. We shouldn't match it, since USBX should never send it. */ + + UX_TEST_SETUP port_power_setup = {0}; + port_power_setup.ux_test_setup_request = UX_SET_FEATURE; + port_power_setup.ux_test_setup_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_OTHER; + port_power_setup.ux_test_setup_value = UX_HOST_CLASS_HUB_PORT_POWER; + + UX_TEST_ACTION port_power_match_action = {0}; + port_power_match_action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + port_power_match_action.function = UX_HCD_TRANSFER_REQUEST; + port_power_match_action.req_action = UX_TEST_SETUP_MATCH_REQUEST | UX_TEST_SETUP_MATCH_VALUE; + port_power_match_action.req_setup = &port_power_setup; + port_power_match_action.no_return = 1; + + ux_test_add_action_to_main_list(port_power_match_action); + + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + ux_test_wait_for_enum_thread_completion(); + + /* Make sure the action ws not matched. */ + UX_TEST_ASSERT(ux_test_check_actions_empty() == UX_FALSE); + + /* Good. Now clear the actions. */ + ux_test_clear_main_list_actions(); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_hub_non_interrupt_in_endpoint_test.c b/test/regression/usbx_hub_non_interrupt_in_endpoint_test.c new file mode 100644 index 00000000..c81929c9 --- /dev/null +++ b/test/regression/usbx_hub_non_interrupt_in_endpoint_test.c @@ -0,0 +1,90 @@ +/* This tests the case where the hub's only endpoint is a non-interrupt IN (supposed to be interrupt). Specific test case is in + ux_host_class_hub_interrupt_endpoint_start.c. */ + +#include "usbx_ux_test_hub.h" + +static unsigned char framework_non_interrupt_in_endpoint[] = { + + /* Device Descriptor */ + 0x12, /* bLength */ + 0x01, /* bDescriptorType */ + 0x00, 0x02, /* bcdUSB */ + 0x09, /* bDeviceClass - Hub */ + 0x00, /* bDeviceSubClass */ + 0x01, /* bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 */ + 0x24, 0x04, /* idVendor */ + 0x12, 0x24, /* idProduct */ + 0xb2, 0x0b, /* bcdDevice */ + 0x00, /* iManufacturer */ + 0x00, /* iProduct */ + 0x00, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ + + /* Configuration Descriptor */ + 0x09, /* bLength */ + 0x02, /* bDescriptorType */ + 0x19, 0x00, /* wTotalLength */ + 0x01, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xe0, /* bmAttributes - Self-powered */ + 0x01, /* bMaxPower */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x09, /* bInterfaceClass - Hub */ + 0x00, /* bInterfaceSubClass */ + 0x00, /* bInterfaceProtocol */ + 0x00, /* iInterface */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x81, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 64, 0x00, /* wMaxPacketSize */ + 0x0c, /* bInterval */ + +}; + +static DEVICE_INIT_DATA device_init_data = { + .dont_enumerate = 1, + .framework = framework_non_interrupt_in_endpoint, + .framework_length = sizeof(framework_non_interrupt_in_endpoint), +}; + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_non_interrupt_in_endpoint_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Hub Non Interrupt In Endpoint Test.......................... "); + + stepinfo("\n"); + + initialize_hub_with_device_init_data(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ + + ux_test_add_action_to_main_list_multiple(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HUB, UX_ENDPOINT_HANDLE_UNKNOWN), 3); + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE)); + + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + ux_test_wait_for_enum_thread_completion(); + + UX_TEST_ASSERT(ux_test_check_actions_empty() == UX_TRUE); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_hub_port_change_enable_test.c b/test/regression/usbx_hub_port_change_enable_test.c new file mode 100644 index 00000000..561a232d --- /dev/null +++ b/test/regression/usbx_hub_port_change_enable_test.c @@ -0,0 +1,41 @@ +/* This tests the case where the hub reports a port ENABLE change. The specific + test case is in ux_host_class_hub_port_change_process.c. */ + +#include "usbx_ux_test_hub.h" + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_port_change_enable_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Hub Port Change Enable Test................................. "); + + stepinfo("\n"); + + initialize_hub(first_unused_memory); +} + +static void post_init_host() +{ +#if UX_MAX_DEVICES > 1 + /* Send port change enable to host. */ + set_and_send_port_event(0, + UX_HOST_CLASS_HUB_PORT_CHANGE_ENABLE); + + /* Wait for enum thread to complete. */ + tx_thread_sleep(100); + ux_test_wait_for_enum_thread_completion(); + + /* Ensure the port enable was cleared. */ + UX_TEST_ASSERT((g_hub_device->port_change & UX_HOST_CLASS_HUB_PORT_CHANGE_ENABLE) == 0); +#endif +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_hub_port_change_over_current_test.c b/test/regression/usbx_hub_port_change_over_current_test.c new file mode 100644 index 00000000..6097fd02 --- /dev/null +++ b/test/regression/usbx_hub_port_change_over_current_test.c @@ -0,0 +1,46 @@ +/* This tests the case where the hub reports a port OVER_CURRENT change. The specific + test case is in ux_host_class_hub_port_change_process.c. */ + +#include "usbx_ux_test_hub.h" + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_port_change_over_current_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Hub Port Change Over Current Test........................... "); + + stepinfo("\n"); + + initialize_hub(first_unused_memory); +} + +static void post_init_host() +{ +#if UX_MAX_DEVICES > 1 + /* We expect USBX to report an error. */ + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HUB, UX_OVER_CURRENT_CONDITION)); + + /* Send port change enable to host. */ + set_and_send_port_event(0, + UX_HOST_CLASS_HUB_PORT_CHANGE_OVER_CURRENT); + + /* Wait for enum thread to complete. */ + tx_thread_sleep(100); + ux_test_wait_for_enum_thread_completion(); + + UX_TEST_ASSERT(ux_test_check_actions_empty() == UX_TRUE); + + /* Ensure the port enable was cleared. */ + UX_TEST_ASSERT((g_hub_device->port_change & UX_HOST_CLASS_HUB_PORT_CHANGE_OVER_CURRENT) == 0); +#endif +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_hub_port_change_reset_test.c b/test/regression/usbx_hub_port_change_reset_test.c new file mode 100644 index 00000000..9d345f73 --- /dev/null +++ b/test/regression/usbx_hub_port_change_reset_test.c @@ -0,0 +1,41 @@ +/* This tests the case where the hub reports a port RESET change. The specific + test case is in ux_host_class_hub_port_change_process.c. */ + +#include "usbx_ux_test_hub.h" + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_port_change_reset_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Hub Port Change Reset Test.................................. "); + + stepinfo("\n"); + + initialize_hub(first_unused_memory); +} + +static void post_init_host() +{ +#if UX_MAX_DEVICES > 1 + /* Send port change enable to host. */ + set_and_send_port_event(0, + UX_HOST_CLASS_HUB_PORT_CHANGE_RESET); + + /* Wait for enum thread to complete. */ + tx_thread_sleep(100); + ux_test_wait_for_enum_thread_completion(); + + /* Ensure the port enable was cleared. */ + UX_TEST_ASSERT((g_hub_device->port_change & UX_HOST_CLASS_HUB_PORT_CHANGE_RESET) == 0); +#endif +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_hub_port_change_suspend_test.c b/test/regression/usbx_hub_port_change_suspend_test.c new file mode 100644 index 00000000..3cedad62 --- /dev/null +++ b/test/regression/usbx_hub_port_change_suspend_test.c @@ -0,0 +1,41 @@ +/* This tests the case where the hub reports a port SUSPEND change. The specific + test case is in ux_host_class_hub_port_change_process.c. */ + +#include "usbx_ux_test_hub.h" + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_port_change_suspend_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Hub Port Suspend Enable Test................................ "); + + stepinfo("\n"); + + initialize_hub(first_unused_memory); +} + +static void post_init_host() +{ +#if UX_MAX_DEVICES > 1 + /* Send port change enable to host. */ + set_and_send_port_event(0, + UX_HOST_CLASS_HUB_PORT_CHANGE_SUSPEND); + + /* Wait for enum thread to complete. */ + tx_thread_sleep(100); + ux_test_wait_for_enum_thread_completion(); + + /* Ensure the port enable was cleared. */ + UX_TEST_ASSERT((g_hub_device->port_change & UX_HOST_CLASS_HUB_PORT_CHANGE_SUSPEND) == 0); +#endif +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_hub_port_never_reset_test.c b/test/regression/usbx_hub_port_never_reset_test.c new file mode 100644 index 00000000..6bdd4ef3 --- /dev/null +++ b/test/regression/usbx_hub_port_never_reset_test.c @@ -0,0 +1,42 @@ +/* This tests the case where the port reset fails because the hub never reports that the port was RESET. + The specific test case is in ux_host_class_hub_port_reset.c. */ + +#include "usbx_ux_test_hub.h" + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_port_reset_fails_due_to_unset_port_enabled_bit_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Hub Port Reset Fails Due To Unset Port Enabled Bit Test..... "); + + stepinfo("\n"); + + initialize_hub(first_unused_memory); +} + +static void post_init_host() +{ +#if UX_MAX_DEVICES > 1 + /* Make sure it is never reset. */ + g_hub_device->dont_reset_port_when_commanded_to = 1; + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HUB, UX_PORT_RESET_FAILED)); + connect_device_to_hub(); + /* Wait for enum thread to pick it up. */ + tx_thread_sleep(100); + ux_test_wait_for_enum_thread_completion(); + UX_TEST_ASSERT(g_dpump_host_from_system_change_function == UX_NULL); + + /* USBX still thinks there's a device connected (since there is, technically), so it will try to remove it, but fail. */ + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ENUMERATOR, UX_DEVICE_HANDLE_UNKNOWN)); +#endif +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_hub_port_reset_fails_during_hub_device_enum_test.c b/test/regression/usbx_hub_port_reset_fails_during_hub_device_enum_test.c new file mode 100644 index 00000000..8546c314 --- /dev/null +++ b/test/regression/usbx_hub_port_reset_fails_during_hub_device_enum_test.c @@ -0,0 +1,60 @@ +/* This tests the case where the port reset commmand fails + when a device connected to the hub is being enumerated. The specific test case + is in ux_host_class_hub_port_change_connection_process.c. */ + +#include "usbx_ux_test_hub.h" + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_port_reset_fails_during_hub_device_enumeration_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Hub Port Reset Fails During Hub Device Enumeration Test..... "); + + stepinfo("\n"); + + initialize_hub(first_unused_memory); +} + +static void post_init_host() +{ +#if UX_MAX_DEVICES > 1 + /* Make port reset fail action. */ + + UX_TEST_SETUP port_reset_setup = {0}; + port_reset_setup.ux_test_setup_request = UX_SET_FEATURE; + port_reset_setup.ux_test_setup_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_OTHER; + + UX_TEST_ACTION port_reset_fail_action = {0}; + port_reset_fail_action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + port_reset_fail_action.function = UX_HCD_TRANSFER_REQUEST; + port_reset_fail_action.req_action = UX_TEST_SETUP_MATCH_REQUEST; + port_reset_fail_action.req_setup = &port_reset_setup; + port_reset_fail_action.no_return = 0; + port_reset_fail_action.status = UX_ERROR; + + /* Add them. */ + ux_test_add_action_to_main_list(port_reset_fail_action); + + /* Tell the host that there's a device connection. */ + connect_device_to_hub(); + + /* Wait for empty actions. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_empty_actions()); + ux_test_wait_for_enum_thread_completion(); + + /* When enumeration fails, USBX still reports the device on the port, so it + will try to remove the device when the the upper-test-layer disconnects the hub. + This will result in an error that we want to ignore. */ + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ENUMERATOR, UX_DEVICE_HANDLE_UNKNOWN)); +#endif +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_hub_quick_hub_device_disconnection_test.c b/test/regression/usbx_hub_quick_hub_device_disconnection_test.c new file mode 100644 index 00000000..b8f32d78 --- /dev/null +++ b/test/regression/usbx_hub_quick_hub_device_disconnection_test.c @@ -0,0 +1,39 @@ +/* This tests the case where the hub reports a device disconnection even though + no device was previously on that port. This can happen if the device is connected + then quickly disconnected, before USBX processes the connection. The specific + test case is in ux_host_class_hub_port_change_connection_process.c. */ + +#include "usbx_ux_test_hub.h" + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_quick_hub_device_disconnection_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Hub Quick Hub Device Disconnection Test..................... "); + + stepinfo("\n"); + + initialize_hub(first_unused_memory); +} + +static void post_init_host() +{ + + /* We test this by just reporting a disconnection when no device has been + connected - USBX won't know the difference! */ + + disconnect_device_from_hub(); + /* Wait for enum thread to detect it. */ + tx_thread_sleep(100); + ux_test_wait_for_enum_thread_completion(); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_hub_quick_hub_device_reconnection_test.c b/test/regression/usbx_hub_quick_hub_device_reconnection_test.c new file mode 100644 index 00000000..3ce49a39 --- /dev/null +++ b/test/regression/usbx_hub_quick_hub_device_reconnection_test.c @@ -0,0 +1,75 @@ +/* This tests the case where the device is connected, disconnected, then reconnected + very quickly (in other words, so fast that the HCD thread doesn't detect the + disconnection). The specific test case is in ux_host_class_hub_port_change_connection_process.c. */ + +#include "usbx_ux_test_hub.h" + +static UINT num_insertions; +static UINT num_removals; + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_quick_hub_device_reconnection_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Hub Quick Hub Device Reconnection Test...................... "); + + stepinfo("\n"); + + initialize_hub(first_unused_memory); +} + +static UINT my_system_change_function(ULONG event, UX_HOST_CLASS *class, VOID *instance) +{ + + if (event == UX_DEVICE_INSERTION) + { + if (!memcmp(class->ux_host_class_name, "ux_host_class_dpump", strlen("ux_host_class_dpump"))) + { + num_insertions++; + } + } + else if (event == UX_DEVICE_REMOVAL) + { + if (!memcmp(class->ux_host_class_name, "ux_host_class_dpump", strlen("ux_host_class_dpump"))) + { + num_removals++; + } + } + return(UX_SUCCESS); +} + +static void post_init_host() +{ +#if UX_MAX_DEVICES > 1 + /* We just test this by connecting the device twice with no disconnection. */ + + /* Tell the host that there's a device connection, and wait for host to enumerate it. */ + connect_device_to_hub(); + class_dpump_get(); + + _ux_system_host->ux_system_host_change_function = my_system_change_function; + + /* Now do it again. */ + connect_device_to_hub(); + + /* Wait for the removal. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uint(&num_removals, 1)); + + /* Wait for reconnection. */ + ux_test_wait_for_enum_thread_completion(); + + /* Ensure we're all good. */ + UX_TEST_ASSERT(num_insertions == 1); + class_dpump_get(); +#endif +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_hub_request_to_hub_itself_test.c b/test/regression/usbx_hub_request_to_hub_itself_test.c new file mode 100644 index 00000000..8755abd2 --- /dev/null +++ b/test/regression/usbx_hub_request_to_hub_itself_test.c @@ -0,0 +1,50 @@ +/* This tests the case where the host sends a request to the hub itself and + not a port. */ + +#include "usbx_ux_test_hub.h" + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_request_to_hub_itself_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Hub Request To Hub Itself Test.............................. "); + + stepinfo("\n"); + + initialize_hub(first_unused_memory); +} + +static void post_init_host() +{ + + /* We perform this test by creating an action match the hub device request. + If it matches, then the request USBX sends is correct. */ + + UINT command = UX_SET_FEATURE; + UINT function = UX_HOST_CLASS_HUB_PORT_POWER; + + UX_TEST_SETUP setup = {0}; + setup.ux_test_setup_request = command; + setup.ux_test_setup_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_DEVICE; + + UX_TEST_ACTION action = {0}; + action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + action.function = UX_HCD_TRANSFER_REQUEST; + action.req_action = UX_TEST_SETUP_MATCH_REQUEST; + action.req_setup = &setup; + action.no_return = 0; + action.status = UX_SUCCESS; + ux_test_add_action_to_main_list(action); + + UX_TEST_CHECK_SUCCESS(_ux_host_class_hub_feature(g_hub_host, 0, command, function)); + + UX_TEST_ASSERT(ux_test_check_actions_empty() == UX_TRUE); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_hub_single_tt_too_many_hub_ports_test.c b/test/regression/usbx_hub_single_tt_too_many_hub_ports_test.c new file mode 100644 index 00000000..6c0ecc38 --- /dev/null +++ b/test/regression/usbx_hub_single_tt_too_many_hub_ports_test.c @@ -0,0 +1,116 @@ +/* This tests the case where the hub reports an invalid device protocol. Specific + test case is in ux_host_class_hub_descriptor_get.c. */ + +#include "usbx_ux_test_hub.h" + +static unsigned char framework_invalid_device_protocol[] = { + + /* Device Descriptor */ + 0x12, /* bLength */ + 0x01, /* bDescriptorType */ + 0x00, 0x02, /* bcdUSB */ + 0x09, /* bDeviceClass - Hub */ + 0x00, /* bDeviceSubClass */ + 0x01, /* bDeviceProtocol - single */ + 0x40, /* bMaxPacketSize0 */ + 0x24, 0x04, /* idVendor */ + 0x12, 0x24, /* idProduct */ + 0xb2, 0x0b, /* bcdDevice */ + 0x00, /* iManufacturer */ + 0x00, /* iProduct */ + 0x00, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ + + /* Configuration Descriptor */ + 0x09, /* bLength */ + 0x02, /* bDescriptorType */ + 0x19, 0x00, /* wTotalLength */ + 0x01, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xe0, /* bmAttributes - Self-powered */ + 0x01, /* bMaxPower */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x09, /* bInterfaceClass - Hub */ + 0x00, /* bInterfaceSubClass */ + 0x00, /* bInterfaceProtocol */ + 0x00, /* iInterface */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x81, /* bEndpointAddress */ + 0x03, /* bmAttributes - Interrupt */ + 0x02, 0x00, /* wMaxPacketSize */ + 0x0c, /* bInterval */ + +}; + +static unsigned char hub_descriptor_too_many_ports[] = { + + /* Hub Descriptor */ + 0x09, /* bLength */ + 0x29, /* bDescriptorType */ + 100, /* bNbrPorts */ + 0x09, 0x00, /* wHubCharacteristics */ + 0x32, /* bPwrOn2PwrGood */ + 0x01, /* bHubContrCurrent */ + 0x00, /* DeviceRemovable */ + 0xff, /* PortPwrCtrlMask */ + +}; + +static DEVICE_INIT_DATA device_init_data = { + .dont_enumerate = 1, + .framework = framework_invalid_device_protocol, + .framework_length = sizeof(framework_invalid_device_protocol), + .hub_descriptor = hub_descriptor_too_many_ports, + .hub_descriptor_length = sizeof(hub_descriptor_too_many_ports), +}; + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hub_too_many_hub_ports_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running Hub Too Many Hub Ports Test................................. "); + + stepinfo("\n"); + + initialize_hub_with_device_init_data(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ +#if UX_MAX_DEVICES > 1 +int i; + + /* We expect error to happen multiple times. */ + for (i = 0; i < UX_RH_ENUMERATION_RETRY; i++) + { + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HUB, UX_TOO_MANY_HUB_PORTS)); + } + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE)); + + /* Enumerate. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + ux_test_wait_for_enum_thread_completion(); + + /* Ensure all expected actions occurred. */ + UX_TEST_ASSERT(ux_test_check_actions_empty()); + UX_TEST_ASSERT(g_hub_host_from_system_change_function == UX_NULL); +#endif +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_msrc_66679_test.c b/test/regression/usbx_msrc_66679_test.c new file mode 100644 index 00000000..c31a6aa8 --- /dev/null +++ b/test/regression/usbx_msrc_66679_test.c @@ -0,0 +1,931 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_stack.h" +#include "ux_device_class_dummy.h" + +#include "ux_host_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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (96*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +#define UX_DEMO_VENDOR_REQUEST 0x54 + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_simulation0; +static TX_THREAD tx_test_thread_simulation1; +static VOID tx_test_thread_simulation0_entry(ULONG); +static VOID tx_test_thread_simulation1_entry(ULONG); + +static UINT test_ms_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_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +static UX_DEVICE_CLASS_DUMMY_PARAMETER *parameter; + +static UX_DEVICE *host_device = UX_NULL; + +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_mem_alloc_count; +static ULONG rsc_enum_sem_usage; +static ULONG rsc_enum_sem_get_count; +static ULONG rsc_enum_mutex_usage; + +static UINT class_entry_rc = UX_SUCCESS; + +static UINT vendor_req_rc = UX_SUCCESS; +static UINT vendor_req_ret_len = 0; +static ULONG vendor_req_req_len; +static ULONG vendor_req_buf_len; + +#define LSB(x) ((x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Storage related descriptors 9+7+7=23 bytes */ +#define MS_IFC_DESC_ALL(ifc, bulk_in_epa, bulk_out_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x03, 0x08, 0x06, 0x50, 0x00,\ + /* Endpoint descriptor (Bulk In) */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Bulk Out) */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00, +#define MS_IFC_DESC_ALL_LEN 23 + +/* CDC IAD 8 bytes */ +#define CDC_IAD_DESC(comm_ifc) \ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (comm_ifc), 0x02, 0x02, 0x02, 0x00, 0x00, +#define CDC_IAD_DESC_LEN 8 + +/* CDC Communication interface descriptors 9+5+4+5+5+7=35 bytes */ +#define CDC_COMM_IFC_DESC_ALL(comm_ifc, data_ifc, interrupt_epa) \ + /* Communication Class Interface Descriptor. 9 bytes. */\ + 0x09, 0x04, (comm_ifc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06,\ + (comm_ifc), /* Master interface */\ + (data_ifc), /* Slave interface */\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03,\ + (data_ifc), /* Data interface */\ + /* Endpoint 0x83 descriptor 7 bytes */\ + 0x07, 0x05, (interrupt_epa),\ + 0x03,\ + 0x08, 0x00,\ + 0xFF, +#define CDC_COMM_IFC_DESC_ALL_LEN 35 + +/* CDC Data interface descriptors 9+7+7=23 bytes */ +#define CDC_DATA_IFC_DESC_ALL(ifc, bulk_in_epa, bulk_out_epa) \ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (ifc),\ + 0x00, /* bAlternateSetting */\ + 0x02, /* bNumEndpoints */\ + 0x0A, 0x00, 0x00,\ + 0x00,\ + /* Endpoint bulk IN descriptor 7 bytes */\ + 0x07, 0x05, (bulk_in_epa),\ + 0x02,\ + 0x40, 0x00,\ + 0x00,\ + /* Endpoint bulk OUT descriptor 7 bytes */\ + 0x07, 0x05, (bulk_out_epa),\ + 0x02,\ + 0x40, 0x00,\ + 0x00, +#define CDC_DATA_IFC_DESC_ALL_LEN 23 + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* Define device framework. */ + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Configuration 1 descriptor 9 bytes */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0xE0, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Endpoint 0x83 descriptor 7 bytes */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, + 0x02, + 0x40, 0x00, + 0x00, + + /* Configuration 2 descriptor 9 bytes */ + 0x09, 0x02, (0x4b + 28 + 46), 0x00, + 0x02, 0x02, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x01, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Endpoint 0x83 descriptor 7 bytes */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + 0x0A, 0x00, 0x00, + 0x00, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x01, /* bAlternateSetting */ + 0x02, /* bNumEndpoints */ + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, + 0x02, + 0x40, 0x00, + 0x00, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x02, /* bAlternateSetting */ + 0x04, /* bNumEndpoints */ + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x85 descriptor 7 bytes */ + 0x07, 0x05, 0x85, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x04 descriptor 7 bytes */ + 0x07, 0x05, 0x04, + 0x02, + 0x40, 0x00, + 0x00, + + /* Configuration 3: CDC + CDC */ + CFG_DESC(CFG_DESC_LEN+2*(CDC_IAD_DESC_LEN+CDC_COMM_IFC_DESC_ALL_LEN+CDC_DATA_IFC_DESC_ALL_LEN), 4, 3) + CDC_IAD_DESC(0) + CDC_COMM_IFC_DESC_ALL(0, 1, 0x83) + CDC_DATA_IFC_DESC_ALL(1, 0x81, 0x02) + CDC_IAD_DESC(2) + CDC_COMM_IFC_DESC_ALL(2, 3, 0x86) + CDC_DATA_IFC_DESC_ALL(3, 0x84, 0x05) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor */ + 0x09, 0x02, (0x4b+5), 0x00, + 0x02, 0x01, 0x00, + 0xE0, 0x00, + + /* OTG Descriptor. */ + 0x05, 0x09, 0x03, 0x02, 0x00, + + /* Interface association descriptor. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor */ + 0x05, 0x24, 0x06, + 0x00, + 0x01, + + /* Call Management Functional Descriptor */ + 0x05, 0x24, 0x01, + 0x00, + 0x01, + + /* Endpoint 0x83 descriptor */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor */ + 0x07, 0x05, 0x81, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor */ + 0x07, 0x05, 0x02, + 0x02, + 0x40, 0x00, + 0x00, + + /* Configuration 2 descriptor 9 bytes */ + 0x09, 0x02, (0x4b + 28 + 46), 0x00, + 0x02, 0x02, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x01, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Endpoint 0x83 descriptor 7 bytes */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, + 0x00, + 0x0A, 0x00, 0x00, + 0x00, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x01, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, + 0x02, + 0x40, 0x00, + 0x00, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x02, /* bAlternateSetting */ + 0x04, /* bNumEndpoints */ + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x85 descriptor 7 bytes */ + 0x07, 0x05, 0x85, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x04 descriptor 7 bytes */ + 0x07, 0x05, 0x04, + 0x02, + 0x40, 0x00, + 0x00, + + /* Configuration 3: CDC + CDC */ + CFG_DESC(CFG_DESC_LEN+2*(CDC_IAD_DESC_LEN+CDC_COMM_IFC_DESC_ALL_LEN+CDC_DATA_IFC_DESC_ALL_LEN), 4, 3) + CDC_IAD_DESC(0) + CDC_COMM_IFC_DESC_ALL(0, 1, 0x83) + CDC_DATA_IFC_DESC_ALL(1, 0x81, 0x02) + CDC_IAD_DESC(2) + CDC_COMM_IFC_DESC_ALL(2, 3, 0x86) + CDC_DATA_IFC_DESC_ALL(3, 0x84, 0x05) +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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_DEMO_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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT test_ms_vendor_request(ULONG request, ULONG request_value, ULONG request_index, ULONG request_length, + UCHAR *transfer_request_buffer, ULONG *transfer_request_length) +{ + vendor_req_req_len = request_length; + vendor_req_buf_len = *transfer_request_length; + *transfer_request_length = vendor_req_ret_len; + return vendor_req_rc; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + + switch(event) + { + + case UX_DEVICE_INSERTION: + break; + + case UX_DEVICE_REMOVAL: + break; + + case UX_DEVICE_CONNECTION: + host_device = (UX_DEVICE *)inst; + break; + case UX_DEVICE_DISCONNECTION: + if (host_device == (UX_DEVICE *)inst) + host_device = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (error_code == UX_DEVICE_ENUMERATION_FAILURE || + error_code == UX_TRANSFER_STALLED) + { + /* It's normal. */ + return; + } + printf("error 0x%x, 0x%x, 0x%x\n", system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_msrc_66679_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + printf("Running MSRC 66679 Test............................................. "); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_count_reset(); + 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_mem_alloc_error_generation_stop(); + 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(); + + /* 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 #1\n"); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* 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 #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_device_class_dummy_name, _ux_device_class_dummy_entry, + 1, 0, ¶meter); + if(status!=UX_SUCCESS) + { + + printf(" ERROR #7\n"); + test_control_return(1); + } + + /* MS extensions. */ + status = _ux_device_stack_microsoft_extension_register(UX_DEMO_VENDOR_REQUEST, test_ms_vendor_request); + + if(status!=UX_SUCCESS) + { + + printf(" ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #8\n"); + test_control_return(1); + } + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + if (status != UX_SUCCESS) + { + + printf(" ERROR #2\n"); + 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 #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_simulation0, "tx test simulation 0", tx_test_thread_simulation0_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #9\n"); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_simulation1, "tx test simulation 1", tx_test_thread_simulation1_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #10\n"); + test_control_return(1); + } +} + +void tx_test_thread_simulation0_entry(ULONG arg) +{ +UINT status; +ULONG actual_length; +UX_DEVICE *device; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_SLAVE_TRANSFER *slave_transfer_request; + + stepinfo("\n"); + + /* Wait for first enumeration to complete. */ + stepinfo(">>>>>>>>>>>>>>>> Wait for first enumeration completion\n"); + while (host_device == UX_NULL) + tx_thread_sleep(10); + + /* Wait for instances to be live. */ + tx_thread_sleep(10); + + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Test connect. Note that we must switch to high speed for tests. */ + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + tx_thread_sleep(100); + if (host_device == UX_NULL) + { + + printf("ERROR #%d: connection not detected\n", __LINE__); + test_control_return(1); + } + + device = host_device; + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + slave_transfer_request = &_ux_system_slave->ux_system_slave_device.ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request; + + stepinfo(">>>>>>>>>>>>>>>> Test Vendor Request\n"); + transfer_request -> ux_transfer_request_function = 0xEE; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_VENDOR | UX_REQUEST_TARGET_DEVICE; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + + printf("ERROR #%d: Vendor request status %x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test MS Vendor Request\n"); + transfer_request -> ux_transfer_request_function = UX_DEMO_VENDOR_REQUEST; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_VENDOR | UX_REQUEST_TARGET_DEVICE; + + vendor_req_rc = UX_ERROR; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + + printf("ERROR #%d: Vendor request status %x\n", __LINE__, status); + test_control_return(1); + } + vendor_req_rc = UX_SUCCESS; + + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: Vendor request status %x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test MSRC Error cases\n"); + /* + Execution flow steps: + ``` + - control request transfer message received, properties set as following + - request_type = UX_REQUEST_TYPE_VENDOR + - request = _ux_system_slave -> ux_system_slave_device_vendor_request) + - ux_system_slave_device_vendor_request_function is executed, returns UX_SUCCESS, sets application_data_length + - _ux_device_stack_transfer_request(transfer_request, request_length, application_data_length) call results in transfer of request_length bytes of data (0xffff) to the host, buffer overflow occurs + ``` + */ + vendor_req_rc = UX_SUCCESS; + vendor_req_ret_len = 8; + transfer_request -> ux_transfer_request_requested_length = 0xFFFF; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(vendor_req_buf_len <= UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH); + UX_TEST_ASSERT(vendor_req_req_len == transfer_request -> ux_transfer_request_requested_length); + UX_TEST_ASSERT(transfer_request -> ux_transfer_request_actual_length == vendor_req_ret_len); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* 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 tx_test_thread_simulation1_entry(ULONG arg) +{ + +UINT status; +ULONG actual_length; + + while(1) + { + + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); + } +} diff --git a/test/regression/usbx_msrc_69702_dfu_dnload_test.c b/test/regression/usbx_msrc_69702_dfu_dnload_test.c new file mode 100644 index 00000000..72694881 --- /dev/null +++ b/test/regression/usbx_msrc_69702_dfu_dnload_test.c @@ -0,0 +1,847 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" + +#include "fx_api.h" + +#include "ux_device_class_dfu.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +#define UX_DEMO_REQUEST_MAX_LENGTH \ + ((UX_HCD_SIM_HOST_MAX_PAYLOAD) > (UX_SLAVE_REQUEST_DATA_MAX_LENGTH) ? \ + (UX_HCD_SIM_HOST_MAX_PAYLOAD) : (UX_SLAVE_REQUEST_DATA_MAX_LENGTH)) + + +/* Define constants. */ + +#define UX_DEMO_MEMORY_SIZE (128*1024) +#define UX_DEMO_STACK_SIZE (1024) + + +/* Define local/extern function prototypes. */ + +static void test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static void tx_test_thread_host_simulation_entry(ULONG); +static void tx_test_thread_slave_simulation_entry(ULONG); + +static VOID demo_thread_dfu_activate(VOID *dfu); +static VOID demo_thread_dfu_deactivate(VOID *dfu); +static UINT demo_thread_dfu_read(VOID *dfu, ULONG block_number, UCHAR * data_pointer, ULONG length, ULONG *actual_length); +static UINT demo_thread_dfu_write(VOID *dfu, ULONG block_number, UCHAR * data_pointer, ULONG length, ULONG *media_status); +static UINT demo_thread_dfu_get_status(VOID *dfu, ULONG *media_status); +static UINT demo_thread_dfu_notify(VOID *dfu, ULONG notification); +static UINT demo_thread_dfu_custom_request(VOID *dfu, UX_SLAVE_TRANSFER *transfer); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +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 interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +static UX_SLAVE_CLASS_DFU_PARAMETER dfu_parameter; + +static UX_DEVICE *device; +static ULONG dfu_block; +static ULONG dfu_transfer_length; +static ULONG dfu_actual_length; +static UCHAR dfu_host_buffer[UX_DEMO_REQUEST_MAX_LENGTH]; +static UCHAR dfu_device_buffer[UX_DEMO_REQUEST_MAX_LENGTH]; + + +/* Define device framework. */ + +/* DFU descriptor must be same for all frameworks!!! */ +#define DFU_FUNCTION_DESCRIPTOR \ + /* Functional descriptor for DFU. */ \ + 0x09, 0x21, \ + 0x0f, /* bmAttributes: B3 bitWillDetach */ \ + /* B2 bitManifestationTolerant */ \ + /* B1 bitCanUpload, B0 bitCanDnload */ \ + 0xE8, 0x03, /* wDetachTimeOut: 0x03E8 (1000) */ \ + UX_W0(UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH), \ + UX_W1(UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH), /* wTransferSize: */ \ + 0x00, 0x01, /* bcdDFUVersion: 0x0100 */ + +/* Interface descriptor for APP/DFU mode. */ +#define DFU_INTERFACE_DESCRIPTOR(bInterfaceNumber, bInterfaceProtocol) \ + /* Interface descriptor for DFU. */ \ + 0x09, 0x04, \ + (bInterfaceNumber), 0x00, 0x00, \ + 0xFE, 0x01, (bInterfaceProtocol), \ + 0x00, \ + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x40, + 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x1b, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor for DFU (bInterfaceProtocol = 1). */ + DFU_INTERFACE_DESCRIPTOR(0x00, 0x01) + DFU_FUNCTION_DESCRIPTOR +}; + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x99, 0x99, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x1b, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor for DFU (bInterfaceProtocol = 1). */ + DFU_INTERFACE_DESCRIPTOR(0x00, 0x01) + DFU_FUNCTION_DESCRIPTOR +}; + +/* 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 sizeof(string_framework) +static UCHAR string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Microsoft AzureRTOS" */ + 0x09, 0x04, 0x01, 19, + 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', + 't', ' ', 'A', 'z', 'u', 'r', 'e', 'R', + 'T', 'O', 'S', + + /* Product string descriptor : Index 2 - "DFU Demo Device" */ + 0x09, 0x04, 0x02, 15, + 'D', 'F', 'U', ' ', 'D', 'e', 'm', 'o', + ' ', 'D', 'e', 'v', 'i', 'c', 'e', + + /* Serial Number string descriptor : Index 3 - "0000" */ + 0x09, 0x04, 0x03, 0x04, + '0', '0', '0', '0' +}; + +/* 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 sizeof(language_id_framework) +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; + + +#define DEVICE_FRAMEWORK_LENGTH_DFU sizeof(device_framework_dfu) +static UCHAR device_framework_dfu[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x40, + 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x1B, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor for DFU (bInterfaceProtocol = 2). */ + DFU_INTERFACE_DESCRIPTOR(0x00, 0x02) + DFU_FUNCTION_DESCRIPTOR +}; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* 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); + } + } +} + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static UINT demo_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + if (event == UX_DEVICE_CONNECTION) + { + device = (UX_DEVICE *)inst; + } + if (event == UX_DEVICE_DISCONNECTION) + { + if ((VOID *)device == inst) + device = UX_NULL; + } +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_device_dfu_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +ULONG test_n; + + /* Inform user. */ + printf("Running MSRC 69702: Device DFU DNLOAD 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(); + + /* 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 #%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(demo_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* There is no host class for DFU now. */ + + /* 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); + } + + /* Store the DFU parameters. */ + dfu_parameter.ux_slave_class_dfu_parameter_instance_activate = demo_thread_dfu_activate; + dfu_parameter.ux_slave_class_dfu_parameter_instance_deactivate = demo_thread_dfu_deactivate; + dfu_parameter.ux_slave_class_dfu_parameter_read = demo_thread_dfu_read; + dfu_parameter.ux_slave_class_dfu_parameter_write = demo_thread_dfu_write; + dfu_parameter.ux_slave_class_dfu_parameter_get_status = demo_thread_dfu_get_status; + dfu_parameter.ux_slave_class_dfu_parameter_notify = demo_thread_dfu_notify; +#ifdef UX_DEVICE_CLASS_DFU_CUSTOM_REQUEST_ENABLE + dfu_parameter.ux_device_class_dfu_parameter_custom_request = demo_thread_dfu_custom_request; +#endif + dfu_parameter.ux_slave_class_dfu_parameter_framework = device_framework_dfu; + dfu_parameter.ux_slave_class_dfu_parameter_framework_length = DEVICE_FRAMEWORK_LENGTH_DFU; + + /* Initilize the device dfu class. The class is connected with interface 1 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_dfu_name, ux_device_class_dfu_entry, + 1, 0, (VOID *)&dfu_parameter); + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_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_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(&tx_test_thread_host_simulation, "tx demo host simulation", tx_test_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx demo slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +static UINT _req_DFU_LOCK(UX_TRANSFER *control_transfer) +{ +UINT status; +#if defined(UX_HOST_STANDALONE) + while(1) + { + ux_system_tasks_run(); + tx_thread_relinquish(); + + UX_ENDPOINT *endpoint = control_transfer -> ux_transfer_request_endpoint; + if (endpoint == UX_NULL || endpoint -> ux_endpoint_state != UX_ENDPOINT_RUNNING) + { + status = UX_ENDPOINT_HANDLE_UNKNOWN; + break; + } + UX_DEVICE *device = endpoint -> ux_endpoint_device; + if (device == UX_NULL || device -> ux_device_handle != (ULONG)(ALIGN_TYPE)(device)) + { + status = UX_DEVICE_HANDLE_UNKNOWN; + break; + } + if ((device -> ux_device_flags & UX_DEVICE_FLAG_LOCK) == 0) + { + device -> ux_device_flags |= UX_DEVICE_FLAG_LOCK; + control_transfer -> ux_transfer_request_flags |= UX_TRANSFER_FLAG_AUTO_DEVICE_UNLOCK; + control_transfer -> ux_transfer_request_timeout_value = UX_WAIT_FOREVER; + status = UX_SUCCESS; + break; + } + } +#else + status = _ux_utility_semaphore_get(&control_transfer->ux_transfer_request_endpoint->ux_endpoint_device->ux_device_protection_semaphore, UX_WAIT_FOREVER); +#endif + if (status != UX_SUCCESS) + { + printf("ERROR #%d: %x\n", __LINE__, status); + test_control_return(1); + } +} +static UINT _req_DFU_GETSTATE(UX_TRANSFER *control_transfer) +{ + _req_DFU_LOCK(control_transfer); + control_transfer->ux_transfer_request_type = 0xA1; + control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_GET_STATE; + control_transfer->ux_transfer_request_index = 0; + control_transfer->ux_transfer_request_requested_length = 1; + control_transfer->ux_transfer_request_data_pointer = dfu_host_buffer; + control_transfer->ux_transfer_request_value = 0; + return ux_host_stack_transfer_request(control_transfer); +} +static UINT _req_DFU_GETSTATUS(UX_TRANSFER *control_transfer) +{ + _req_DFU_LOCK(control_transfer); + control_transfer->ux_transfer_request_type = 0xA1; + control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_GET_STATUS; + control_transfer->ux_transfer_request_index = 0; + control_transfer->ux_transfer_request_requested_length = 6; + control_transfer->ux_transfer_request_data_pointer = dfu_host_buffer; + control_transfer->ux_transfer_request_value = 0; + return ux_host_stack_transfer_request(control_transfer); +} +static UINT _req_DFU_DETACH(UX_TRANSFER *control_transfer) +{ + _req_DFU_LOCK(control_transfer); + control_transfer->ux_transfer_request_type = 0x21; + control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_DETACH; + control_transfer->ux_transfer_request_index = 0; + control_transfer->ux_transfer_request_value = 1000; + control_transfer->ux_transfer_request_requested_length = 0; + return ux_host_stack_transfer_request(control_transfer); +} +static UINT _req_DFU_DNLOAD_IN(UX_TRANSFER *control_transfer, ULONG block, ULONG len) +{ + _req_DFU_LOCK(control_transfer); + control_transfer->ux_transfer_request_type = 0xA1; + control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_DOWNLOAD; + control_transfer->ux_transfer_request_index = 0; + control_transfer->ux_transfer_request_data_pointer = dfu_host_buffer; + control_transfer->ux_transfer_request_requested_length = len; + control_transfer->ux_transfer_request_value = block; + return ux_host_stack_transfer_request(control_transfer); +} +static UINT _req_DFU_DNLOAD(UX_TRANSFER *control_transfer, ULONG block, ULONG len) +{ + _req_DFU_LOCK(control_transfer); + control_transfer->ux_transfer_request_type = 0x21; + control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_DOWNLOAD; + control_transfer->ux_transfer_request_index = 0; + control_transfer->ux_transfer_request_data_pointer = dfu_host_buffer; + control_transfer->ux_transfer_request_requested_length = len; + control_transfer->ux_transfer_request_value = block; + return ux_host_stack_transfer_request(control_transfer); +} +static UINT _req_DFU_UPLOAD(UX_TRANSFER *control_transfer, ULONG block, ULONG len) +{ + _req_DFU_LOCK(control_transfer); + control_transfer->ux_transfer_request_type = 0xA1; + control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_UPLOAD; + control_transfer->ux_transfer_request_index = 0; + control_transfer->ux_transfer_request_data_pointer = dfu_host_buffer; + control_transfer->ux_transfer_request_requested_length = len; + control_transfer->ux_transfer_request_value = block; + return ux_host_stack_transfer_request(control_transfer); +} +static UINT _req_DFU_CLRSTATUS(UX_TRANSFER *control_transfer) +{ + _req_DFU_LOCK(control_transfer); + control_transfer->ux_transfer_request_type = 0x21; + control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_CLEAR_STATUS; + control_transfer->ux_transfer_request_index = 0; + control_transfer->ux_transfer_request_data_pointer = UX_NULL; + control_transfer->ux_transfer_request_requested_length = 0; + control_transfer->ux_transfer_request_value = 0; + return ux_host_stack_transfer_request(control_transfer); +} + + +static void tx_test_thread_host_simulation_entry(ULONG arg) +{ +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *control_transfer; +ULONG len, trans_len, block; +INT i; +UINT status; + + stepinfo("\n"); + + stepinfo(">>>>>>>>>>>> Test DFU connect\n"); + status = ux_test_wait_for_non_null((VOID **)&device); + UX_TEST_ASSERT(status == UX_SUCCESS); + if (device -> ux_device_state == UX_DEVICE_CONFIGURED) + { + printf("ERROR #%d, device state 0x%lx\n", __LINE__, device->ux_device_state); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Test DFU set configure\n"); + status = ux_host_stack_device_configuration_select(device->ux_device_first_configuration); + UX_TEST_ASSERT(status == UX_SUCCESS); + + /* Get endpoint and transfer request. */ + control_endpoint = &device->ux_device_control_endpoint; + control_transfer = &control_endpoint->ux_endpoint_transfer_request; + + stepinfo(">>>>>>>>>>>> Test DFU_GETSTATE\n"); + status = _req_DFU_GETSTATE(control_transfer); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: transfer status 0x%x\n", __LINE__, status); + test_control_return(1); + } + UX_TEST_ASSERT(dfu_host_buffer[0] == UX_SYSTEM_DFU_STATE_APP_IDLE); + + stepinfo(">>>>>>>>>>>> Test DFU DETACH\n"); + + /* Uses DFU framework after USB reset (re-connect). */ + ux_test_dcd_sim_slave_connect_framework(device_framework_dfu, DEVICE_FRAMEWORK_LENGTH_DFU); + status = _req_DFU_DETACH(control_transfer); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: transfer status 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = ux_test_wait_for_null((VOID **)&device); + UX_TEST_ASSERT(status == UX_SUCCESS); + status = ux_test_wait_for_non_null((VOID **)&device); + UX_TEST_ASSERT(status == UX_SUCCESS); + status = ux_host_stack_device_configuration_select(device->ux_device_first_configuration); + UX_TEST_ASSERT(status == UX_SUCCESS); + + status = _req_DFU_GETSTATE(control_transfer); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: transfer status 0x%x\n", __LINE__, status); + test_control_return(1); + } + UX_TEST_ASSERT(dfu_host_buffer[0] == UX_SYSTEM_DFU_STATE_DFU_IDLE); + + stepinfo(">>>>>>>>>>>> Test DFU DNLOAD direction error\n"); + status = _req_DFU_DNLOAD_IN(control_transfer, 0, 16); + UX_TEST_CHECK_CODE(UX_TRANSFER_STALLED, status); + status = _req_DFU_CLRSTATUS(control_transfer); + UX_TEST_CHECK_SUCCESS(status); + status = _req_DFU_GETSTATE(control_transfer); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: transfer status 0x%x\n", __LINE__, status); + test_control_return(1); + } + UX_TEST_ASSERT(dfu_host_buffer[0] == UX_SYSTEM_DFU_STATE_DFU_IDLE); + + stepinfo(">>>>>>>>>>>> Test DFU DNLOAD length\n"); + status = _req_DFU_DNLOAD(control_transfer, 0, UX_DEMO_REQUEST_MAX_LENGTH); + UX_TEST_CHECK_CODE(UX_TRANSFER_STALLED, status); + status = _req_DFU_CLRSTATUS(control_transfer); + UX_TEST_CHECK_SUCCESS(status); + status = _req_DFU_GETSTATE(control_transfer); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: transfer status 0x%x\n", __LINE__, status); + test_control_return(1); + } + UX_TEST_ASSERT(dfu_host_buffer[0] == UX_SYSTEM_DFU_STATE_DFU_IDLE); + + stepinfo(">>>>>>>>>>>> Test DFU DNLOAD direction error @ DNLOAD_IDLE\n"); + trans_len = 2; block = 0; + for (i = 0; i < trans_len; i ++) + { + dfu_host_buffer[i] = (UCHAR)(block + i); + dfu_device_buffer[i] = 0xFF; + } + status = _req_DFU_DNLOAD(control_transfer, block, trans_len); + if (status != UX_SUCCESS) + { + printf("ERROR #%d(%ld, %ld): DNLOAD status 0x%x\n", __LINE__, block, trans_len, status); + test_control_return(1); + } + UX_TEST_ASSERT(dfu_transfer_length == trans_len); + UX_TEST_ASSERT(dfu_block == block); + if (ux_utility_memory_compare(dfu_host_buffer, dfu_device_buffer, trans_len) != UX_SUCCESS) + { + printf("ERROR #%d(%ld, %ld): data error\n", __LINE__, block, trans_len); + test_control_return(1); + } + status = _req_DFU_GETSTATUS(control_transfer); + if (status != UX_SUCCESS) + { + printf("ERROR #%d(%ld, %ld): GETSTATUS status 0x%x\n", __LINE__, block, trans_len, status); + test_control_return(1); + } + status = _req_DFU_DNLOAD_IN(control_transfer, 0, 16); + UX_TEST_CHECK_CODE(UX_TRANSFER_STALLED, status); + status = _req_DFU_CLRSTATUS(control_transfer); + UX_TEST_CHECK_SUCCESS(status); + status = _req_DFU_GETSTATE(control_transfer); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: transfer status 0x%x\n", __LINE__, status); + test_control_return(1); + } + UX_TEST_ASSERT(dfu_host_buffer[0] == UX_SYSTEM_DFU_STATE_DFU_IDLE); + + stepinfo(">>>>>>>>>>>> Test DFU DNLOAD length error @ DNLOAD_IDLE\n"); + trans_len = 2; block = 0; + for (i = 0; i < trans_len; i ++) + { + dfu_host_buffer[i] = (UCHAR)(block + i); + dfu_device_buffer[i] = 0xFF; + } + status = _req_DFU_DNLOAD(control_transfer, block, trans_len); + if (status != UX_SUCCESS) + { + printf("ERROR #%d(%ld, %ld): DNLOAD status 0x%x\n", __LINE__, block, trans_len, status); + test_control_return(1); + } + UX_TEST_ASSERT(dfu_transfer_length == trans_len); + UX_TEST_ASSERT(dfu_block == block); + if (ux_utility_memory_compare(dfu_host_buffer, dfu_device_buffer, trans_len) != UX_SUCCESS) + { + printf("ERROR #%d(%ld, %ld): data error\n", __LINE__, block, trans_len); + test_control_return(1); + } + status = _req_DFU_GETSTATUS(control_transfer); + if (status != UX_SUCCESS) + { + printf("ERROR #%d(%ld, %ld): GETSTATUS status 0x%x\n", __LINE__, block, trans_len, status); + test_control_return(1); + } + status = _req_DFU_DNLOAD(control_transfer, 0, UX_DEMO_REQUEST_MAX_LENGTH); + UX_TEST_CHECK_CODE(UX_TRANSFER_STALLED, status); + status = _req_DFU_CLRSTATUS(control_transfer); + UX_TEST_CHECK_SUCCESS(status); + status = _req_DFU_GETSTATE(control_transfer); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: transfer status 0x%x\n", __LINE__, status); + test_control_return(1); + } + UX_TEST_ASSERT(dfu_host_buffer[0] == UX_SYSTEM_DFU_STATE_DFU_IDLE); + + stepinfo(">>>>>>>>>>>> All Done\n"); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* 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 void tx_test_thread_slave_simulation_entry(ULONG arg) +{ + while(1) + { + +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); + tx_thread_relinquish(); +#else + + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); +#endif + } +} + +static UINT demo_device_state_change(ULONG event) +{ + return(UX_SUCCESS); +} + +static VOID demo_thread_dfu_activate(VOID *dfu) +{ +} + +static VOID demo_thread_dfu_deactivate(VOID *dfu) +{ +} + +static UINT demo_thread_dfu_read(VOID *dfu, ULONG block_number, UCHAR * data_pointer, ULONG length, ULONG *actual_length) +{ +ULONG return_length; + + stepinfo("dfuRead %ld,%ld: %2x %2x %2x %2x ... -> %p\n", block_number, length, + dfu_device_buffer[0], dfu_device_buffer[1], dfu_device_buffer[2], dfu_device_buffer[3], + data_pointer); + dfu_block = block_number; + dfu_transfer_length = length; + + return_length = UX_MIN(length, sizeof(dfu_device_buffer)); + return_length = UX_MIN(return_length, dfu_actual_length); + + ux_utility_memory_copy(data_pointer, dfu_device_buffer, return_length); + + /* Here is where the data block is read from the firmware. */ + /* Some code needs to be inserted specifically for a target platform. */ + *actual_length = return_length; + return(UX_SUCCESS); +} + +static UINT demo_thread_dfu_write(VOID *dfu, ULONG block_number, UCHAR * data_pointer, ULONG length, ULONG *media_status) +{ + stepinfo("dfuWrite %ld,%ld\n", block_number, length); + dfu_block = block_number; + dfu_transfer_length = length; + ux_utility_memory_copy(dfu_device_buffer, data_pointer, UX_MIN(length, sizeof(dfu_device_buffer))); + + /* Here is where the data block is coming to be written to the firmware. */ + /* Some code needs to be inserted specifically for a target platform. */ + /* Return media status ok. */ + if (length > UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH) + return(UX_ERROR); + *media_status = UX_SLAVE_CLASS_DFU_MEDIA_STATUS_OK ; + return(UX_SUCCESS); +} + +static UINT demo_thread_dfu_get_status(VOID *dfu, ULONG *media_status) +{ + + /* Return media status ok. */ + *media_status = UX_SLAVE_CLASS_DFU_MEDIA_STATUS_OK ; + + return(UX_SUCCESS); +} + +static UINT demo_thread_dfu_notify(VOID *dfu, ULONG notification) +{ + stepinfo("dfuNotify 0x%lx\n", notification); + switch (notification) + { + + + case UX_SLAVE_CLASS_DFU_NOTIFICATION_BEGIN_DOWNLOAD : + + /* Begin of Download. */ + break; + + case UX_SLAVE_CLASS_DFU_NOTIFICATION_END_DOWNLOAD : + + /* Completion of Download. */ + break; + + case UX_SLAVE_CLASS_DFU_NOTIFICATION_ABORT_DOWNLOAD : + + /* Download was aborted. */ + break; + + case UX_SLAVE_CLASS_DFU_NOTIFICATION_BEGIN_UPLOAD : + + /* Begin of UPLOAD. */ + break; + + case UX_SLAVE_CLASS_DFU_NOTIFICATION_END_UPLOAD : + + /* Completion of UPLOAD. */ + break; + + case UX_SLAVE_CLASS_DFU_NOTIFICATION_ABORT_UPLOAD : + + /* Download was aborted. */ + break; + + default : + + /* Bad notification signal. Should never get here. */ + break; + + } + + return(UX_SUCCESS); +} + +static UINT demo_thread_dfu_custom_request(VOID *dfu, UX_SLAVE_TRANSFER *transfer) +{ +UCHAR *setup; +UCHAR *buffer; + + /* Check state and request to insert custom operation, before the standard + handling process. + If no standard handling process is needed, return UX_SUCCESS. + */ + + /* E.g., accept DNLOAD command with wLength 0 in dfuIDLE. */ + if (ux_device_class_dfu_state_get((UX_SLAVE_CLASS_DFU *)dfu) == UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_IDLE) + { + setup = transfer -> ux_slave_transfer_request_setup; + buffer = transfer -> ux_slave_transfer_request_data_pointer; + + if (setup[UX_SETUP_REQUEST] == UX_SLAVE_CLASS_DFU_COMMAND_DOWNLOAD && + setup[UX_SETUP_LENGTH] == 0 && + setup[UX_SETUP_LENGTH + 1] == 0) + { + + /* Accept the case (by default it's stalled). */ + stepinfo("dfuIDLE - accept dfuDNLOAD & wLength 0\n"); + + /* Fill the status data payload. First with status. */ + *buffer = UX_SLAVE_CLASS_DFU_STATUS_OK; + + /* Poll time out value is set to 500ms. */ + *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT) = UX_DW0(500); + *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 1) = UX_DW1(500); + *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 2) = UX_DW2(500); + + /* Next state: still dfuIDLE. */ + *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_STATE) = (UCHAR) UX_SYSTEM_DFU_STATE_DFU_IDLE; + + /* String index set to 0. */ + *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_STRING) = 0; + + /* We have a request to obtain the status of the DFU instance. */ + _ux_device_stack_transfer_request(transfer, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH); + + /* Inform stack it's taken. */ + return(UX_SUCCESS); + } + } + + /* No custom request. */ + return(UX_ERROR); +} diff --git a/test/regression/usbx_msrc_71934_dfu_upload_test.c b/test/regression/usbx_msrc_71934_dfu_upload_test.c new file mode 100644 index 00000000..5e4ec48a --- /dev/null +++ b/test/regression/usbx_msrc_71934_dfu_upload_test.c @@ -0,0 +1,807 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" + +#include "fx_api.h" + +#include "ux_device_class_dfu.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +#define UX_DEMO_REQUEST_MAX_LENGTH \ + ((UX_HCD_SIM_HOST_MAX_PAYLOAD) > (UX_SLAVE_REQUEST_DATA_MAX_LENGTH) ? \ + (UX_HCD_SIM_HOST_MAX_PAYLOAD) : (UX_SLAVE_REQUEST_DATA_MAX_LENGTH)) + + +/* Define constants. */ + +#define UX_DEMO_MEMORY_SIZE (128*1024) +#define UX_DEMO_STACK_SIZE (1024) + + +/* Define local/extern function prototypes. */ + +static void test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static void tx_test_thread_host_simulation_entry(ULONG); +static void tx_test_thread_slave_simulation_entry(ULONG); + +static VOID demo_thread_dfu_activate(VOID *dfu); +static VOID demo_thread_dfu_deactivate(VOID *dfu); +static UINT demo_thread_dfu_read(VOID *dfu, ULONG block_number, UCHAR * data_pointer, ULONG length, ULONG *actual_length); +static UINT demo_thread_dfu_write(VOID *dfu, ULONG block_number, UCHAR * data_pointer, ULONG length, ULONG *media_status); +static UINT demo_thread_dfu_get_status(VOID *dfu, ULONG *media_status); +static UINT demo_thread_dfu_notify(VOID *dfu, ULONG notification); +static UINT demo_thread_dfu_custom_request(VOID *dfu, UX_SLAVE_TRANSFER *transfer); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +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 interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +static UX_SLAVE_CLASS_DFU_PARAMETER dfu_parameter; + +static UX_DEVICE *device; +static ULONG dfu_block; +static ULONG dfu_transfer_length; +static ULONG dfu_actual_length; +static UCHAR dfu_host_buffer[UX_DEMO_REQUEST_MAX_LENGTH]; +static UCHAR dfu_device_buffer[UX_DEMO_REQUEST_MAX_LENGTH]; + + +/* Define device framework. */ + +/* DFU descriptor must be same for all frameworks!!! */ +#define DFU_FUNCTION_DESCRIPTOR \ + /* Functional descriptor for DFU. */ \ + 0x09, 0x21, \ + 0x0f, /* bmAttributes: B3 bitWillDetach */ \ + /* B2 bitManifestationTolerant */ \ + /* B1 bitCanUpload, B0 bitCanDnload */ \ + 0xE8, 0x03, /* wDetachTimeOut: 0x03E8 (1000) */ \ + UX_W0(UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH), \ + UX_W1(UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH), /* wTransferSize: */ \ + 0x00, 0x01, /* bcdDFUVersion: 0x0100 */ + +/* Interface descriptor for APP/DFU mode. */ +#define DFU_INTERFACE_DESCRIPTOR(bInterfaceNumber, bInterfaceProtocol) \ + /* Interface descriptor for DFU. */ \ + 0x09, 0x04, \ + (bInterfaceNumber), 0x00, 0x00, \ + 0xFE, 0x01, (bInterfaceProtocol), \ + 0x00, \ + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x40, + 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x1b, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor for DFU (bInterfaceProtocol = 1). */ + DFU_INTERFACE_DESCRIPTOR(0x00, 0x01) + DFU_FUNCTION_DESCRIPTOR +}; + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x99, 0x99, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x1b, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor for DFU (bInterfaceProtocol = 1). */ + DFU_INTERFACE_DESCRIPTOR(0x00, 0x01) + DFU_FUNCTION_DESCRIPTOR +}; + +/* 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 sizeof(string_framework) +static UCHAR string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Microsoft AzureRTOS" */ + 0x09, 0x04, 0x01, 19, + 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', + 't', ' ', 'A', 'z', 'u', 'r', 'e', 'R', + 'T', 'O', 'S', + + /* Product string descriptor : Index 2 - "DFU Demo Device" */ + 0x09, 0x04, 0x02, 15, + 'D', 'F', 'U', ' ', 'D', 'e', 'm', 'o', + ' ', 'D', 'e', 'v', 'i', 'c', 'e', + + /* Serial Number string descriptor : Index 3 - "0000" */ + 0x09, 0x04, 0x03, 0x04, + '0', '0', '0', '0' +}; + +/* 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 sizeof(language_id_framework) +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; + + +#define DEVICE_FRAMEWORK_LENGTH_DFU sizeof(device_framework_dfu) +static UCHAR device_framework_dfu[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x40, + 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x1B, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor for DFU (bInterfaceProtocol = 2). */ + DFU_INTERFACE_DESCRIPTOR(0x00, 0x02) + DFU_FUNCTION_DESCRIPTOR +}; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* 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); + } + } +} + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static UINT demo_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + if (event == UX_DEVICE_CONNECTION) + { + device = (UX_DEVICE *)inst; + } + if (event == UX_DEVICE_DISCONNECTION) + { + if ((VOID *)device == inst) + device = UX_NULL; + } +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_device_dfu_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +ULONG test_n; + + /* Inform user. */ + printf("Running MSRC 71934: Device DFU UPLOAD 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(); + + /* 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 #%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(demo_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* There is no host class for DFU now. */ + + /* 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); + } + + /* Store the DFU parameters. */ + dfu_parameter.ux_slave_class_dfu_parameter_instance_activate = demo_thread_dfu_activate; + dfu_parameter.ux_slave_class_dfu_parameter_instance_deactivate = demo_thread_dfu_deactivate; + dfu_parameter.ux_slave_class_dfu_parameter_read = demo_thread_dfu_read; + dfu_parameter.ux_slave_class_dfu_parameter_write = demo_thread_dfu_write; + dfu_parameter.ux_slave_class_dfu_parameter_get_status = demo_thread_dfu_get_status; + dfu_parameter.ux_slave_class_dfu_parameter_notify = demo_thread_dfu_notify; +#ifdef UX_DEVICE_CLASS_DFU_CUSTOM_REQUEST_ENABLE + dfu_parameter.ux_device_class_dfu_parameter_custom_request = demo_thread_dfu_custom_request; +#endif + dfu_parameter.ux_slave_class_dfu_parameter_framework = device_framework_dfu; + dfu_parameter.ux_slave_class_dfu_parameter_framework_length = DEVICE_FRAMEWORK_LENGTH_DFU; + + /* Initilize the device dfu class. The class is connected with interface 1 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_dfu_name, ux_device_class_dfu_entry, + 1, 0, (VOID *)&dfu_parameter); + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_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_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(&tx_test_thread_host_simulation, "tx demo host simulation", tx_test_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx demo slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +static UINT _req_DFU_LOCK(UX_TRANSFER *control_transfer) +{ +UINT status; +#if defined(UX_HOST_STANDALONE) + while(1) + { + ux_system_tasks_run(); + tx_thread_relinquish(); + + UX_ENDPOINT *endpoint = control_transfer -> ux_transfer_request_endpoint; + if (endpoint == UX_NULL || endpoint -> ux_endpoint_state != UX_ENDPOINT_RUNNING) + { + status = UX_ENDPOINT_HANDLE_UNKNOWN; + break; + } + UX_DEVICE *device = endpoint -> ux_endpoint_device; + if (device == UX_NULL || device -> ux_device_handle != (ULONG)(ALIGN_TYPE)(device)) + { + status = UX_DEVICE_HANDLE_UNKNOWN; + break; + } + if ((device -> ux_device_flags & UX_DEVICE_FLAG_LOCK) == 0) + { + device -> ux_device_flags |= UX_DEVICE_FLAG_LOCK; + control_transfer -> ux_transfer_request_flags |= UX_TRANSFER_FLAG_AUTO_DEVICE_UNLOCK; + control_transfer -> ux_transfer_request_timeout_value = UX_WAIT_FOREVER; + status = UX_SUCCESS; + break; + } + } +#else + status = _ux_utility_semaphore_get(&control_transfer->ux_transfer_request_endpoint->ux_endpoint_device->ux_device_protection_semaphore, UX_WAIT_FOREVER); +#endif + if (status != UX_SUCCESS) + { + printf("ERROR #%d: %x\n", __LINE__, status); + test_control_return(1); + } +} +static UINT _req_DFU_GETSTATE(UX_TRANSFER *control_transfer) +{ + _req_DFU_LOCK(control_transfer); + control_transfer->ux_transfer_request_type = 0xA1; + control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_GET_STATE; + control_transfer->ux_transfer_request_index = 0; + control_transfer->ux_transfer_request_requested_length = 1; + control_transfer->ux_transfer_request_data_pointer = dfu_host_buffer; + control_transfer->ux_transfer_request_value = 0; + return ux_host_stack_transfer_request(control_transfer); +} +static UINT _req_DFU_GETSTATUS(UX_TRANSFER *control_transfer) +{ + _req_DFU_LOCK(control_transfer); + control_transfer->ux_transfer_request_type = 0xA1; + control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_GET_STATUS; + control_transfer->ux_transfer_request_index = 0; + control_transfer->ux_transfer_request_requested_length = 6; + control_transfer->ux_transfer_request_data_pointer = dfu_host_buffer; + control_transfer->ux_transfer_request_value = 0; + return ux_host_stack_transfer_request(control_transfer); +} +static UINT _req_DFU_DETACH(UX_TRANSFER *control_transfer) +{ + _req_DFU_LOCK(control_transfer); + control_transfer->ux_transfer_request_type = 0x21; + control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_DETACH; + control_transfer->ux_transfer_request_index = 0; + control_transfer->ux_transfer_request_value = 1000; + control_transfer->ux_transfer_request_requested_length = 0; + return ux_host_stack_transfer_request(control_transfer); +} +static UINT _req_DFU_DNLOAD_IN(UX_TRANSFER *control_transfer, ULONG block, ULONG len) +{ + _req_DFU_LOCK(control_transfer); + control_transfer->ux_transfer_request_type = 0xA1; + control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_DOWNLOAD; + control_transfer->ux_transfer_request_index = 0; + control_transfer->ux_transfer_request_data_pointer = dfu_host_buffer; + control_transfer->ux_transfer_request_requested_length = len; + control_transfer->ux_transfer_request_value = block; + return ux_host_stack_transfer_request(control_transfer); +} +static UINT _req_DFU_DNLOAD(UX_TRANSFER *control_transfer, ULONG block, ULONG len) +{ + _req_DFU_LOCK(control_transfer); + control_transfer->ux_transfer_request_type = 0x21; + control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_DOWNLOAD; + control_transfer->ux_transfer_request_index = 0; + control_transfer->ux_transfer_request_data_pointer = dfu_host_buffer; + control_transfer->ux_transfer_request_requested_length = len; + control_transfer->ux_transfer_request_value = block; + return ux_host_stack_transfer_request(control_transfer); +} +static UINT _req_DFU_UPLOAD(UX_TRANSFER *control_transfer, ULONG block, ULONG len) +{ + _req_DFU_LOCK(control_transfer); + control_transfer->ux_transfer_request_type = 0xA1; + control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_UPLOAD; + control_transfer->ux_transfer_request_index = 0; + control_transfer->ux_transfer_request_data_pointer = dfu_host_buffer; + control_transfer->ux_transfer_request_requested_length = len; + control_transfer->ux_transfer_request_value = block; + return ux_host_stack_transfer_request(control_transfer); +} +static UINT _req_DFU_CLRSTATUS(UX_TRANSFER *control_transfer) +{ + _req_DFU_LOCK(control_transfer); + control_transfer->ux_transfer_request_type = 0x21; + control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_CLEAR_STATUS; + control_transfer->ux_transfer_request_index = 0; + control_transfer->ux_transfer_request_data_pointer = UX_NULL; + control_transfer->ux_transfer_request_requested_length = 0; + control_transfer->ux_transfer_request_value = 0; + return ux_host_stack_transfer_request(control_transfer); +} + + +static void tx_test_thread_host_simulation_entry(ULONG arg) +{ +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *control_transfer; +ULONG len, trans_len, block; +INT i; +UINT status; + + stepinfo("\n"); + + stepinfo(">>>>>>>>>>>> Test DFU connect\n"); + status = ux_test_wait_for_non_null((VOID **)&device); + UX_TEST_ASSERT(status == UX_SUCCESS); + if (device -> ux_device_state == UX_DEVICE_CONFIGURED) + { + printf("ERROR #%d, device state 0x%lx\n", __LINE__, device->ux_device_state); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Test DFU set configure\n"); + status = ux_host_stack_device_configuration_select(device->ux_device_first_configuration); + UX_TEST_ASSERT(status == UX_SUCCESS); + + /* Get endpoint and transfer request. */ + control_endpoint = &device->ux_device_control_endpoint; + control_transfer = &control_endpoint->ux_endpoint_transfer_request; + + stepinfo(">>>>>>>>>>>> Test DFU_GETSTATE\n"); + status = _req_DFU_GETSTATE(control_transfer); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: transfer status 0x%x\n", __LINE__, status); + test_control_return(1); + } + UX_TEST_ASSERT(dfu_host_buffer[0] == UX_SYSTEM_DFU_STATE_APP_IDLE); + + stepinfo(">>>>>>>>>>>> Test DFU DETACH\n"); + + /* Uses DFU framework after USB reset (re-connect). */ + ux_test_dcd_sim_slave_connect_framework(device_framework_dfu, DEVICE_FRAMEWORK_LENGTH_DFU); + status = _req_DFU_DETACH(control_transfer); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: transfer status 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = ux_test_wait_for_null((VOID **)&device); + UX_TEST_ASSERT(status == UX_SUCCESS); + status = ux_test_wait_for_non_null((VOID **)&device); + UX_TEST_ASSERT(status == UX_SUCCESS); + status = ux_host_stack_device_configuration_select(device->ux_device_first_configuration); + UX_TEST_ASSERT(status == UX_SUCCESS); + + status = _req_DFU_GETSTATE(control_transfer); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: transfer status 0x%x\n", __LINE__, status); + test_control_return(1); + } + UX_TEST_ASSERT(dfu_host_buffer[0] == UX_SYSTEM_DFU_STATE_DFU_IDLE); + +#if !defined(UX_DEVICE_CLASS_DFU_UPLOAD_DISABLE) + + stepinfo(">>>>>>>>>>>> Test DFU UPLOAD FAIL\n"); + status = _req_DFU_UPLOAD(control_transfer, 0, UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH + 1); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: UPLOAD should STALL\n", __LINE__); + test_control_return(1); + } + status = _req_DFU_CLRSTATUS(control_transfer); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: CLRSTATUS error 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Test DFU UPLOAD fail @ UPLOAD_IDLE\n"); + trans_len = UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH; block = 0; + for (i = 0; i < trans_len; i ++) + { + dfu_device_buffer[i] = (UCHAR)(block + i); + dfu_host_buffer[i] = 0xFF; + } + dfu_actual_length = trans_len; + status = _req_DFU_UPLOAD(control_transfer, block, trans_len); + if (status != UX_SUCCESS) + { + printf("ERROR #%d(%ld, %ld): UPLOAD status 0x%x\n", __LINE__, block, trans_len, status); + test_control_return(1); + } + UX_TEST_ASSERT(dfu_transfer_length == trans_len); + UX_TEST_ASSERT(dfu_block == block); + if (ux_utility_memory_compare(dfu_host_buffer, dfu_device_buffer, trans_len) != UX_SUCCESS) + { + printf("ERROR #%d(%ld, %ld): data error\n", __LINE__, block, trans_len); + printf(" device buffer %p: %2x %2x ...\n", dfu_device_buffer, dfu_device_buffer[0], dfu_device_buffer[1]); + printf(" host buffer %p: %2x %2x ...\n", dfu_host_buffer, dfu_host_buffer[0], dfu_host_buffer[1]); + test_control_return(1); + } + /* Test upload faile. */ + status = _req_DFU_UPLOAD(control_transfer, 0, UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH + 1); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: UPLOAD should STALL\n", __LINE__); + test_control_return(1); + } + status = _req_DFU_CLRSTATUS(control_transfer); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: CLRSTATUS error 0x%x\n", __LINE__, status); + test_control_return(1); + } + /* Check state. */ + status = _req_DFU_GETSTATE(control_transfer); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: transfer status 0x%x\n", __LINE__, status); + test_control_return(1); + } + UX_TEST_ASSERT(dfu_host_buffer[0] == UX_SYSTEM_DFU_STATE_DFU_IDLE); +#endif + + stepinfo(">>>>>>>>>>>> All Done\n"); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* 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 void tx_test_thread_slave_simulation_entry(ULONG arg) +{ + while(1) + { + +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); + tx_thread_relinquish(); +#else + + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); +#endif + } +} + +static UINT demo_device_state_change(ULONG event) +{ + return(UX_SUCCESS); +} + +static VOID demo_thread_dfu_activate(VOID *dfu) +{ +} + +static VOID demo_thread_dfu_deactivate(VOID *dfu) +{ +} + +static UINT demo_thread_dfu_read(VOID *dfu, ULONG block_number, UCHAR * data_pointer, ULONG length, ULONG *actual_length) +{ +ULONG return_length; + + stepinfo("dfuRead %ld,%ld: %2x %2x %2x %2x ... -> %p\n", block_number, length, + dfu_device_buffer[0], dfu_device_buffer[1], dfu_device_buffer[2], dfu_device_buffer[3], + data_pointer); + dfu_block = block_number; + dfu_transfer_length = length; + + return_length = UX_MIN(length, sizeof(dfu_device_buffer)); + return_length = UX_MIN(return_length, dfu_actual_length); + + ux_utility_memory_copy(data_pointer, dfu_device_buffer, return_length); + + /* Here is where the data block is read from the firmware. */ + /* Some code needs to be inserted specifically for a target platform. */ + *actual_length = return_length; + return(UX_SUCCESS); +} + +static UINT demo_thread_dfu_write(VOID *dfu, ULONG block_number, UCHAR * data_pointer, ULONG length, ULONG *media_status) +{ + stepinfo("dfuWrite %ld,%ld\n", block_number, length); + dfu_block = block_number; + dfu_transfer_length = length; + ux_utility_memory_copy(dfu_device_buffer, data_pointer, UX_MIN(length, sizeof(dfu_device_buffer))); + + /* Here is where the data block is coming to be written to the firmware. */ + /* Some code needs to be inserted specifically for a target platform. */ + /* Return media status ok. */ + if (length > UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH) + return(UX_ERROR); + *media_status = UX_SLAVE_CLASS_DFU_MEDIA_STATUS_OK ; + return(UX_SUCCESS); +} + +static UINT demo_thread_dfu_get_status(VOID *dfu, ULONG *media_status) +{ + + /* Return media status ok. */ + *media_status = UX_SLAVE_CLASS_DFU_MEDIA_STATUS_OK ; + + return(UX_SUCCESS); +} + +static UINT demo_thread_dfu_notify(VOID *dfu, ULONG notification) +{ + stepinfo("dfuNotify 0x%lx\n", notification); + switch (notification) + { + + + case UX_SLAVE_CLASS_DFU_NOTIFICATION_BEGIN_DOWNLOAD : + + /* Begin of Download. */ + break; + + case UX_SLAVE_CLASS_DFU_NOTIFICATION_END_DOWNLOAD : + + /* Completion of Download. */ + break; + + case UX_SLAVE_CLASS_DFU_NOTIFICATION_ABORT_DOWNLOAD : + + /* Download was aborted. */ + break; + + case UX_SLAVE_CLASS_DFU_NOTIFICATION_BEGIN_UPLOAD : + + /* Begin of UPLOAD. */ + break; + + case UX_SLAVE_CLASS_DFU_NOTIFICATION_END_UPLOAD : + + /* Completion of UPLOAD. */ + break; + + case UX_SLAVE_CLASS_DFU_NOTIFICATION_ABORT_UPLOAD : + + /* Download was aborted. */ + break; + + default : + + /* Bad notification signal. Should never get here. */ + break; + + } + + return(UX_SUCCESS); +} + +static UINT demo_thread_dfu_custom_request(VOID *dfu, UX_SLAVE_TRANSFER *transfer) +{ +UCHAR *setup; +UCHAR *buffer; + + /* Check state and request to insert custom operation, before the standard + handling process. + If no standard handling process is needed, return UX_SUCCESS. + */ + + /* E.g., accept DNLOAD command with wLength 0 in dfuIDLE. */ + if (ux_device_class_dfu_state_get((UX_SLAVE_CLASS_DFU *)dfu) == UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_IDLE) + { + setup = transfer -> ux_slave_transfer_request_setup; + buffer = transfer -> ux_slave_transfer_request_data_pointer; + + if (setup[UX_SETUP_REQUEST] == UX_SLAVE_CLASS_DFU_COMMAND_DOWNLOAD && + setup[UX_SETUP_LENGTH] == 0 && + setup[UX_SETUP_LENGTH + 1] == 0) + { + + /* Accept the case (by default it's stalled). */ + stepinfo("dfuIDLE - accept dfuDNLOAD & wLength 0\n"); + + /* Fill the status data payload. First with status. */ + *buffer = UX_SLAVE_CLASS_DFU_STATUS_OK; + + /* Poll time out value is set to 500ms. */ + *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT) = UX_DW0(500); + *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 1) = UX_DW1(500); + *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 2) = UX_DW2(500); + + /* Next state: still dfuIDLE. */ + *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_STATE) = (UCHAR) UX_SYSTEM_DFU_STATE_DFU_IDLE; + + /* String index set to 0. */ + *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_STRING) = 0; + + /* We have a request to obtain the status of the DFU instance. */ + _ux_device_stack_transfer_request(transfer, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH); + + /* Inform stack it's taken. */ + return(UX_SUCCESS); + } + } + + /* No custom request. */ + return(UX_ERROR); +} diff --git a/test/regression/usbx_msrc_72227_host_pima_read_test.c b/test/regression/usbx_msrc_72227_host_pima_read_test.c new file mode 100644 index 00000000..e4e46161 --- /dev/null +++ b/test/regression/usbx_msrc_72227_host_pima_read_test.c @@ -0,0 +1,3934 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#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_msrc_72227_pima_read_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +ULONG test_n; + + /* Inform user. */ + printf("Running MSRC 72227 PIMA read 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); + } +} + +VOID test_pima_storage_ids_send(UX_SLAVE_CLASS_PIMA *pima, ULONG array_length, ULONG container_length, ULONG trans_length) +{ +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; +UINT status; + // printf("array %ld (%lx), container %ld\n", array_length, array_length, container_length); + if (container_length < (array_length + 1) * 4) + container_length = (array_length + 1) * 4; + /* Fill in the data container type. */ + _ux_utility_short_put(buffer + UX_DEVICE_CLASS_PIMA_DATA_HEADER_TYPE, + UX_DEVICE_CLASS_PIMA_CT_DATA_BLOCK); + /* Fill in the data code. */ + _ux_utility_short_put(buffer + UX_DEVICE_CLASS_PIMA_DATA_HEADER_CODE, + UX_DEVICE_CLASS_PIMA_OC_GET_STORAGE_IDS); + /* Fill in the Transaction ID. */ + _ux_utility_long_put(buffer + UX_DEVICE_CLASS_PIMA_DATA_HEADER_TRANSACTION_ID, + pima -> ux_device_class_pima_transaction_id); + /* Fill array. */ + array = (ULONG*)(buffer + UX_DEVICE_CLASS_PIMA_DATA_HEADER_SIZE); + /* - Length of array. */ + _ux_utility_long_put((UCHAR*)array, array_length); + array ++; + /* - Items in array. */ + array_length = UX_MIN(array_length, (container_length - UX_DEVICE_CLASS_PIMA_DATA_HEADER_LENGTH - 4) / 4); + for (i = 0; i < array_length; i ++) + array[i] = i; + /* Fill in the size of the response header. */ + _ux_utility_long_put(buffer + UX_DEVICE_CLASS_PIMA_DATA_HEADER_LENGTH, + container_length); + status = _ux_device_stack_transfer_request(transfer, trans_length, 0); + status = _ux_device_class_pima_response_send(pima, UX_DEVICE_CLASS_PIMA_RC_OK, 0, 0, 0, 0); +} + +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_ids_n = 0; +static ULONG replace_pima_container_l = UX_DEVICE_CLASS_PIMA_DATA_HEADER_SIZE; +static ULONG replace_pima_transfer_l = UX_DEVICE_CLASS_PIMA_DATA_HEADER_SIZE + 4; + +void replace_pima_cmd_thread_entry(ULONG arg) +{ + while(1) + { + tx_semaphore_get(&replace_pima_cmd_semaphore, TX_WAIT_FOREVER); + test_pima_storage_ids_send(pima_device, replace_pima_ids_n, replace_pima_container_l, replace_pima_transfer_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 } +}; + +static void test_msrc_72227_cases(void) +{ +UINT status; +ULONG actual_length; + + 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); + +/* +The _ux_host_class_pima_read function, called either by the application or +_ux_host_class_pima_command, accepts among others a pointer to a data buffer and +its size. + +``` +UINT _ux_host_class_pima_read(UX_HOST_CLASS_PIMA *pima, UCHAR *data_pointer, +ULONG data_length, +ULONG max_payload_length) +``` + +Initially the function issues a usb transfer request reading +UX_HOST_CLASS_PIMA_CONTAINER_SIZE bytes of data. The response size is validated +to be greater than UX_HOST_CLASS_PIMA_DATA_HEADER_SIZE and if the condition is +matched header_length is retrieved from the response with offset +UX_HOST_CLASS_PIMA_DATA_HEADER_LENGTH. +This value decreased by UX_HOST_CLASS_PIMA_DATA_HEADER_SIZE needs to fit the +supplied buffer (comparison against data_length). + +``` +if (transfer_request -> ux_transfer_request_actual_length <= UX_HOST_CLASS_PIMA_DATA_HEADER_SIZE) +return(UX_CLASS_MALFORMED_PACKET_RECEIVED_ERROR); +header_length = _ux_utility_long_get(ptp_payload + UX_HOST_CLASS_PIMA_DATA_HEADER_LENGTH); +... +... +if ((header_length - UX_HOST_CLASS_PIMA_DATA_HEADER_SIZE)> data_length) +return(UX_ERROR); +``` + +Now the execution flow reaches the critical part - data_length is adjusted to +support a case when the first packet contains data. + +``` +data_length = header_length - transfer_request -> ux_transfer_request_actual_length; +``` + +Since data_length is a ULONG in case header_length is smaller than +ux_transfer_request_actual_length the above subtraction will result in an +integer underflow. +In example when header_length is 0x0C (or UX_HOST_CLASS_PIMA_DATA_HEADER_SIZE) +and actual number of transferred bytes is 0x0E +(UX_HOST_CLASS_PIMA_DATA_HEADER_SIZE + 2) the data_length will be 4294967294. + +Next the two bytes of payload will be copied to the data buffer. After this step +data will be read from the target device in a while loop as long as data_length +is positive in batches of max_payload_length bytes +(as long as data_length > max_payload_length). In each iteration the data is +retrieved and stored in the location pointed by data_pointer which is +successively updated. Finally one may break the loop by providing a response +with size less than payload_length. + +``` +while(data_length) +{ +if (data_length > max_payload_length) +payload_length = max_payload_length; +else +payload_length = data_length; + +transfer_request -> ux_transfer_request_data_pointer = data_pointer; +transfer_request -> ux_transfer_request_requested_length = payload_length; + +status = ux_host_stack_transfer_request(transfer_request); + +if (status == UX_SUCCESS) +{ + +status = _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, UX_MS_TO_TICK(UX_HOST_CLASS_PIMA_CLASS_TRANSFER_TIMEOUT)); + +if (status != UX_SUCCESS) +{ +... +} +} +else +{ +return(status); +} + +if (payload_length != transfer_request -> ux_transfer_request_actual_length) +return(UX_TRANSFER_ERROR); + +data_length -= payload_length; +data_pointer += payload_length; + +} +``` + +*Impact* + +Processing of a maliciously crafted pima read request response will result in an +integer underflow followed by a buffer overflow. The attacker will have full +control over the contents of the overflowed buffer. This issue may potentially +allow one to execute arbitrary code on the pima host device. + +*Reproduction steps* + +- Connect a malicious pima device to the host +- In response to a pima read request from the host provide a response of i.e., 0x0E bytes with a header_length set to 0x0C +- Observer an integer underflow of data_length +- Provide payload according to needs +*/ + + /* Hook requests to replace answers. */ + 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); + + /* Container length overflow! */ + replace_pima_ids_n = 1; + replace_pima_container_l = UX_DEVICE_CLASS_PIMA_DATA_HEADER_SIZE + 2; + replace_pima_transfer_l = UX_DEVICE_CLASS_PIMA_DATA_HEADER_SIZE + 4; + ux_test_hcd_sim_host_set_actions(replace_bulk_out_transfer); + + status = ux_host_class_pima_storage_ids_get(pima_host, &pima_host_session, host_buffer32, 32); + UX_TEST_CHECK_CODE(UX_CLASS_MALFORMED_PACKET_RECEIVED_ERROR, 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_msrc_72227_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_msrc_72427_ecm_host_mac_test.c b/test/regression/usbx_msrc_72427_ecm_host_mac_test.c new file mode 100644 index 00000000..8248d133 --- /dev/null +++ b/test/regression/usbx_msrc_72427_ecm_host_mac_test.c @@ -0,0 +1,77 @@ +/* This tests the case where the mac address string is too long. This is an + error. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static unsigned char invalid_mac_address_string_length[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL CDCECM Device" */ + 0x09, 0x04, 0x02, 0x10, + 0x45, 0x4c, 0x20, 0x43, 0x44, 0x43, 0x45, 0x43, + 0x4d, 0x20, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31, + + /* MAC Address string descriptor : Index 4 - "001E5841B878" */ + 0x09, 0x04, 0x04, + 0x1, /* This byte is the length of the string. It just needs to be small (look in mac_address_get.c). */ + 0x30, 0x30, + +}; + +static DEVICE_INIT_DATA device_init_data = { + .string_framework = invalid_mac_address_string_length, + .string_framework_length = sizeof(invalid_mac_address_string_length), + .dont_register_hcd = 1, +}; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_msrc_72427_ecm_mac_address_invalid_length_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running MSRC 72427 : CDC-ECM Mac Address Invalid Length Test ....... "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize_use_framework(first_unused_memory, &device_init_data); +} + +static void post_init_host() +{ + +int i; + + /* We expect this to fail multiple times since enumeration tries multiple times. */ + for (i = 0; i < UX_RH_ENUMERATION_RETRY; i++) + { + + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED)); + } + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE)); + + /* Enumerate. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + + /* The HCD init function put()s the HCD semaphore, so we can do this here. */ + ux_test_wait_for_enum_thread_completion(); + + /* Enumeration should've failed. */ + UX_TEST_ASSERT(ux_test_check_actions_empty()); + UX_TEST_ASSERT(cdc_ecm_host_from_system_change_function == UX_NULL); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_msrc_72525_host_pima_obj_handles_get_test.c b/test/regression/usbx_msrc_72525_host_pima_obj_handles_get_test.c new file mode 100644 index 00000000..36279dd6 --- /dev/null +++ b/test/regression/usbx_msrc_72525_host_pima_obj_handles_get_test.c @@ -0,0 +1,3888 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#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_msrc_72525_pima_obj_handles_get_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +ULONG test_n; + + /* Inform user. */ + printf("Running MSRC 72525 PIMA obj handles get 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); + } +} + +VOID test_pima_object_handles_send(UX_SLAVE_CLASS_PIMA *pima, ULONG array_length, ULONG container_length) +{ +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; +UINT status; + // printf("array %ld (%lx), container %ld\n", array_length, array_length, container_length); + if (container_length < (array_length + 1) * 4) + container_length = (array_length + 1) * 4; + /* Fill in the data container type. */ + _ux_utility_short_put(buffer + UX_DEVICE_CLASS_PIMA_DATA_HEADER_TYPE, + UX_DEVICE_CLASS_PIMA_CT_DATA_BLOCK); + /* Fill in the data code. */ + _ux_utility_short_put(buffer + UX_DEVICE_CLASS_PIMA_DATA_HEADER_CODE, + UX_DEVICE_CLASS_PIMA_OC_GET_OBJECT_HANDLES); + /* Fill in the Transaction ID. */ + _ux_utility_long_put(buffer + UX_DEVICE_CLASS_PIMA_DATA_HEADER_TRANSACTION_ID, + pima -> ux_device_class_pima_transaction_id); + /* Fill array. */ + array = (ULONG*)(buffer + UX_DEVICE_CLASS_PIMA_DATA_HEADER_SIZE); + /* - Length of array. */ + _ux_utility_long_put((UCHAR*)array, array_length); + array ++; + /* - Items in array. */ + array_length = UX_MIN(array_length, (container_length - UX_DEVICE_CLASS_PIMA_DATA_HEADER_LENGTH - 4) / 4); + for (i = 0; i < array_length; i ++) + array[i] = i; + /* Fill in the size of the response header. */ + _ux_utility_long_put(buffer + UX_DEVICE_CLASS_PIMA_DATA_HEADER_LENGTH, + container_length); + status = _ux_device_stack_transfer_request(transfer, container_length, 0); + status = _ux_device_class_pima_response_send(pima, UX_DEVICE_CLASS_PIMA_RC_OK, 0, 0, 0, 0); +} + +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; + +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(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 } +}; + +static void test_msrc_72525_cases(void) +{ +UINT status; +ULONG actual_length; + + 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); + + /* nb_objects check overflow! */ + pima_host_session.ux_host_class_pima_session_nb_objects = 0x40000001; /* Overflow if * 4 (=4). */ + status = ux_host_class_pima_object_handles_get(pima_host, &pima_host_session, host_buffer32, 64, 0, UX_HOST_CLASS_PIMA_OFC_UNDEFINED, 0); + UX_TEST_CHECK_NOT_SUCCESS(status); + + 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); + +/* +The _ux_host_class_pima_object_handles_get function does not process the +response retrieved from a pima device in a secure manner. The number of returned +object handles may be maliciously crafted to bypass validation against available +buffer size by triggering an integer overflow in multiplication of number of +object handles and size of ULONG type. + +A large number of object handles, stored in the nb_object_handles variable, will +result in a buffer overflow in the for loop responsible for unpacking of object +handles. + +``` +if (status == UX_SUCCESS) +{ + nb_object_handles = _ux_utility_long_get(object_handles_array_raw); + pima_session -> ux_host_class_pima_session_nb_objects = nb_object_handles; + if ((nb_object_handles * sizeof(ULONG)) > object_handles_length) + return(UX_MEMORY_INSUFFICIENT); + + for(count_object_handles = 0; count_object_handles < nb_object_handles; count_object_handles++) + + *(object_handles_array + count_object_handles) = _ux_utility_long_get(object_handles_array_raw + sizeof(ULONG) + + (count_object_handles * sizeof(ULONG))); +} +``` + +For example if the application calls _ux_host_class_pima_object_handles_get to +retrieve handles for two objects to the object_handles_array array with +object_handles_length set to 8 bytes, setting nb_object_handles to 1073741825 +will bypass the memory check and overflow the target array. + +*Impact* + +Processing of a maliciously crafted UX_HOST_CLASS_PIMA_OC_GET_OBJECT_HANDLES +request response will result in integer and buffer overflows. The attacker may +exploit this issue to cause denial of service by crashing the pima host. +Depending on end application it may also be possible to achieve execution of +arbitrary code i.e., by providing the payload in a larger usb transfer prior to +retrieval of PIMA object handles reusing the memory region for buffer allocation. + +*Reproduction steps* + +- Connect a malicious pima device to the host +- Provide a crafted response to the UX_HOST_CLASS_PIMA_OC_GET_OBJECT_HANDLES request triggering an integer overflow during multiplication nb_object_handles and sizeof(ULONG) +- Observe that (nb_object_handles * sizeof(ULONG)) > object_handles_length) condition may be bypassed by exploiting the integer overflow +- Observe further overflow of the object_handles_array array in the for loop responsible for unpacking of object handles + +*/ + + /* Hook requests to replace answers. */ + 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); + + /* Device reported array size (nb_object_handles * sizeof(ULONG)) overflow! */ + replace_pima_obj_n = 0x40000001; /* Overflow if * 4 (=4). */ + replace_pima_container_l = UX_DEVICE_CLASS_PIMA_DATA_HEADER_SIZE + 4; + ux_test_hcd_sim_host_set_actions(replace_bulk_out_transfer); + + status = ux_host_class_pima_object_handles_get(pima_host, &pima_host_session, host_buffer32, 64, 0, UX_HOST_CLASS_PIMA_OFC_UNDEFINED, 0); + UX_TEST_CHECK_NOT_SUCCESS(status); + + /* Restore hooks. */ + + 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_msrc_72525_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_msrc_72526_pictbridge_dps_host_start_test.c b/test/regression/usbx_msrc_72526_pictbridge_dps_host_start_test.c new file mode 100644 index 00000000..9cb30dc9 --- /dev/null +++ b/test/regression/usbx_msrc_72526_pictbridge_dps_host_start_test.c @@ -0,0 +1,895 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#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_pictbridge.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" + +#include "ux_test_jpeg_image.h" + +/* Define constants. */ +#define UX_TEST_STACK_SIZE (2*1024) +#define UX_TEST_MEMORY_SIZE (512*1024) + +/* Define local/extern function prototypes. */ + +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_pima_instance_activate(VOID *pima_instance); +static VOID test_pima_instance_deactivate(VOID *pima_instance); + + +/* 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_PICTBRIDGE pictbridge_device; +static UX_PICTBRIDGE_PRINTINFO printinfo; +static UX_PICTBRIDGE_JOBINFO *jobinfo; +static UX_SLAVE_CLASS_PIMA_OBJECT *object; +static TX_SEMAPHORE print_semaphore; +static ULONG pictbridge_device_copy_count = 0; + +static UX_HOST_CLASS_PIMA *pima_host; +static UX_PICTBRIDGE pictbridge_host; +static ULONG pictbridge_host_copy_count = 0; +static TX_SEMAPHORE wait_semaphore; + +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; + +/* 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, + +}; +#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) + +/* Pima device info manufacture string (Unicode). */ +UCHAR string_pima_manufacturer[] = +{ + 0x0C, + 0x45, 0x00, 0x78, 0x00, 0x70, 0x00, 0x72, 0x00, + 0x65, 0x00, 0x73, 0x00, 0x20, 0x00, 0x4c, 0x00, + 0x6f, 0x00, 0x67, 0x00, 0x69, 0x00, 0x63, 0x00 +}; + +/* Pima device info Model string (Unicode). */ +UCHAR string_pima_model[] = +{ + 0x0C, + 0x50, 0x00, 0x69, 0x00, 0x6D, 0x00, 0x61, 0x00, + 0x20, 0x00, 0x43, 0x00, 0x61, 0x00, 0x6D, 0x00, + 0x65, 0x00, 0x72, 0x00, 0x61, 0x00, 0x20, 0x00 +}; + +/* Pima device info Device version (Unicode). */ +UCHAR string_pima_device_version[] = +{ + 0x04, + 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x31, 0x00 +}; + +/* Pima device info Device serial number (Unicode). */ +UCHAR string_pima_serial_number[] = +{ + 0x04, + 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00 +}; + +UCHAR string_pima_storage_description[] = +{ + 0x0b, + 0x56, 0x00, 0x69, 0x00, 0x72, 0x00, 0x74, 0x00, + 0x75, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x20, 0x00, + 0x44, 0x00, 0x69, 0x00, 0x73, 0x00, 0x6b, 0x00 +}; + +UCHAR string_pima_storage_volume_label[] = +{ + 0x09, + 0x4d, 0x00, 0x79, 0x00, 0x20, 0x00, 0x56, 0x00, + 0x6f, 0x00, 0x6c, 0x00, 0x75, 0x00, 0x6d, 0x00, + 0x65, 0x00 +}; + +/* 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_pictbridge_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +ULONG test_n; + + /* Inform user. */ + printf("Running Pictbridge Basic Functionality 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(); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Register PIMA class. */ + status = ux_host_stack_class_register(_ux_system_host_class_pima_name, ux_host_class_pima_entry); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Initialize the Pictbridge string components. */ + ux_utility_memory_copy(pictbridge_device.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_vendor_name, "ExpressLogic",13); + ux_utility_memory_copy(pictbridge_device.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_product_name, "EL_Pictbridge_Camera",21); + ux_utility_memory_copy(pictbridge_device.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_serial_no, "ABC_123",7); + ux_utility_memory_copy(pictbridge_device.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dpsversions, "1.0 1.1",7); + pictbridge_device.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_vendor_specific_version = 0x0100; + + pictbridge_device.ux_pictbridge_pima_parameter.ux_device_class_pima_instance_activate = test_pima_instance_activate; + pictbridge_device.ux_pictbridge_pima_parameter.ux_device_class_pima_instance_deactivate = test_pima_instance_deactivate; + + pictbridge_device.ux_pictbridge_pima_parameter.ux_device_class_pima_parameter_device_version = "0.0"; + + /* Start the Pictbridge client. */ + status = ux_pictbridge_dpsclient_start(&pictbridge_device); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Create a semaphore for the demo. */ + status = tx_semaphore_create(&wait_semaphore,"Wait Semaphore", 0); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); +} + +/* Copy the object data. */ +static UINT test_pictbridge_host_object_data_write(UX_PICTBRIDGE *pictbridge,UCHAR *object_buffer, ULONG offset, ULONG total_length, ULONG length) +{ + pictbridge_host_copy_count ++; + + /* We have copied the requested data. Return OK. */ + return(UX_SUCCESS); + +} + +static ULONG ux_test_command_count = 0; +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_cmd_n_obj = 96; + +void replace_pima_cmd_thread_entry(ULONG arg) +{ +UINT status; +ULONG actual_flags; +ULONG temp; + while(1) + { + tx_semaphore_get(&replace_pima_cmd_semaphore, TX_WAIT_FOREVER); + switch(ux_test_command_count) + { + case 4: + /* GetNumObjects. */ + // printf("GetNumObjects\n"); + pima_host -> ux_host_class_pima_bulk_out_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_actual_length = pima_host -> ux_host_class_pima_bulk_out_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_requested_length; + pima_host -> ux_host_class_pima_bulk_out_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_completion_code = UX_SUCCESS; + tx_semaphore_put(&pima_host -> ux_host_class_pima_bulk_out_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_semaphore); + status = _ux_device_class_pima_response_send(pima_device, UX_DEVICE_CLASS_PIMA_RC_OK, 1, replace_pima_cmd_n_obj, 0, 0); + UX_TEST_CHECK_SUCCESS(status); + ux_test_command_count ++; + break; + case 5: + /* GetObjectHandles. */ + // printf("GetNumObjectHandles\n"); + pima_host -> ux_host_class_pima_bulk_out_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_actual_length = pima_host -> ux_host_class_pima_bulk_out_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_requested_length; + pima_host -> ux_host_class_pima_bulk_out_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_completion_code = UX_SUCCESS; + tx_semaphore_put(&pima_host -> ux_host_class_pima_bulk_out_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_semaphore); + status = _ux_device_class_pima_object_handles_send(pima_device, pima_device->ux_device_class_pima_storage_id, UX_PICTBRIDGE_OBJECT_SCRIPT, 0); + UX_TEST_CHECK_SUCCESS(status); + ux_test_command_count ++; + break; + } + } +} +static VOID ux_test_pima_command(UX_TEST_ACTION *action, VOID *params) +{ +UINT status; + // printf("PIMA command #%ld\n", ux_test_command_count); + switch(ux_test_command_count) + { + case 4: + tx_semaphore_put(&replace_pima_cmd_semaphore); + return; + } + ux_test_command_count ++; +} + +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_TRUE}, /* 1. _device_info_get */ +{ 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_TRUE}, /* 2. _session_open */ +{ 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_TRUE}, /* 3. _storage_ids_get */ +{ 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_TRUE}, /* 4. _storage_info_get */ +{ 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}, /* 5. _num_objects_get */ +{ 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_TRUE}, /* 6. _num_objects_get */ +{ 0 } +}; + + +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); + } + + /* Initialize the dpshost structure with the printer vendor info. */ + ux_utility_memory_copy(pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_vendor_name, "ExpressLogic",13); + ux_utility_memory_copy(pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_product_name, "EL_Pictbridge_Printer",21); + ux_utility_memory_copy(pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_serial_no, "ABC_123",7); + + /* Set supported versions. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dpsversions[0] = 0x00010000; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dpsversions[1] = 0x00010001; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dpsversions[2] = 0; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_vendor_specific_version = 0x00010000; + + /* Set print services to TRUE. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_print_service_available = 0x30010000; + + /* Set Qualities. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_qualities[0] = UX_PICTBRIDGE_QUALITIES_DEFAULT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_qualities[1] = UX_PICTBRIDGE_QUALITIES_NORMAL; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_qualities[2] = UX_PICTBRIDGE_QUALITIES_DRAFT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_qualities[3] = UX_PICTBRIDGE_QUALITIES_FINE; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_qualities[4] = 0; + + /* Set Paper Sizes. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_papersizes[0] = UX_PICTBRIDGE_PAPER_SIZES_DEFAULT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_papersizes[1] = UX_PICTBRIDGE_PAPER_SIZES_4IX6I; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_papersizes[2] = UX_PICTBRIDGE_PAPER_SIZES_L; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_papersizes[3] = UX_PICTBRIDGE_PAPER_SIZES_2L; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_papersizes[4] = UX_PICTBRIDGE_PAPER_SIZES_LETTER; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_papersizes[5] = 0; + + /* Set Paper Types. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_papertypes[0] = UX_PICTBRIDGE_PAPER_TYPES_DEFAULT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_papertypes[1] = UX_PICTBRIDGE_PAPER_TYPES_PLAIN; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_papertypes[2] = UX_PICTBRIDGE_PAPER_TYPES_PHOTO; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_papertypes[3] = 0; + + /* Set File Types. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_filetypes[0] = UX_PICTBRIDGE_FILE_TYPES_DEFAULT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_filetypes[1] = UX_PICTBRIDGE_FILE_TYPES_EXIF_JPEG; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_filetypes[2] = UX_PICTBRIDGE_FILE_TYPES_JFIF; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_filetypes[3] = UX_PICTBRIDGE_FILE_TYPES_DPOF; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_filetypes[4] = 0; + + /* Set Date Prints. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dateprints[0] = UX_PICTBRIDGE_DATE_PRINTS_DEFAULT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dateprints[1] = UX_PICTBRIDGE_DATE_PRINTS_OFF; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dateprints[2] = UX_PICTBRIDGE_DATE_PRINTS_ON; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dateprints[3] = 0; + + /* Set File Name Prints. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_filenameprints[0] = UX_PICTBRIDGE_FILE_NAME_PRINTS_DEFAULT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_filenameprints[1] = UX_PICTBRIDGE_FILE_NAME_PRINTS_OFF; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_filenameprints[2] = UX_PICTBRIDGE_FILE_NAME_PRINTS_ON; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_filenameprints[3] = 0; + + /* Set Image optimizes. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_imageoptimizes[0] = UX_PICTBRIDGE_IMAGE_OPTIMIZES_DEFAULT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_imageoptimizes[1] = UX_PICTBRIDGE_IMAGE_OPTIMIZES_OFF; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_imageoptimizes[2] = UX_PICTBRIDGE_IMAGE_OPTIMIZES_ON; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_imageoptimizes[3] = 0; + + /* Set Layouts. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_layouts[0] = UX_PICTBRIDGE_LAYOUTS_DEFAULT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_layouts[1] = UX_PICTBRIDGE_LAYOUTS_1_UP_BORDER; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_layouts[2] = UX_PICTBRIDGE_LAYOUTS_INDEX_PRINT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_layouts[3] = UX_PICTBRIDGE_LAYOUTS_1_UP_BORDERLESS; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_layouts[4] = 0; + + /* Set Fixed Sizes. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_fixedsizes[0] = UX_PICTBRIDGE_FIXED_SIZE_DEFAULT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_fixedsizes[1] = UX_PICTBRIDGE_FIXED_SIZE_35IX5I; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_fixedsizes[2] = UX_PICTBRIDGE_FIXED_SIZE_4IX6I; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_fixedsizes[3] = UX_PICTBRIDGE_FIXED_SIZE_5IX7I; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_fixedsizes[4] = UX_PICTBRIDGE_FIXED_SIZE_7CMX10CM; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_fixedsizes[5] = UX_PICTBRIDGE_FIXED_SIZE_LETTER; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_fixedsizes[6] = UX_PICTBRIDGE_FIXED_SIZE_A4; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_fixedsizes[7] = 0; + + /* Set croppings. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_croppings[0] = UX_PICTBRIDGE_CROPPINGS_DEFAULT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_croppings[1] = UX_PICTBRIDGE_CROPPINGS_OFF; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_croppings[2] = UX_PICTBRIDGE_CROPPINGS_ON; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_croppings[3] = 0; + + /* Set Print Service Status to idle. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dpsprintservicestatus = UX_PICTBRIDGE_DPS_PRINTSERVICE_STATUS_IDLE; + + /* Set Job End Reason. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_jobendreason = UX_PICTBRIDGE_JOB_END_REASON_NOT_ENDED; + + /* Set Error Status. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_errorstatus = UX_PICTBRIDGE_ERROR_STATUS_NO_ERROR; + + /* Set Error Reason. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_errorreason = UX_PICTBRIDGE_ERROR_REASON_NO_REASON; + + /* Set Disconnection Enable. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_disconnectenable = UX_PICTBRIDGE_DISCONNECT_ENABLE_TRUE; + + /* Set Capability Changed. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_capabilitychanged = UX_PICTBRIDGE_CAPABILITY_CHANGED_FALSE; + + /* Set New Job OK. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_newjobok = UX_PICTBRIDGE_NEW_JOB_TRUE; + + /* Set a callback when an object is being received. */ + pictbridge_host.ux_pictbridge_application_object_data_write = test_pictbridge_host_object_data_write; + +/* +During initialization the host pictbridge application queries the device for +number of objects and later retrieves the object handles. One may observe that +the pictbridge -> ux_pictbridge_object_handles_array array is hardcoded to be 64 +elements ULONG large. In case a malicious pima device provides a number of +object larger than 64 a buffer overflow during retrieval of object handles will +occur as the buffer size is set to 4 * ux_host_class_pima_session_nb_objects, +where ux_host_class_pima_session_nb_objects is attacker controlled. + +In example if a malicious device provides object count of 256, +pima_session -> ux_host_class_pima_session_nb_objects will be set to 256 and +256 * 4 bytes of payload will be retrieved from the device and stored in the +64 * 4 byte large pictbridge -> ux_pictbridge_object_handles_array array +resulting in an overflow of 768 bytes. +Since ux_host_class_pima_session_nb_objects is controlled by the attacker the +actual size of the overflow may be quite larger. One may attempt to achieve +execution of arbitrary code e.g., by overwriting one of the void pointers +present in the UX_PICTBRIDGE_STRUCT struct (the +ux_pictbridge_object_handles_array array is a member of this struct). + +``` +status = _ux_host_class_pima_num_objects_get(pima, pima_session, +UX_PICTBRIDGE_ALL_CONTAINERS, UX_PICTBRIDGE_OBJECT_SCRIPT); +if (status != UX_SUCCESS) +{ + _ux_host_class_pima_session_close(pima, pima_session); + return(UX_PICTBRIDGE_ERROR_STORE_NOT_AVAILABLE); +} +status = _ux_host_class_pima_object_handles_get(pima, pima_session, +pictbridge -> ux_pictbridge_object_handles_array, +4 * pima_session -> ux_host_class_pima_session_nb_objects, +UX_PICTBRIDGE_ALL_CONTAINERS, UX_PICTBRIDGE_OBJECT_SCRIPT, 0); +``` + +The implementation does not assure that the number of provided objects can +actually fit the pictbridge -> ux_pictbridge_object_handles_array array. + +*Impact* + +The vulnerability may be exploited to execute arbitrary code or crash the +pictbridge host application. + +*Reproduction steps* + +- Connect a malicious device to the host running pictbridge application +- Provide a response with a number of objects larger than 64 (size of +pictbridge -> ux_pictbridge_object_handles_array) +- Observe a buffer overflow during retrieval of object handles +*/ + + /* Hook requests to replace answers. */ + 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); + replace_pima_cmd_n_obj = 256; + ux_test_hcd_sim_host_set_actions(replace_bulk_out_transfer); + + /* Activate the pictbridge dpshost. */ + status = _ux_pictbridge_dpshost_start(&pictbridge_host, pima_host); + UX_TEST_CHECK_NOT_SUCCESS(status); + + tx_thread_sleep(5); + + 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); + +} + +static UINT test_pictbridge_device_object_data_copy(UX_PICTBRIDGE *pictbridge, ULONG object_handle, UCHAR *object_buffer, ULONG object_offset, ULONG object_length, ULONG *actual_length) +{ + pictbridge_device_copy_count ++; + + /* Copy the demanded object data portion. */ + ux_utility_memory_copy(object_buffer, ux_test_jpeg_image + object_offset, object_length); + + /* Update the actual length. */ + *actual_length = object_length; + + /* We have copied the requested data. Return OK. */ + return(UX_SUCCESS); + +} + + +UINT test_pictbridge_device_event_callback(struct UX_PICTBRIDGE_STRUCT *pictbridge, UINT event_flag) +{ + + /* Check if we received NotifyDeviceStatus event. */ + if (event_flag & UX_PICTBRIDGE_EVENT_FLAG_NOTIFY_DEVICE_STATUS) + { + + /* Check if the printer can accept new job. */ + if (pictbridge -> ux_pictbridge_dpsclient.ux_pictbridge_devinfo_newjobok == UX_PICTBRIDGE_NEW_JOB_TRUE) + { + + /* Let the demo thread to send a new job. */ + tx_semaphore_put(&print_semaphore); + } + } + + return UX_SUCCESS; +} + + +void test_thread_device_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG actual_flags; + + /* Create a semaphore for the demo. */ + status = tx_semaphore_create(&print_semaphore,"Print Semaphore", 0); + UX_TEST_CHECK_SUCCESS(status); + + while(1) + { + + /* We should wait for the host and the client to discover one another. */ + status = ux_utility_event_flags_get(&pictbridge_device.ux_pictbridge_event_flags_group, UX_PICTBRIDGE_EVENT_FLAG_DISCOVERY, + TX_AND_CLEAR, &actual_flags, UX_PICTBRIDGE_EVENT_TIMEOUT); + + /* Check status. */ + if (status == UX_SUCCESS) + { + + /* Check if the pictbridge state machine has changed to discovery complete. */ + if (pictbridge_device.ux_pictbridge_discovery_state == UX_PICTBRIDGE_DPSCLIENT_DISCOVERY_COMPLETE) + { + + /* We can now communicate using XML scripts with the printer. First get information on capabilities. */ + status = ux_pictbridge_dpsclient_api_configure_print_service(&pictbridge_device); + UX_TEST_CHECK_SUCCESS(status); + + /* Check status. */ + if (status == UX_SUCCESS) + { + + /* Get the printer capabilities : Qualities. */ + status = ux_pictbridge_dpsclient_api_capability(&pictbridge_device, UX_PICTBRIDGE_API_QUALITIES, 0); + UX_TEST_CHECK_SUCCESS(status); + + /* Get the printer capabilities : PaperSizes. */ + status = ux_pictbridge_dpsclient_api_capability(&pictbridge_device, UX_PICTBRIDGE_API_PAPER_SIZES, 0); + UX_TEST_CHECK_SUCCESS(status); + + /* Get the printer capabilities : FileTypes. */ + status = ux_pictbridge_dpsclient_api_capability(&pictbridge_device, UX_PICTBRIDGE_API_FILE_TYPES, 0); + UX_TEST_CHECK_SUCCESS(status); + + /* Get the printer capabilities : DatePrints. */ + status = ux_pictbridge_dpsclient_api_capability(&pictbridge_device, UX_PICTBRIDGE_API_DATE_PRINTS, 0); + UX_TEST_CHECK_SUCCESS(status); + + /* Get the printer capabilities : FileNamePrints. */ + status = ux_pictbridge_dpsclient_api_capability(&pictbridge_device, UX_PICTBRIDGE_API_FILE_NAME_PRINTS, 0); + UX_TEST_CHECK_SUCCESS(status); + + /* Get the printer capabilities : ImageOptimizes. */ + status = ux_pictbridge_dpsclient_api_capability(&pictbridge_device, UX_PICTBRIDGE_API_IMAGE_OPTIMIZES, 0); + UX_TEST_CHECK_SUCCESS(status); + + /* Get the printer capabilities : Layouts. */ + status = ux_pictbridge_dpsclient_api_capability(&pictbridge_device, UX_PICTBRIDGE_API_LAYOUTS, 0); + UX_TEST_CHECK_SUCCESS(status); + + /* Get the printer capabilities : FixedSizes. */ + status = ux_pictbridge_dpsclient_api_capability(&pictbridge_device, UX_PICTBRIDGE_API_FIXED_SIZES, 0); + UX_TEST_CHECK_SUCCESS(status); + + /* Get the printer capabilities : Croppings. */ + status = ux_pictbridge_dpsclient_api_capability(&pictbridge_device, UX_PICTBRIDGE_API_CROPPINGS, 0); + UX_TEST_CHECK_SUCCESS(status); + + /* We have all the printer capabilities, get the device status. */ + status = ux_pictbridge_dpsclient_api_device_status(&pictbridge_device); + UX_TEST_CHECK_SUCCESS(status); + + /* Check status. */ + if (status == UX_SUCCESS) + { + + /* Check if the printer is ready for a pring job. */ + if (pictbridge_device.ux_pictbridge_dpsclient.ux_pictbridge_devinfo_newjobok == UX_PICTBRIDGE_NEW_JOB_TRUE) + { + + /* We can start a new job. Fill in the JobConfig and PrintInfo structures. */ + jobinfo = &pictbridge_device.ux_pictbridge_jobinfo; + + /* Attach a printinfo structure to the job. */ + jobinfo -> ux_pictbridge_jobinfo_printinfo_start = &printinfo; + + + /* Set the default values for print job. */ + jobinfo -> ux_pictbridge_jobinfo_quality = UX_PICTBRIDGE_QUALITIES_DEFAULT; + jobinfo -> ux_pictbridge_jobinfo_papersize = UX_PICTBRIDGE_PAPER_SIZES_DEFAULT; + jobinfo -> ux_pictbridge_jobinfo_papertype = UX_PICTBRIDGE_PAPER_TYPES_DEFAULT; + jobinfo -> ux_pictbridge_jobinfo_filetype = UX_PICTBRIDGE_FILE_TYPES_DEFAULT; + jobinfo -> ux_pictbridge_jobinfo_dateprint = UX_PICTBRIDGE_DATE_PRINTS_DEFAULT; + jobinfo -> ux_pictbridge_jobinfo_filenameprint = UX_PICTBRIDGE_FILE_NAME_PRINTS_DEFAULT; + jobinfo -> ux_pictbridge_jobinfo_imageoptimize = UX_PICTBRIDGE_IMAGE_OPTIMIZES_OFF; + jobinfo -> ux_pictbridge_jobinfo_layout = UX_PICTBRIDGE_LAYOUTS_DEFAULT; + jobinfo -> ux_pictbridge_jobinfo_fixedsize = UX_PICTBRIDGE_FIXED_SIZE_DEFAULT; + jobinfo -> ux_pictbridge_jobinfo_cropping = UX_PICTBRIDGE_CROPPINGS_DEFAULT; + + /* Program the callback function for reading the object data. */ + jobinfo -> ux_pictbridge_jobinfo_object_data_read = test_pictbridge_device_object_data_copy; + + /* This is a demo, the fileID is hardwired (1 and 2 for scripts, 3 for photo to be printed. */ + printinfo.ux_pictbridge_printinfo_fileid = UX_PICTBRIDGE_OBJECT_HANDLE_PRINT; + ux_utility_memory_copy(printinfo.ux_pictbridge_printinfo_filename, "Pictbridge demo file", 20); + ux_utility_memory_copy(printinfo.ux_pictbridge_printinfo_date, "01/01/2008", 10); + + /* Fill in the object info to be printed. First get the pointer to the object container in the job info structure. */ + object = (UX_SLAVE_CLASS_PIMA_OBJECT *) jobinfo -> ux_pictbridge_jobinfo_object; + + /* Store the object format : JPEG picture. */ + object -> ux_device_class_pima_object_format = UX_DEVICE_CLASS_PIMA_OFC_EXIF_JPEG; + object -> ux_device_class_pima_object_compressed_size = UX_TEST_JPEG_IMAGE_LENGTH; + object -> ux_device_class_pima_object_offset = 0; + object -> ux_device_class_pima_object_handle_id = UX_PICTBRIDGE_OBJECT_HANDLE_PRINT; + object -> ux_device_class_pima_object_length = UX_TEST_JPEG_IMAGE_LENGTH; + + /* File name is in Unicode. */ + ux_utility_string_to_unicode("JPEG Image", object -> ux_device_class_pima_object_filename); + + /* And start the job. */ + status = ux_pictbridge_dpsclient_api_start_job(&pictbridge_device); + UX_TEST_CHECK_SUCCESS(status); + + /* Register the callback function to receive events from the printer. */ + ux_pictbridge_dpsclient_register_event_callback_function(&pictbridge_device, test_pictbridge_device_event_callback); + + /* Wait for the job to complete. */ + status = tx_semaphore_get(&print_semaphore, 30000); + UX_TEST_CHECK_SUCCESS(status); + + if (status == TX_SUCCESS) + { + + /* Print the job again to demo the use of callback function. */ + status = ux_pictbridge_dpsclient_api_start_job(&pictbridge_device); + UX_TEST_CHECK_SUCCESS(status); + + /* Let host thread run to end. */ + tx_semaphore_put(&wait_semaphore); + } + + /* Unregister the callback function by passing a Null pointer. */ + ux_pictbridge_dpsclient_register_event_callback_function(&pictbridge_device, UX_NULL); + } + } + } + } + } + } +} diff --git a/test/regression/usbx_msrc_72619_host_pima_stor_ids_get_test.c b/test/regression/usbx_msrc_72619_host_pima_stor_ids_get_test.c new file mode 100644 index 00000000..21cb2295 --- /dev/null +++ b/test/regression/usbx_msrc_72619_host_pima_stor_ids_get_test.c @@ -0,0 +1,3866 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#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_msrc_72619_pima_storage_ids_get_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +ULONG test_n; + + /* Inform user. */ + printf("Running MSRC 72619 PIMA storage IDs get 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); + } +} + +VOID test_pima_storage_ids_send(UX_SLAVE_CLASS_PIMA *pima, ULONG array_length, ULONG container_length) +{ +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; +UINT status; + // printf("array %ld (%lx), container %ld\n", array_length, array_length, container_length); + if (container_length < (array_length + 1) * 4) + container_length = (array_length + 1) * 4; + /* Fill in the data container type. */ + _ux_utility_short_put(buffer + UX_DEVICE_CLASS_PIMA_DATA_HEADER_TYPE, + UX_DEVICE_CLASS_PIMA_CT_DATA_BLOCK); + /* Fill in the data code. */ + _ux_utility_short_put(buffer + UX_DEVICE_CLASS_PIMA_DATA_HEADER_CODE, + UX_DEVICE_CLASS_PIMA_OC_GET_STORAGE_IDS); + /* Fill in the Transaction ID. */ + _ux_utility_long_put(buffer + UX_DEVICE_CLASS_PIMA_DATA_HEADER_TRANSACTION_ID, + pima -> ux_device_class_pima_transaction_id); + /* Fill array. */ + array = (ULONG*)(buffer + UX_DEVICE_CLASS_PIMA_DATA_HEADER_SIZE); + /* - Length of array. */ + _ux_utility_long_put((UCHAR*)array, array_length); + array ++; + /* - Items in array. */ + array_length = UX_MIN(array_length, (container_length - UX_DEVICE_CLASS_PIMA_DATA_HEADER_LENGTH - 4) / 4); + for (i = 0; i < array_length; i ++) + array[i] = i; + /* Fill in the size of the response header. */ + _ux_utility_long_put(buffer + UX_DEVICE_CLASS_PIMA_DATA_HEADER_LENGTH, + container_length); + status = _ux_device_stack_transfer_request(transfer, container_length, 0); + status = _ux_device_class_pima_response_send(pima, UX_DEVICE_CLASS_PIMA_RC_OK, 0, 0, 0, 0); +} + +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_ids_n = 0; +static ULONG replace_pima_container_l = UX_DEVICE_CLASS_PIMA_DATA_HEADER_SIZE; + +void replace_pima_cmd_thread_entry(ULONG arg) +{ + while(1) + { + tx_semaphore_get(&replace_pima_cmd_semaphore, TX_WAIT_FOREVER); + test_pima_storage_ids_send(pima_device, replace_pima_ids_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 } +}; + +static void test_msrc_72525_cases(void) +{ +UINT status; +ULONG actual_length; + + 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); + +/* +The _ux_host_class_pima_storage_ids_get function does not process the response +retrieved from a pima device in a secure manner. The number of returned storage +ids may be maliciously crafted to bypass validation against available memory by +triggering an integer overflow in multiplication of number of storage ids and +size of ULONG type. + +A large number of storage ids, stored in the nb_storage_ids variable, will +result in a buffer overflow in the for loop responsible for unpacking of storage +ids. + +``` +nb_storage_ids = _ux_utility_long_get(storage_ids); +if (((nb_storage_ids + 1) * sizeof(ULONG)) > UX_HOST_CLASS_PIMA_STORAGE_IDS_LENGTH) +nb_storage_ids = (UX_HOST_CLASS_PIMA_STORAGE_IDS_LENGTH / sizeof(ULONG)) - 1; +pima_session -> ux_host_class_pima_session_nb_storage_ids = nb_storage_ids; + +if ((nb_storage_ids * sizeof(ULONG)) -> storage_id_length) + return(UX_MEMORY_INSUFFICIENT); + +for(count_storage_ids = 0; count_storage_ids < nb_storage_ids; count_storage_ids++) + *(storage_ids_array + count_storage_ids) = _ux_utility_long_get(storage_ids + sizeof(ULONG) + + (count_storage_ids * sizeof(ULONG))); + +``` + +*Impact* + +Processing of a maliciously crafted UX_HOST_CLASS_PIMA_OC_GET_STORAGE_IDS request response will result in an integer overflow and a consecutive buffer overflow. The attacker may exploit this issue to cause denial of service by crashing the pima host. Depending on end application, if one has control over contents of memory past the storage_ids array it would also be possible to achieve execution of arbitrary code (e.g. by overwriting a function pointer member of the UX_PICTBRIDGE_STRUCT struct). + +*Reproduction steps* + +- Connect a malicious pima device to the host +- Provide a UX_HOST_CLASS_PIMA_OC_GET_STORAGE_IDS response with triggering integer overflow to bypass validation (e.g. number of storage ids set to 1073741825) +- Observe the buffer overflow of the storage_ids_array array in the for loop unpacking storage ids +*/ + + /* Hook requests to replace answers. */ + 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); + + /* Device reported array size ((nb_storage_ids + 1) * sizeof(ULONG)) overflow! */ + replace_pima_ids_n = 0x40000001; /* Overflow if *4 (=4) and (+1)*4 (=8) */ + replace_pima_container_l = UX_DEVICE_CLASS_PIMA_DATA_HEADER_SIZE + 4; + ux_test_hcd_sim_host_set_actions(replace_bulk_out_transfer); + + status = ux_host_class_pima_storage_ids_get(pima_host, &pima_host_session, host_buffer32, 32); + UX_TEST_CHECK_NOT_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_msrc_72525_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_msrc_73386_host_storage_media_open_buffer_test.c b/test/regression/usbx_msrc_73386_host_storage_media_open_buffer_test.c new file mode 100644 index 00000000..4f775464 --- /dev/null +++ b/test/regression/usbx_msrc_73386_host_storage_media_open_buffer_test.c @@ -0,0 +1,586 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SECTOR_SIZE 512 +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_N_LB (UX_RAM_DISK_SIZE / UX_RAM_DISK_SECTOR_SIZE) +#define UX_RAM_DISK_LAST_LBA (UX_RAM_DISK_N_LB - 1) + +#define UX_STORAGE_SECTOR_SIZE 4096 + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[UX_STORAGE_SECTOR_SIZE]; +static CHAR ram_disk_buffer2[UX_STORAGE_SECTOR_SIZE]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static UINT ram_disk_read_status = UX_SUCCESS; +static ULONG ram_disk_read_media_status = 0; +static CHAR ram_disk_read_sent = 0; + +static CHAR ram_disk_flush = 0; +static UINT ram_disk_flush_status = UX_SUCCESS; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; +static UINT error_callback_last_code = UX_SUCCESS; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + error_callback_counter ++; + error_callback_last_code = error_code; + + 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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_msrc_73386_host_storage_media_open_buffer_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running MSRC 73386 Host Storage Media Open Test..................... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, sizeof(ram_disk_buffer1), "RAM DISK1", 2, 512, 0, UX_RAM_DISK_N_LB, UX_RAM_DISK_SECTOR_SIZE, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, sizeof(ram_disk_buffer2), "RAM DISK2", 2, 512, 0, UX_RAM_DISK_N_LB, UX_RAM_DISK_SECTOR_SIZE, 4, 1, 1); + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 2; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = UX_STORAGE_SECTOR_SIZE; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = UX_STORAGE_SECTOR_SIZE; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_parameter); + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + // status = _ux_test_dcd_sim_slave_initialize(); + status = ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + // 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 #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +ULONG rfree, cfree; +FX_MEDIA *media; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done (). */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + /* Media mount should fail. */ + UX_TEST_CHECK_NOT_SUCCESS(status); + /* Last error: memory error. */ + UX_TEST_CHECK_CODE(UX_HOST_CLASS_MEMORY_ERROR, error_callback_last_code); + + /* Wait a while so the thread goes. */ + _ux_utility_delay_ms(10); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + + if (lun > 1) + return UX_ERROR; + + ram_disk_read_sent = UX_TRUE; + + if (ram_disk_read_status != UX_SUCCESS) + { + if (media_status != UX_NULL) + *media_status = ram_disk_read_media_status; + + return ram_disk_read_status; + } + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * UX_STORAGE_SECTOR_SIZE], number_blocks * UX_STORAGE_SECTOR_SIZE); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * UX_STORAGE_SECTOR_SIZE], data_pointer, number_blocks * UX_STORAGE_SECTOR_SIZE); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)number_blocks; + (void)lba; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ram_disk_flush = UX_TRUE; + return ram_disk_flush_status; +} \ No newline at end of file diff --git a/test/regression/usbx_msrc_73492_host_vc_header_parse.c b/test/regression/usbx_msrc_73492_host_vc_header_parse.c new file mode 100644 index 00000000..9fa2d041 --- /dev/null +++ b/test/regression/usbx_msrc_73492_host_vc_header_parse.c @@ -0,0 +1,1086 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_dummy.h" +#include "ux_device_stack.h" +#include "ux_host_class_video.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); + +static VOID ux_test_hcd_entry_should_not_be_called(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_disconnect(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +static VOID ux_test_system_host_enum_hub_function(VOID); + +/* Define global data structures. */ +UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +UX_HOST_CLASS_VIDEO *host_video = UX_NULL; + +ULONG enum_counter; + +ULONG error_counter; + +ULONG set_cfg_counter; + +ULONG rsc_mem_free_on_set_cfg; +ULONG rsc_sem_on_set_cfg; +ULONG rsc_sem_get_on_set_cfg; +ULONG rsc_mutex_on_set_cfg; + +ULONG rsc_enum_sem_usage; +ULONG rsc_enum_sem_get_count; +ULONG rsc_enum_mutex_usage; +ULONG rsc_enum_mem_usage; + +static UX_DEVICE_CLASS_DUMMY *device_dummy[2] = {UX_NULL, UX_NULL}; +static UX_DEVICE_CLASS_DUMMY_PARAMETER device_dummy_parameter; + +/* Define device framework. */ + +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0xEF bDeviceClass: Composite class code + 0x02 bDeviceSubclass: class sub code + 0x00 bDeviceProtocol: Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Configuration 1 descriptor 9 bytes @ 0x12 */ + 0x09, 0x02, + 0xE6, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor @ 0x12+0x09=27 */ + 0x08, 0x0b, 0x00, 0x02, 0x0E, 0x03, 0x00, 0x00, + + /* VideoControl Interface Descriptor Requirement @ 0x12+0x09+8=35 */ + 0x09, 0x04, + 0x00, 0x00, + 0x01, + 0x0E, 0x01, 0x01, + 0x00, + + /* VC_HEADER Descriptor @ 35+9=44 */ + 0x0D, 0x24, 0x01, + 0x50, 0x01, + 0x4D, 0x00, /* wTotalLength: */ + 0x00, 0x00, 0x00, 0x00, + 0x01, /* bInCollection */ + 0x01, /* baInterfaceNr(1) */ + + /* Input Terminal Descriptor (Camera) @ 44+0x0D=57 */ + 0x12, 0x24, 0x02, + 0x02, /* bTerminalID */ + 0x01, 0x02, /* wTerminalType ITT_CAMERA */ + 0x00, + 0x00, + 0x00, 0x00, /* wObjectiveFocalLengthMin */ + 0x00, 0x00, /* wObjectiveFocalLengthMax */ + 0x00, 0x00, /* wOcularFocalLength */ + 0x03, /* bControlSize */ + 0x00, 0x02, 0x00, /* bmControls */ + + /* Input Terminal Descriptor (Media Transport) @ 57+0x12=75 */ + 0x10, 0x24, 0x02, + 0x03, /* bTerminalID */ + 0x02, 0x02, /* wTerminalType ITT_MEDIA_TRANSPORT_INPUT */ + 0x00, + 0x00, + 0x01, /* bControlSize */ + 0x0D, /* bmControls */ + 0x05, /* bTransportModeSize */ + 0xAF, 0xFF, 0xFF, 0x7F, 0x00, /* bmTransportModes */ + + /* Selector Unit Descriptor @ 75+0x10=91 */ + 0x08, 0x24, 0x04, + 0x01, /* bUnitID */ + 0x02, /* bNrInPins */ + 0x02, /* baSourceID(1) */ + 0x03, /* baSourceID(2) */ + 0x00, + + /* Processing Unit Descriptor @ 91+8=99 */ + 13, 0x24, 0x05, + 0x05, /* bUnitID */ + 0x01, /* bSourceID */ + 0x00, 0x00, /* wMaxMultiplier */ + 0x03, /* bControlSize */ + 0x00, 0x00, 0x00, /* bmControls */ + 0x00, + 0x00, /* bmVideoStandards */ + + /* Output Terminal Descriptor @ 99+13=112 */ + 0x09, 0x24, 0x03, + 0x04, /* bTerminalID */ + 0x01, 0x01, /* wTerminalType TT_STREAMING */ + 0x00, + 0x05, /* bSourceID */ + 0x00, + + /* Interrupt Endpoint 0x83 descriptor @ 112+9=121 */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0x0A, + + /* CS_ENDPOINT @ 121+7=128 */ + 0x05, 0x25, 0x03, + 0x20, 0x00, /* wMaxTransferSize */ + + /* VideoStreaming Interface 1.0 @ 128+5=133 */ + 0x09, 0x04, + 0x01, 0x00, + 0x01, + 0x0E, 0x02, 0x00, + 0x00, + + /* VS_INPUT_HEADER @ 133+9=142 */ + 0x0E, 0x24, 0x01, + 0x01, /* bNumFormats */ + 0x4C, 0x00, /* wTotalLength */ + 0x85, /* bEndpointAddress */ + 0x00, + 0x04, /* bTerminalLink */ + 0x03, /* bStillCaptureMethod */ + 0x00, /* bTriggerSupport */ + 0x00, /* bTriggerUsage */ + 0x01, /* bControlSize */ + 0x00, /* bmaControls */ + + /* VS_FORMAT_MJPEG @ 142+0xE=156 */ + 0x0B, 0x24, 0x06, + 0x01, /* bFormatIndex */ + 0x01, /* bNumFrameDescriptors */ + 0x01, /* bmFlags */ + 0x01, /* bDefaultFrameIndex */ + 0x00, 0x00, + 0x02, /* bmInterlaceFlags */ + 0x00, /* bCopyProtect */ + + /* VS_FRAME_MJPEG @ 156+0x0b=167 */ + 0x1E, 0x24, 0x07, + 0x01, /* bFrameIndex */ + 0x02, /* bmCapabilities */ + 0xA0, 0x00, /* wWidth 160 */ + 0x78, 0x00, /* wHeight 120 */ + 0x00, 0x65, 0x04, 0x00, /* dwMinBitRate */ + 0x00, 0xA0, 0x0F, 0x00, /* dwMaxBitRate */ + 0x00, 0x08, 0x00, 0x00, /* dwMaxVideoFrameBufSize */ + 0x2A, 0x2C, 0x0A, 0x00, /* dwDefaultFrameInterval */ + 0x01, /* bFrameIntervalType */ + 0x2A, 0x2C, 0x0A, 0x00, /* dwFrameInterval(1) 666666 */ + + /* VS_STILL_FRAME @ 167+0x1e=197 */ + 0x0F, 0x24, 0x03, + 0x86, /* bEndpointAddress */ + 0x02, /* bNumImageSizePatterns */ + 0x20, 0x03, /* wWidth 800 */ + 0x58, 0x02, /* wHeight 600 */ + 0x20, 0x03, /* wWidth */ + 0x20, 0x03, /* wHeight */ + 0x01, /* bNumCompressionPtr */ + 0x64, /* bCompression 1:100 */ + + /* VS_COLORFORMAT @ 197+0xf=212 */ + 0x06, 0x24, 0x0D, + 0x00, 0x00, 0x00, + + /* Bulk endpoint 0x86 */ + 0x07, 0x05, + 0x86, + 0x02, + 0x40, 0x00, + 0x00, + + /* VideoStreaming Interface 1.1 */ + 0x09, 0x04, + 0x01, 0x01, + 0x02, + 0x0E, 0x02, 0x00, + 0x00, + + /* ISO Endpoint 0x85 */ + 0x07, 0x05, + 0x85, + 0x05, + 0x80, 0x00, /* 128 */ + 0x01, + + /* Bulk Endpoint 0x86 */ + 0x07, 0x05, + 0x86, + 0x02, + 0x40, 0x00, + 0x00, +}; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor 18 bytes + 0xEF bDeviceClass: Composite class code + 0x02 bDeviceSubclass: class sub code + 0x00 bDeviceProtocol: Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Configuration 1 descriptor 9 bytes @ 0x12 */ + 0x09, 0x02, + 0xE6, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor @ 0x12+0x09=27 */ + 0x08, 0x0b, 0x00, 0x02, 0x0E, 0x03, 0x00, 0x00, + + /* VideoControl Interface Descriptor Requirement @ 0x12+0x09+8=35 */ + 0x09, 0x04, + 0x00, 0x00, + 0x01, + 0x0E, 0x01, 0x01, + 0x00, + + /* VC_HEADER Descriptor @ 35+9=44 */ + 0x0D, 0x24, 0x01, + 0x50, 0x01, + 0x4D, 0x00, /* wTotalLength: */ + 0x00, 0x00, 0x00, 0x00, + 0x01, /* bInCollection */ + 0x01, /* baInterfaceNr(1) */ + + /* Input Terminal Descriptor (Camera) @ 44+0x0D=57 */ + 0x12, 0x24, 0x02, + 0x02, /* bTerminalID */ + 0x01, 0x02, /* wTerminalType ITT_CAMERA */ + 0x00, + 0x00, + 0x00, 0x00, /* wObjectiveFocalLengthMin */ + 0x00, 0x00, /* wObjectiveFocalLengthMax */ + 0x00, 0x00, /* wOcularFocalLength */ + 0x03, /* bControlSize */ + 0x00, 0x02, 0x00, /* bmControls */ + + /* Input Terminal Descriptor (Media Transport) @ 57+0x12=75 */ + 0x10, 0x24, 0x02, + 0x03, /* bTerminalID */ + 0x02, 0x02, /* wTerminalType ITT_MEDIA_TRANSPORT_INPUT */ + 0x00, + 0x00, + 0x01, /* bControlSize */ + 0x0D, /* bmControls */ + 0x05, /* bTransportModeSize */ + 0xAF, 0xFF, 0xFF, 0x7F, 0x00, /* bmTransportModes */ + + /* Selector Unit Descriptor @ 75+0x10=91 */ + 0x08, 0x24, 0x04, + 0x01, /* bUnitID */ + 0x02, /* bNrInPins */ + 0x02, /* baSourceID(1) */ + 0x03, /* baSourceID(2) */ + 0x00, + + /* Processing Unit Descriptor @ 91+8=99 */ + 13, 0x24, 0x05, + 0x05, /* bUnitID */ + 0x01, /* bSourceID */ + 0x00, 0x00, /* wMaxMultiplier */ + 0x03, /* bControlSize */ + 0x00, 0x00, 0x00, /* bmControls */ + 0x00, + 0x00, /* bmVideoStandards */ + + /* Output Terminal Descriptor @ 99+13=112 */ + 0x09, 0x24, 0x03, + 0x04, /* bTerminalID */ + 0x01, 0x01, /* wTerminalType TT_STREAMING */ + 0x00, + 0x05, /* bSourceID */ + 0x00, + + /* Interrupt Endpoint 0x83 descriptor @ 112+9=121 */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x08, + 0x01, + + /* CS_ENDPOINT @ 121+7=128 */ + 0x05, 0x25, 0x03, + 0x20, 0x00, /* wMaxTransferSize */ + + /* VideoStreaming Interface 1.0 @ 128+5=133 */ + 0x09, 0x04, + 0x01, 0x00, + 0x01, + 0x0E, 0x02, 0x00, + 0x00, + + /* VS_INPUT_HEADER @ 133+9=142 */ + 0x0E, 0x24, 0x01, + 0x01, /* bNumFormats */ + 0x4C, 0x00, /* wTotalLength */ + 0x85, /* bEndpointAddress */ + 0x00, + 0x04, /* bTerminalLink */ + 0x03, /* bStillCaptureMethod */ + 0x00, /* bTriggerSupport */ + 0x00, /* bTriggerUsage */ + 0x01, /* bControlSize */ + 0x00, /* bmaControls */ + + /* VS_FORMAT_MJPEG @ 142+0xE=156 */ + 0x0B, 0x24, 0x06, + 0x01, /* bFormatIndex */ + 0x01, /* bNumFrameDescriptors */ + 0x01, /* bmFlags */ + 0x01, /* bDefaultFrameIndex */ + 0x00, 0x00, + 0x02, /* bmInterlaceFlags */ + 0x00, /* bCopyProtect */ + + /* VS_FRAME_MJPEG @ 156+0x0b=167 */ + 0x1E, 0x24, 0x07, + 0x01, /* bFrameIndex */ + 0x02, /* bmCapabilities */ + 0xA0, 0x00, /* wWidth 160 */ + 0x78, 0x00, /* wHeight 120 */ + 0x00, 0x65, 0x04, 0x00, /* dwMinBitRate */ + 0x00, 0xA0, 0x0F, 0x00, /* dwMaxBitRate */ + 0x00, 0x08, 0x00, 0x00, /* dwMaxVideoFrameBufSize */ + 0x2A, 0x2C, 0x0A, 0x00, /* dwDefaultFrameInterval */ + 0x01, /* bFrameIntervalType */ + 0x2A, 0x2C, 0x0A, 0x00, /* dwFrameInterval(1) 666666 */ + + /* VS_STILL_FRAME @ 167+0x1e=197 */ + 0x0F, 0x24, 0x03, + 0x86, /* bEndpointAddress */ + 0x02, /* bNumImageSizePatterns */ + 0x20, 0x03, /* wWidth 800 */ + 0x58, 0x02, /* wHeight 600 */ + 0x20, 0x03, /* wWidth */ + 0x20, 0x03, /* wHeight */ + 0x01, /* bNumCompressionPtr */ + 0x64, /* bCompression 1:100 */ + + /* VS_COLORFORMAT @ 197+0xf=212 */ + 0x06, 0x24, 0x0D, + 0x00, 0x00, 0x00, + + /* Bulk endpoint 0x86 */ + 0x07, 0x05, + 0x86, + 0x02, + 0x40, 0x00, + 0x00, + + /* VideoStreaming Interface 1.1 */ + 0x09, 0x04, + 0x01, 0x01, + 0x02, + 0x0E, 0x02, 0x00, + 0x00, + + /* ISO Endpoint 0x85 */ + 0x07, 0x05, + 0x85, + 0x05, + 0x80, 0x08, /* 2 x 128 = 256 */ + 0x01, + + /* Bulk Endpoint 0x86 */ + 0x07, 0x05, + 0x86, + 0x02, + 0x40, 0x00, + 0x00, +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 + }; + +static UX_TEST_SETUP _SetAddress = UX_TEST_SETUP_SetAddress; +static UX_TEST_SETUP _GetDeviceDescriptor = UX_TEST_SETUP_GetDevDescr; +static UX_TEST_SETUP _GetConfigDescriptor = UX_TEST_SETUP_GetCfgDescr; +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +/* Test interactions */ + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION normal_enum_replace[] = { +/* 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, &_GetDeviceDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 0, 8, 0, + UX_SUCCESS, UX_NULL}, +{ UX_HCD_TRANSFER_REQUEST, &_GetDeviceDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 0, 18, 0, + UX_SUCCESS, UX_NULL}, +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 18, UX_CONFIGURATION_DESCRIPTOR_LENGTH, 0, + UX_SUCCESS, UX_NULL}, +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 18, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 18, 0, + UX_SUCCESS, UX_NULL}, +{ 0 } +} +; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT test_slave_change_function(ULONG change) +{ + return 0; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_VIDEO *video_inst = (UX_HOST_CLASS_VIDEO *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + host_video = video_inst; + break; + + case UX_DEVICE_REMOVAL: + host_video = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_dummy_instance_activate(VOID *dummy_instance) +{ + if (device_dummy[0] == UX_NULL) + { + device_dummy[0] = (UX_DEVICE_CLASS_DUMMY *)dummy_instance; + return; + } + if (device_dummy[1] == UX_NULL) + { + device_dummy[1] = (UX_DEVICE_CLASS_DUMMY *)dummy_instance; + return; + } +} +static VOID test_dummy_instance_deactivate(VOID *dummy_instance) +{ + if (device_dummy[0] == dummy_instance) + device_dummy[0] = UX_NULL; + if (device_dummy[1] == dummy_instance) + device_dummy[1] = UX_NULL; +} +static UX_SLAVE_TRANSFER _last_control_transfer; +static UCHAR _last_control_data[64]; +static VOID test_dummy_instance_control_request(UX_DEVICE_CLASS_DUMMY *dummy_instance, + UX_SLAVE_TRANSFER *transfer) +{ +USHORT req_length = _ux_utility_short_get(transfer->ux_slave_transfer_request_setup + 6); +#if 0 + printf("D_Video_Req %x: %x %x, %x %x %x; %d/%d\n", + transfer->ux_slave_transfer_request_phase, + transfer->ux_slave_transfer_request_setup[0], + transfer->ux_slave_transfer_request_setup[1], + _ux_utility_short_get(transfer->ux_slave_transfer_request_setup + 2), + _ux_utility_short_get(transfer->ux_slave_transfer_request_setup + 4), + _ux_utility_short_get(transfer->ux_slave_transfer_request_setup + 6), + transfer->ux_slave_transfer_request_actual_length, + transfer->ux_slave_transfer_request_requested_length); +#endif + _ux_utility_memory_copy(&_last_control_transfer, transfer, sizeof(UX_SLAVE_TRANSFER)); + if (transfer->ux_slave_transfer_request_setup[0] & 0x80) /* GET */ + { + _ux_utility_memory_copy(transfer->ux_slave_transfer_request_data_pointer, + _last_control_data, + req_length); + _ux_device_stack_transfer_request(transfer, req_length, req_length); + } + else /* SET */ + { + _ux_utility_memory_copy(_last_control_data, + transfer->ux_slave_transfer_request_data_pointer, + req_length); + } + // _ux_device_stack_endpoint_stall(transfer->ux_slave_transfer_request_endpoint); +} +static VOID test_dummy_instance_change(UX_DEVICE_CLASS_DUMMY *dummy_instance) +{ +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_enum_sem_get_count = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +static VOID ux_test_system_host_enum_hub_function(VOID) +{ + enum_counter ++; +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_host_class_video_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + printf("Running Host Class Video Basic Functionality Test................... "); +#if !(UX_TEST_MULTI_IFC_ON && UX_TEST_MULTI_ALT_ON) + printf("SKIP!\n"); + test_control_return(0); + return; +#endif + + /* 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(); + + /* 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 #1\n"); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + if (status != UX_SUCCESS) + { + + printf(" ERROR #2\n"); + test_control_return(1); + } + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_video_name, ux_host_class_video_entry); + if (status != UX_SUCCESS) + { + + printf(" ERROR #3\n"); + 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, + test_slave_change_function); + if(status!=UX_SUCCESS) + { + + printf(" ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a dummy device. */ + _ux_utility_memory_set(&device_dummy_parameter, 0, sizeof(device_dummy_parameter)); + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks. + ux_device_class_dummy_instance_activate = test_dummy_instance_activate; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks. + ux_device_class_dummy_instance_deactivate = test_dummy_instance_deactivate; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks. + ux_device_class_dummy_change = test_dummy_instance_change; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks. + ux_device_class_dummy_control_request = test_dummy_instance_control_request; + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, + _ux_device_class_dummy_entry, + 1, 0, &device_dummy_parameter); + status |= ux_device_stack_class_register(_ux_system_slave_class_dpump_name, + _ux_device_class_dummy_entry, + 1, 1, &device_dummy_parameter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if(status != UX_SUCCESS) + { + + printf(" ERROR #7\n"); + test_control_return(1); + } +#endif + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #8\n"); + 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 #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #9\n"); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #10\n"); + test_control_return(1); + } +} + +#define TX_TEST_VIDEO_PARSER_SIZE 32 +typedef struct TX_TEST_VIDEO_PARSER_STRUCT +{ + UCHAR *descriptor_base; + ULONG parsed_interface[TX_TEST_VIDEO_PARSER_SIZE]; + ULONG parsed_entity[TX_TEST_VIDEO_PARSER_SIZE]; + ULONG parsed_count; +} TX_TEST_VIDEO_PARSER; + +static const TX_TEST_VIDEO_PARSER parser_check = +{ + UX_NULL, + {17, 17, 17, 17, 17, 17, 17, 17, + 115, 115, 115, 115, 115}, + {26, 39, 57, 73, 81, 94, 103, 110, + 124, 138, 149, 179, 182}, + 13 +}; + +static UINT tx_test_video_descriptors_parser(VOID *arg, + UCHAR *packed_interface_descriptor, + UCHAR *packed_entity_descriptor) +{ +TX_TEST_VIDEO_PARSER *parser; + + parser = (TX_TEST_VIDEO_PARSER *)arg; + parser->parsed_interface[parser->parsed_count] = packed_interface_descriptor - parser->descriptor_base; + parser->parsed_entity [parser->parsed_count] = packed_entity_descriptor - parser->descriptor_base; + parser->parsed_count ++; +} + + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +ULONG mem_free; +ULONG loop; +TX_TEST_VIDEO_PARSER parser; +ULONG parameter_u32[64/4]; +USHORT *parameter_u16 = (USHORT*)parameter_u32; +UCHAR *parameter_u8 = (UCHAR*)parameter_u32; +UX_ENDPOINT *iso_ep; +UX_ENDPOINT *int_ep; +UX_DEVICE *device; + + + stepinfo("\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Find the video class and wait for the link to be up. */ + for (loop = 0; loop < 100; loop ++) + if (host_video != UX_NULL) + break; + if (host_video == UX_NULL) + { + printf("ERROR #%d: enum fail", __LINE__); + test_control_return(1); + } + if (host_video->ux_host_class_video_feature_unit_id != 5) + { + printf("ERROR #%d: wrong feature bUnitID 0x%lx\n", __LINE__, host_video->ux_host_class_video_feature_unit_id); + test_control_return(1); + } + if (host_video->ux_host_class_video_terminal_id != 2) + { + printf("ERROR #%d: wrong input bTerminalID 0x%lx\n", __LINE__, host_video->ux_host_class_video_terminal_id); + test_control_return(1); + } + if (host_video->ux_host_class_video_number_formats != 1) + { + printf("ERROR #%d: wrong VS_HEADER bNumFormats %ld\n", __LINE__, host_video->ux_host_class_video_number_formats); + test_control_return(1); + } + if (host_video->ux_host_class_video_length_formats != 0x004C) + { + printf("ERROR #%d: wrong VS_HEADER wTotalLength 0x%lx\n", __LINE__, host_video->ux_host_class_video_length_formats); + test_control_return(1); + } + if (host_video->ux_host_class_video_format_address != + (host_video->ux_host_class_video_configuration_descriptor + 124)) + { + printf("ERROR #%d: wrong VS_HEADER addr %p <> %p\n", __LINE__, + host_video->ux_host_class_video_format_address, + (host_video->ux_host_class_video_configuration_descriptor + 124)); + test_control_return(1); + } + int_ep = host_video->ux_host_class_video_device-> + ux_device_current_configuration-> + ux_configuration_first_interface-> + ux_interface_first_endpoint; + if (int_ep->ux_endpoint_transfer_request.ux_transfer_request_packet_length != 8) + { + printf("ERROR #%d: wrong INT max packet length %ld\n", __LINE__, iso_ep->ux_endpoint_transfer_request.ux_transfer_request_packet_length); + test_control_return(1); + } + iso_ep = host_video->ux_host_class_video_device-> + ux_device_current_configuration-> + ux_configuration_first_interface-> + ux_interface_next_interface-> + ux_interface_next_interface->ux_interface_first_endpoint; + if (iso_ep->ux_endpoint_transfer_request.ux_transfer_request_packet_length != 128) + { + printf("ERROR #%d: wrong ISO max packet length %ld\n", __LINE__, iso_ep->ux_endpoint_transfer_request.ux_transfer_request_packet_length); + test_control_return(1); + } + + /* Re-connect with high speed. */ + ux_test_hcd_sim_host_disconnect(); + ux_test_dcd_sim_slave_disconnect(); + + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + /* Find the video class and wait for the link to be up. */ + for (loop = 0; loop < 100; loop ++) + if (host_video != UX_NULL) + break; + if (host_video == UX_NULL) + { + printf("ERROR #%d: enum fail", __LINE__); + test_control_return(1); + } + if (host_video->ux_host_class_video_feature_unit_id != 5) + { + printf("ERROR #%d: wrong feature bUnitID 0x%lx\n", __LINE__, host_video->ux_host_class_video_feature_unit_id); + test_control_return(1); + } + if (host_video->ux_host_class_video_terminal_id != 2) + { + printf("ERROR #%d: wrong input bTerminalID 0x%lx\n", __LINE__, host_video->ux_host_class_video_terminal_id); + test_control_return(1); + } + if (host_video->ux_host_class_video_number_formats != 1) + { + printf("ERROR #%d: wrong VS_HEADER bNumFormats %ld\n", __LINE__, host_video->ux_host_class_video_number_formats); + test_control_return(1); + } + if (host_video->ux_host_class_video_length_formats != 0x004C) + { + printf("ERROR #%d: wrong VS_HEADER wTotalLength 0x%lx\n", __LINE__, host_video->ux_host_class_video_length_formats); + test_control_return(1); + } + if (host_video->ux_host_class_video_format_address != + (host_video->ux_host_class_video_configuration_descriptor + 124)) + { + printf("ERROR #%d: wrong VS_HEADER addr %p <> %p\n", __LINE__, + host_video->ux_host_class_video_format_address, + (host_video->ux_host_class_video_configuration_descriptor + 124)); + test_control_return(1); + } + int_ep = host_video->ux_host_class_video_device-> + ux_device_current_configuration-> + ux_configuration_first_interface-> + ux_interface_first_endpoint; + if (int_ep->ux_endpoint_transfer_request.ux_transfer_request_packet_length != 8*2) + { + printf("ERROR #%d: wrong INT max packet length %ld\n", __LINE__, iso_ep->ux_endpoint_transfer_request.ux_transfer_request_packet_length); + test_control_return(1); + } + iso_ep = host_video->ux_host_class_video_device-> + ux_device_current_configuration-> + ux_configuration_first_interface-> + ux_interface_next_interface-> + ux_interface_next_interface->ux_interface_first_endpoint; + if (iso_ep->ux_endpoint_transfer_request.ux_transfer_request_packet_length != 128*2) + { + printf("ERROR #%d: wrong ISO max packet length %ld\n", __LINE__, iso_ep->ux_endpoint_transfer_request.ux_transfer_request_packet_length); + test_control_return(1); + } + + /* Test entities parse. */ + ux_utility_memory_set(&parser, 0, sizeof(parser)); + parser.descriptor_base = host_video->ux_host_class_video_configuration_descriptor; + status = _ux_host_class_video_entities_parse(host_video, tx_test_video_descriptors_parser, &parser); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: parse error 0x%x\n", __LINE__, status); + test_control_return(1); + } + for(loop = 0; loop < parser.parsed_count; loop++) + { + if (parser.parsed_interface[loop] != parser_check.parsed_interface[loop]) + { + printf("ERROR #%d: wrong interface: %ld <> %ld\n", __LINE__, + parser.parsed_interface[loop], parser_check.parsed_interface[loop]); + test_control_return(1); + } + if (parser.parsed_entity[loop] != parser_check.parsed_entity[loop]) + { + printf("ERROR #%d: wrong entity descriptor: %ld <> %ld\n", __LINE__, + parser.parsed_entity[loop], parser_check.parsed_entity[loop]); + test_control_return(1); + } + } + + /* Test VC_HEADER Descriptor @ device_framework_full_speed[ 35+9=44 ] errors. */ + /* Default: bLength = 0x0D (13), bInCollection = 1, baInterfaceNr[0] = 1. */ + + /* Case 1 : bInCollection @ 11 = 1, baInterfaceNr[0] @ 12 = 5 (interface number not exist). */ + ux_test_hcd_sim_host_disconnect(); + ux_test_dcd_sim_slave_disconnect(); + UX_TEST_ASSERT(host_video == UX_NULL); + device_framework_full_speed[44 + 11] = 1; + device_framework_full_speed[44 + 12] = 5; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + /* Find the video class and wait for the link to be up. */ + for (loop = 0; loop < 100; loop ++) + if (host_video != UX_NULL) + break; + status = ux_host_stack_device_get(0, &device); + UX_TEST_ASSERT(status == UX_SUCCESS && host_video == UX_NULL); + device_framework_full_speed[44 + 11] = 1; + device_framework_full_speed[44 + 12] = 1; + + /* Case 2 : bInCollection @ 11 = 3 (over what in configuration). */ + ux_test_hcd_sim_host_disconnect(); + ux_test_dcd_sim_slave_disconnect(); + UX_TEST_ASSERT(host_video == UX_NULL); + device_framework_full_speed[44 + 11] = 3; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + /* Find the video class and wait for the link to be up. */ + for (loop = 0; loop < 100; loop ++) + if (host_video != UX_NULL) + break; + status = ux_host_stack_device_get(0, &device); + UX_TEST_ASSERT(status == UX_SUCCESS && host_video == UX_NULL); + device_framework_full_speed[44 + 11] = 1; + + /* Case 3 : bLength @ 0 = 12 (VC header descriptor length too small). */ + ux_test_hcd_sim_host_disconnect(); + ux_test_dcd_sim_slave_disconnect(); + UX_TEST_ASSERT(host_video == UX_NULL); + device_framework_full_speed[44 + 0] = 12; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + /* Find the video class and wait for the link to be up. */ + for (loop = 0; loop < 100; loop ++) + if (host_video != UX_NULL) + break; + status = ux_host_stack_device_get(0, &device); + UX_TEST_ASSERT(status == UX_SUCCESS && host_video == UX_NULL); + device_framework_full_speed[44 + 0] = 13; + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + if (host_video != UX_NULL) + { + + printf("ERROR #13: instance not removed when disconnect"); + test_control_return(1); + } + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_dpump_name, _ux_device_class_dummy_entry); + status |= ux_device_stack_class_unregister(_ux_system_slave_class_dpump_name, _ux_device_class_dummy_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); + } +} diff --git a/test/regression/usbx_msrc_73716_cdc_ecm_mac_get_desc_check.c b/test/regression/usbx_msrc_73716_cdc_ecm_mac_get_desc_check.c new file mode 100644 index 00000000..3fe6ce03 --- /dev/null +++ b/test/regression/usbx_msrc_73716_cdc_ecm_mac_get_desc_check.c @@ -0,0 +1,63 @@ +/* Include necessary system files. */ + +#include "usbx_ux_test_cdc_ecm.h" + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_msrc73716_cdc_ecm_mac_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running MSRC 73716 CDC ECM MAC get Test............................. "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static void post_init_host() +{ +UINT status; +UX_DEVICE *device; + + ux_test_ignore_all_errors(); + + /* Modify bLength of CDC Header Functional Descriptor @ 44 (5). */ + ux_test_disconnect_slave_and_host_wait_for_enum_completion(); + status = ux_host_stack_device_get(0, &device); + UX_TEST_ASSERT(status == UX_DEVICE_HANDLE_UNKNOWN); + default_device_framework[44] = 0; + ux_test_connect_slave_and_host_wait_for_enum_completion(); + status = ux_host_stack_device_get(0, &device); + UX_TEST_ASSERT(status == UX_SUCCESS && device -> ux_device_state != UX_DEVICE_CONFIGURED); + default_device_framework[44] = 5; + + /* Modify bLength of CDC Header Functional Descriptor @ 44 (5). */ + ux_test_disconnect_slave_and_host_wait_for_enum_completion(); + status = ux_host_stack_device_get(0, &device); + UX_TEST_ASSERT(status == UX_DEVICE_HANDLE_UNKNOWN); + default_device_framework[44] = 1; + ux_test_connect_slave_and_host_wait_for_enum_completion(); + status = ux_host_stack_device_get(0, &device); + UX_TEST_ASSERT(status == UX_SUCCESS && device -> ux_device_state != UX_DEVICE_CONFIGURED); + default_device_framework[44] = 5; + + /* Modify bLength of CDC Header Functional Descriptor @ 44 (5). */ + ux_test_disconnect_slave_and_host_wait_for_enum_completion(); + status = ux_host_stack_device_get(0, &device); + UX_TEST_ASSERT(status == UX_DEVICE_HANDLE_UNKNOWN); + default_device_framework[44] = sizeof(default_device_framework)+1; + ux_test_connect_slave_and_host_wait_for_enum_completion(); + status = ux_host_stack_device_get(0, &device); + UX_TEST_ASSERT(status == UX_SUCCESS && device -> ux_device_state != UX_DEVICE_CONFIGURED); + default_device_framework[44] = 5; + +} + +static void post_init_device() +{ + +} \ No newline at end of file diff --git a/test/regression/usbx_msrc_80947_device_cdc_ecm_rx_length_less_than_14.c b/test/regression/usbx_msrc_80947_device_cdc_ecm_rx_length_less_than_14.c new file mode 100644 index 00000000..45f33e8f --- /dev/null +++ b/test/regression/usbx_msrc_80947_device_cdc_ecm_rx_length_less_than_14.c @@ -0,0 +1,80 @@ +/* Include necessary system files. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static UCHAR device_is_finished; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_msrc_80947_device_cdc_ecm_rx_length_less_than_14_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running MSRC 80947 - Device CDC ECM RX length less than 14 Test............ "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static void msrc_8947_test(void) +{ +NX_PACKET_POOL *packet_pool; +NX_PACKET *packet; +UINT i; + + packet_pool = cdc_ecm_host->ux_host_class_cdc_ecm_packet_pool; + UX_TEST_ASSERT(packet_pool != UX_NULL); + + /* Simulate a packet with less than 14 bytes data on host side. */ + for (i = 0; i < 100; i ++) + { + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CLASS_MALFORMED_PACKET_RECEIVED_ERROR)); + + UX_TEST_CHECK_SUCCESS(nx_packet_allocate(packet_pool, &packet, 20, UX_MS_TO_TICK(UX_HOST_CLASS_CDC_ECM_PACKET_POOL_WAIT))); + *packet->nx_packet_append_ptr ++= 0; packet->nx_packet_length = 1; + UX_TEST_CHECK_SUCCESS(_ux_host_class_cdc_ecm_write(cdc_ecm_host, packet)); + tx_thread_sleep(1); + } +} + +static void post_init_host() +{ + + /* Test MSRC 8947, packet should be discarded service continue. */ + msrc_8947_test(); + + /* Running TCP test. */ + stepinfo("running TCP test.\n"); + cdc_ecm_basic_test(BASIC_TEST_HOST, BASIC_TEST_TCP); + + /* Running UDP test. */ + stepinfo("running UDP test.\n"); + cdc_ecm_basic_test(BASIC_TEST_HOST, BASIC_TEST_UDP); + + /* Wait for device to finish. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uchar(&device_is_finished, UX_TRUE)); + + /* Disconnect. */ + ux_test_disconnect_slave_and_host_wait_for_enum_completion(); + + /* Connect with null system change function. */ + _ux_system_host->ux_system_host_change_function = UX_NULL; + + /* Connect. */ + ux_test_connect_slave_and_host_wait_for_enum_completion(); + + /* We're done. */ +} + +static void post_init_device() +{ + + cdc_ecm_basic_test(BASIC_TEST_DEVICE, BASIC_TEST_TCP); + cdc_ecm_basic_test(BASIC_TEST_DEVICE, BASIC_TEST_UDP); + + device_is_finished = UX_TRUE; +} \ No newline at end of file diff --git a/test/regression/usbx_msrc_80991_device_rndis_rx_length_less_than_14_test.c b/test/regression/usbx_msrc_80991_device_rndis_rx_length_less_than_14_test.c new file mode 100644 index 00000000..b38eb961 --- /dev/null +++ b/test/regression/usbx_msrc_80991_device_rndis_rx_length_less_than_14_test.c @@ -0,0 +1,688 @@ +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_network_driver.h" +#include "ux_host_class_cdc_ecm.h" +#include "ux_device_class_rndis.h" +#include "ux_device_class_cdc_ecm.h" +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" +#include "ux_test.h" +#include "ux_test_actions.h" +#include "ux_hcd_sim_host.h" +#include "ux_dcd_sim_slave.h" + +#define DEMO_IP_THREAD_STACK_SIZE (8*1024) +#define HOST_IP_ADDRESS IP_ADDRESS(192,168,1,176) +#define HOST_SOCKET_PORT_UDP 45054 +#define DEVICE_IP_ADDRESS IP_ADDRESS(192,168,1,175) +#define DEVICE_SOCKET_PORT_UDP 45055 + +#define PACKET_PAYLOAD 1400 +#define PACKET_POOL_SIZE (PACKET_PAYLOAD*10000) +#define ARP_MEMORY_SIZE 1024 + +/* Define local constants. */ + +#define UX_DEMO_STACK_SIZE (4*1024) +#define UX_USBX_MEMORY_SIZE (128*1024) + +/* Host */ + +static UX_HOST_CLASS *class_driver_host; +static UX_HOST_CLASS_CDC_ECM *cdc_ecm_host; +static UX_HOST_CLASS_CDC_ECM **cdc_ecm_host_ptr; +static TX_THREAD thread_host; +static UCHAR thread_stack_host[UX_DEMO_STACK_SIZE]; +static NX_IP nx_ip_host; +static NX_PACKET_POOL packet_pool_host; +static NX_UDP_SOCKET udp_socket_host; +static CHAR *packet_pool_memory_host; +static CHAR ip_thread_stack_host[DEMO_IP_THREAD_STACK_SIZE]; +static CHAR arp_memory_host[ARP_MEMORY_SIZE]; + +/* Device */ + +static TX_THREAD thread_device; +static UX_HOST_CLASS *class_driver_device; +static UX_SLAVE_CLASS_RNDIS *rndis_device; +static UX_SLAVE_CLASS_RNDIS_PARAMETER rndis_parameter; +static UCHAR thread_stack_device[UX_DEMO_STACK_SIZE]; +static NX_IP nx_ip_device; +static NX_PACKET_POOL packet_pool_device; +static NX_UDP_SOCKET udp_socket_device; +static CHAR *packet_pool_memory_device; +static CHAR ip_thread_stack_device[DEMO_IP_THREAD_STACK_SIZE]; +static CHAR arp_memory_device[ARP_MEMORY_SIZE]; + +static UCHAR global_is_device_initialized; + +static ULONG global_basic_test_num_writes_host; +static ULONG global_basic_test_num_reads_host; + +static ULONG global_basic_test_num_writes_device; +static ULONG global_basic_test_num_reads_device; + +/* Define local prototypes and definitions. */ +static void thread_entry_host(ULONG arg); +static void thread_entry_device(ULONG arg); + +//#define USE_ZERO_ENDPOINT_SETTING + +static unsigned char device_framework_high_speed[] = { + + /* Device Descriptor */ + 0x12, /* bLength */ + 0x01, /* bDescriptorType */ + 0x10, 0x01, /* bcdUSB */ + 0xef, /* bDeviceClass - Depends on bDeviceSubClass */ + 0x02, /* bDeviceSubClass - Depends on bDeviceProtocol */ + 0x01, /* bDeviceProtocol - There's an IAD */ + 0x40, /* bMaxPacketSize0 */ + 0x70, 0x07, /* idVendor */ + 0x42, 0x10, /* idProduct */ + 0x00, 0x01, /* bcdDevice */ + 0x01, /* iManufacturer */ + 0x02, /* iProduct */ + 0x03, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ + + /* Configuration Descriptor */ + 0x09, /* bLength */ + 0x02, /* bDescriptorType */ + +#ifdef USE_ZERO_ENDPOINT_SETTING + 0x58, 0x00, /* wTotalLength */ +#else + 0x4f, 0x00, /* wTotalLength */ +#endif + 0x02, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xc0, /* bmAttributes - Self-powered */ + 0x00, /* bMaxPower */ + + /* Interface Association Descriptor */ + 0x08, /* bLength */ + 0x0b, /* bDescriptorType */ + 0x00, /* bFirstInterface */ + 0x02, /* bInterfaceCount */ + 0x02, /* bFunctionClass - CDC - Communication */ + 0x06, /* bFunctionSubClass - ECM */ + 0x00, /* bFunctionProtocol - No class specific protocol required */ + 0x00, /* iFunction */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x02, /* bInterfaceClass - CDC - Communication */ + 0x06, /* bInterfaceSubClass - ECM */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* CDC Header Functional Descriptor */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x00, /* bDescriptorSubType */ + 0x10, 0x01, /* bcdCDC */ + + /* CDC ECM Functional Descriptor */ + 0x0d, /* bLength */ + 0x24, /* bDescriptorType */ + 0x0f, /* bDescriptorSubType */ + 0x04, /* iMACAddress */ + 0x00, 0x00, 0x00, 0x00, /* bmEthernetStatistics */ + 0xea, 0x05, /* wMaxSegmentSize */ + 0x00, 0x00, /* wNumberMCFilters */ + 0x00, /* bNumberPowerFilters */ + + /* CDC Union Functional Descriptor */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x06, /* bDescriptorSubType */ + 0x00, /* bmMasterInterface */ + 0x01, /* bmSlaveInterface0 */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x83, /* bEndpointAddress */ + 0x03, /* bmAttributes - Interrupt */ + 0x08, 0x00, /* wMaxPacketSize */ + 0x08, /* bInterval */ + +#ifdef USE_ZERO_ENDPOINT_SETTING + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x01, /* bAlternateSetting */ + 0x02, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ +#else + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x02, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ +#endif + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x02, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x81, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + +}; + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL CDCECM Device" */ + 0x09, 0x04, 0x02, 0x10, + 0x45, 0x4c, 0x20, 0x43, 0x44, 0x43, 0x45, 0x43, + 0x4d, 0x20, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31, + + /* MAC Address string descriptor : Index 4 - "001E5841B879" */ + 0x09, 0x04, 0x04, 0x0C, + 0x30, 0x30, 0x31, 0x45, 0x35, 0x38, + 0x34, 0x31, 0x42, 0x38, 0x37, 0x39, + +}; + +static unsigned char *device_framework_full_speed = device_framework_high_speed; +#define FRAMEWORK_LENGTH sizeof(device_framework_high_speed) + + /* 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 + }; + +/* Define local variables. */ + +static UINT class_cdc_ecm_get_host(void) +{ + +UX_HOST_CLASS *class; +UINT status; + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_cdc_ecm_name, &class); + if (status != UX_SUCCESS) + test_control_return(0); + + /* We get the first instance of the storage device */ + do + { + status = ux_host_stack_class_instance_get(class, 0, (void **) &cdc_ecm_host); + tx_thread_sleep(10); + } while (status != UX_SUCCESS); + + /* We still need to wait for the cdc-ecm status to be live */ + while (cdc_ecm_host -> ux_host_class_cdc_ecm_state != UX_HOST_CLASS_INSTANCE_LIVE) + tx_thread_sleep(10); + + return(UX_SUCCESS); +} + +static VOID demo_rndis_instance_activate(VOID *rndis_instance) +{ + + /* Save the CDC instance. */ + rndis_device = (UX_SLAVE_CLASS_RNDIS *) rndis_instance; +} + +static VOID demo_rndis_instance_deactivate(VOID *rndis_instance) +{ + + /* Reset the CDC instance. */ + rndis_device = UX_NULL; +} + +static void read_packet_udp(NX_UDP_SOCKET *udp_socket, ULONG num_reads, CHAR *name) +{ + +NX_PACKET *rcv_packet; +ULONG num_writes_from_peer; + +#ifndef LOCAL_MACHINE + if (num_reads % 100 == 0) +#endif + stepinfo("%s reading packet# %lu\n", name, num_reads); + + UX_TEST_CHECK_SUCCESS(nx_udp_socket_receive(udp_socket, &rcv_packet, NX_WAIT_FOREVER)); + + num_writes_from_peer = *(ULONG *)rcv_packet->nx_packet_prepend_ptr; + if (num_writes_from_peer != num_reads) + test_control_return(0); + + UX_TEST_CHECK_SUCCESS(nx_packet_release(rcv_packet)); +} + +static void write_packet_udp(NX_UDP_SOCKET *udp_socket, NX_PACKET_POOL *packet_pool, ULONG ip_address, ULONG port, ULONG num_writes, CHAR *name) +{ + +NX_PACKET *out_packet; + + UX_TEST_CHECK_SUCCESS(nx_packet_allocate(packet_pool, &out_packet, NX_UDP_PACKET, MS_TO_TICK(1000))); + + *(ULONG *)out_packet->nx_packet_prepend_ptr = num_writes; + out_packet->nx_packet_length = sizeof(ULONG); + out_packet->nx_packet_append_ptr = out_packet->nx_packet_prepend_ptr + out_packet->nx_packet_length; + +#ifndef LOCAL_MACHINE + if (num_writes % 100 == 0) +#endif + stepinfo("%s writing packet# %lu\n", name, num_writes); + + UX_TEST_CHECK_SUCCESS(nx_udp_socket_send(udp_socket, out_packet, ip_address, port)); +} + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_msrc_80991_device_rndis_rx_length_less_than_14_test_application_define(void *first_unused_memory) +#endif +{ + +CHAR *memory_pointer = first_unused_memory; + + /* Inform user. */ + printf("Running MSRC 80991 - Device RNDIS RX length < 14 Test............... "); + + stepinfo("\n"); + + /* Initialize USBX Memory. */ + UX_TEST_CHECK_SUCCESS(ux_system_initialize(memory_pointer, UX_USBX_MEMORY_SIZE, UX_NULL, 0)); + memory_pointer += UX_USBX_MEMORY_SIZE; + + /* It looks weird if this doesn't have a comment! */ + ux_utility_error_callback_register(ux_test_error_callback); + + /* Perform the initialization of the network driver. */ + UX_TEST_CHECK_SUCCESS(ux_network_driver_init()); + + /* Initialize the NetX system. */ + nx_system_initialize(); + + /* Now allocate memory for the packet pools. Note that using the memory passed + to us by ThreadX is mucho bettero than putting it in global memory because + we can reuse the memory for each test. So no more having to worry about + running out of memory! */ + packet_pool_memory_host = memory_pointer; + memory_pointer += PACKET_POOL_SIZE; + packet_pool_memory_device = memory_pointer; + memory_pointer += PACKET_POOL_SIZE; + + /* Create the host thread. */ + UX_TEST_CHECK_SUCCESS(tx_thread_create(&thread_host, "host thread", thread_entry_host, 0, + thread_stack_host, UX_DEMO_STACK_SIZE, + 30, 30, 1, TX_AUTO_START)); + + /* Create the slave thread. */ + UX_TEST_CHECK_SUCCESS(tx_thread_create(&thread_device, "device thread", thread_entry_device, 0, + thread_stack_device, UX_DEMO_STACK_SIZE, + 30, 30, 1, TX_AUTO_START)); +} + +/* Needs to be large enough to hold NetX packet data and RNDIS header. */ +static UCHAR host_bulk_endpoint_transfer_data[16*1024]; + +static UINT my_ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UX_TRANSFER *transfer_request; +UX_ENDPOINT *endpoint; + + + if (function == UX_HCD_TRANSFER_REQUEST) + { + + transfer_request = parameter; + endpoint = transfer_request->ux_transfer_request_endpoint; + + /* Bulk out? */ + if ((endpoint->ux_endpoint_descriptor.bmAttributes == 0x02) && + (endpoint->ux_endpoint_descriptor.bEndpointAddress & 0x80) == 0) + { + + UX_TEST_ASSERT(transfer_request->ux_transfer_request_requested_length + UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH <= sizeof(host_bulk_endpoint_transfer_data)); + + /* Fix it, now! - we need to add the RNDIS header. */ + + /* Copy that packet payload. */ + memcpy(host_bulk_endpoint_transfer_data + UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH, + transfer_request->ux_transfer_request_data_pointer, + transfer_request->ux_transfer_request_requested_length); + + /* Add the RNDIS header to this packet. */ + + _ux_utility_long_put(host_bulk_endpoint_transfer_data + UX_DEVICE_CLASS_RNDIS_PACKET_MESSAGE_TYPE, UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_MSG); + + _ux_utility_long_put(host_bulk_endpoint_transfer_data + UX_DEVICE_CLASS_RNDIS_PACKET_MESSAGE_LENGTH, + transfer_request->ux_transfer_request_requested_length + UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH); + + _ux_utility_long_put(host_bulk_endpoint_transfer_data + UX_DEVICE_CLASS_RNDIS_PACKET_DATA_OFFSET, + UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH - UX_DEVICE_CLASS_RNDIS_PACKET_DATA_OFFSET); + + _ux_utility_long_put(host_bulk_endpoint_transfer_data + UX_DEVICE_CLASS_RNDIS_PACKET_DATA_LENGTH, + transfer_request->ux_transfer_request_requested_length); + + /* The original data pointer points to the packet, so no leak. We also + only allow one transfer at a time, so no worries with overriding data. */ + transfer_request->ux_transfer_request_data_pointer = host_bulk_endpoint_transfer_data; + transfer_request->ux_transfer_request_requested_length += UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH; + } + } + + return _ux_hcd_sim_host_entry(hcd, function, parameter); +} + +static UINT my_ux_dcd_sim_slave_function(UX_SLAVE_DCD *dcd, UINT function, VOID *parameter) +{ + +UX_SLAVE_TRANSFER *transfer_request; +UX_SLAVE_ENDPOINT *endpoint; +UINT netx_packet_length; +UINT i; + + + if (function == UX_HCD_TRANSFER_REQUEST) + { + + transfer_request = parameter; + endpoint = transfer_request->ux_slave_transfer_request_endpoint; + + /* Bulk in? */ + if ((endpoint->ux_slave_endpoint_descriptor.bmAttributes == 0x02) && + (endpoint->ux_slave_endpoint_descriptor.bEndpointAddress & 0x80) != 0) + { + + /* Fix it, now! - we need to remove the RNDIS header. */ + + netx_packet_length = transfer_request->ux_slave_transfer_request_requested_length - UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH; + + /* Just shift the packet over the RNDIS header. */ + for (i = 0; i < netx_packet_length; i++) + { + + transfer_request->ux_slave_transfer_request_data_pointer[i] = transfer_request->ux_slave_transfer_request_data_pointer[i + UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH]; + } + + transfer_request->ux_slave_transfer_request_requested_length = netx_packet_length; + } + } + + return _ux_dcd_sim_slave_function(dcd, function, parameter); +} + +static void msrc_80991_test(void) +{ +NX_PACKET_POOL *packet_pool; +NX_PACKET *packet; +UINT i; + + packet_pool = cdc_ecm_host->ux_host_class_cdc_ecm_packet_pool; + UX_TEST_ASSERT(packet_pool != UX_NULL); + + /* Simulate a packet with less than 14 bytes data on host side. */ + for (i = 0; i < 100; i ++) + { + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CLASS_MALFORMED_PACKET_RECEIVED_ERROR)); + + UX_TEST_CHECK_SUCCESS(nx_packet_allocate(packet_pool, &packet, 20, UX_MS_TO_TICK(UX_HOST_CLASS_CDC_ECM_PACKET_POOL_WAIT))); + *packet->nx_packet_append_ptr ++= 0; packet->nx_packet_length = 1; + UX_TEST_CHECK_SUCCESS(_ux_host_class_cdc_ecm_write(cdc_ecm_host, packet)); + tx_thread_sleep(1); + } +} + +static void thread_entry_host(ULONG input) +{ + +UINT i; +UINT num_iters; + + /* Wait for device to initialize before starting the HCD thread; also, there + seems to be some race condition with simultaneous NetX initialization: + somehow, device was calling the host CDC-ECM write. */ + while (!global_is_device_initialized) + tx_thread_sleep(10); + + /* Wait for device to initialize. */ + while (!global_is_device_initialized) + tx_thread_sleep(10); + + /* Create the IP instance. */ + + UX_TEST_CHECK_SUCCESS(nx_packet_pool_create(&packet_pool_host, "NetX Host Packet Pool", PACKET_PAYLOAD, packet_pool_memory_host, PACKET_POOL_SIZE)); + UX_TEST_CHECK_SUCCESS(nx_ip_create(&nx_ip_host, "NetX Host Thread", HOST_IP_ADDRESS, 0xFF000000UL, + &packet_pool_host, _ux_network_driver_entry, ip_thread_stack_host, DEMO_IP_THREAD_STACK_SIZE, 1)); + + /* Setup ARP. */ + + UX_TEST_CHECK_SUCCESS(nx_arp_enable(&nx_ip_host, (void *)arp_memory_host, ARP_MEMORY_SIZE)); + UX_TEST_CHECK_SUCCESS(nx_arp_static_entry_create(&nx_ip_host, DEVICE_IP_ADDRESS, 0x0000001E, 0x80032CD8)); + + /* Setup UDP. */ + + UX_TEST_CHECK_SUCCESS(nx_udp_enable(&nx_ip_host)); + UX_TEST_CHECK_SUCCESS(nx_udp_socket_create(&nx_ip_host, &udp_socket_host, "USB HOST UDP SOCKET", NX_IP_NORMAL, NX_DONT_FRAGMENT, 20, 20)); + UX_TEST_CHECK_SUCCESS(nx_udp_socket_bind(&udp_socket_host, HOST_SOCKET_PORT_UDP, NX_NO_WAIT)); + + /* The code below is required for installing the host portion of USBX. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_initialize(UX_NULL)); + + /* Register cdc_ecm class. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_class_register(_ux_system_host_class_cdc_ecm_name, ux_host_class_cdc_ecm_entry)); + + ux_test_ignore_all_errors(); + + /* Register all the USB host controllers available in this system. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + + /* Change entry function. */ + _ux_system_host->ux_system_host_hcd_array[0].ux_hcd_entry_function = my_ux_hcd_sim_host_entry; + + /* Find the storage class. */ + class_cdc_ecm_get_host(); + + /* Now wait for the link to be up. */ + while (cdc_ecm_host -> ux_host_class_cdc_ecm_link_state != UX_HOST_CLASS_CDC_ECM_LINK_STATE_UP) + tx_thread_sleep(10); + + /* Test MSRC case. */ + msrc_80991_test(); + + for (num_iters = 0; num_iters < 100; num_iters++) + { + + for (i = 0; i < 10; i++) + write_packet_udp(&udp_socket_host, &packet_pool_host, DEVICE_IP_ADDRESS, DEVICE_SOCKET_PORT_UDP, global_basic_test_num_writes_host++, "host"); + + for (i = 0; i < 10; i++) + read_packet_udp(&udp_socket_host, global_basic_test_num_reads_host++, "host"); + } + + /* Wait for all transfers to complete. */ + while (global_basic_test_num_reads_host != 1000 || global_basic_test_num_reads_device != 1000) + tx_thread_sleep(10); + + /* And finally the usbx system resources. */ + _ux_system_uninitialize(); + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + +static void thread_entry_device(ULONG input) +{ + +UINT i; +UINT status; +UINT num_iters; +UCHAR *notification_buffer; +UX_SLAVE_TRANSFER *interrupt_transfer; + + /* Create the IP instance. */ + + UX_TEST_CHECK_SUCCESS(nx_packet_pool_create(&packet_pool_device, "NetX Device Packet Pool", PACKET_PAYLOAD, packet_pool_memory_device, PACKET_POOL_SIZE)); + + UX_TEST_CHECK_SUCCESS(nx_ip_create(&nx_ip_device, "NetX Device Thread", DEVICE_IP_ADDRESS, 0xFF000000L, &packet_pool_device, + _ux_network_driver_entry, ip_thread_stack_device, DEMO_IP_THREAD_STACK_SIZE, 1)); + + /* Setup ARP. */ + + UX_TEST_CHECK_SUCCESS(nx_arp_enable(&nx_ip_device, (void *)arp_memory_device, ARP_MEMORY_SIZE)); + UX_TEST_CHECK_SUCCESS(nx_arp_static_entry_create(&nx_ip_device, HOST_IP_ADDRESS, 0x0000001E, 0x5841B878)); + + /* Setup UDP. */ + + UX_TEST_CHECK_SUCCESS(nx_udp_enable(&nx_ip_device)); + UX_TEST_CHECK_SUCCESS(nx_udp_socket_create(&nx_ip_device, &udp_socket_device, "USB DEVICE UDP SOCKET", NX_IP_NORMAL, NX_DONT_FRAGMENT, 20, 20)); + UX_TEST_CHECK_SUCCESS(nx_udp_socket_bind(&udp_socket_device, DEVICE_SOCKET_PORT_UDP, NX_NO_WAIT)); + + /* The code below is required for installing the device portion of USBX. */ + status = ux_device_stack_initialize(device_framework_high_speed, FRAMEWORK_LENGTH, + device_framework_full_speed, FRAMEWORK_LENGTH, + string_framework, sizeof(string_framework), + language_id_framework, sizeof(language_id_framework), + UX_NULL); + if (status) + test_control_return(0); + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + rndis_parameter.ux_slave_class_rndis_instance_activate = demo_rndis_instance_activate; + rndis_parameter.ux_slave_class_rndis_instance_deactivate = demo_rndis_instance_deactivate; + + /* Define a local NODE ID. */ + rndis_parameter.ux_slave_class_rndis_parameter_local_node_id[0] = 0x00; + rndis_parameter.ux_slave_class_rndis_parameter_local_node_id[1] = 0x1e; + rndis_parameter.ux_slave_class_rndis_parameter_local_node_id[2] = 0x58; + rndis_parameter.ux_slave_class_rndis_parameter_local_node_id[3] = 0x41; + rndis_parameter.ux_slave_class_rndis_parameter_local_node_id[4] = 0xb8; + rndis_parameter.ux_slave_class_rndis_parameter_local_node_id[5] = 0x78; + + /* Define a remote NODE ID. */ + rndis_parameter.ux_slave_class_rndis_parameter_remote_node_id[0] = 0x00; + rndis_parameter.ux_slave_class_rndis_parameter_remote_node_id[1] = 0x1e; + rndis_parameter.ux_slave_class_rndis_parameter_remote_node_id[2] = 0x58; + rndis_parameter.ux_slave_class_rndis_parameter_remote_node_id[3] = 0x41; + rndis_parameter.ux_slave_class_rndis_parameter_remote_node_id[4] = 0xb8; + rndis_parameter.ux_slave_class_rndis_parameter_remote_node_id[5] = 0x79; + + /* Set extra parameters used by the RNDIS query command with certain OIDs. */ + rndis_parameter.ux_slave_class_rndis_parameter_vendor_id = 0x04b4 ; + rndis_parameter.ux_slave_class_rndis_parameter_driver_version = 0x1127; + ux_utility_memory_copy(rndis_parameter.ux_slave_class_rndis_parameter_vendor_description, "ELOGIC RNDIS", 12); + + /* Initialize the device rndis class. This class owns both interfaces. */ + status = ux_device_stack_class_register(_ux_system_slave_class_rndis_name, ux_device_class_rndis_entry, 1, 0, &rndis_parameter); + if (status) + test_control_return(0); + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + if (status) + test_control_return(0); + + _ux_system_slave->ux_system_slave_dcd.ux_slave_dcd_function = my_ux_dcd_sim_slave_function; + + global_is_device_initialized = UX_TRUE; + + while (!rndis_device) + tx_thread_sleep(10); + + while (rndis_device -> ux_slave_class_rndis_link_state != UX_DEVICE_CLASS_RNDIS_LINK_STATE_UP) + tx_thread_sleep(10); + + /* Since host is CDC-ECM, it's waiting for the LINK_UP notification from the + interrupt endpoint. RNDIS does not send this, so we have to do it manually. */ + { + interrupt_transfer = &rndis_device->ux_slave_class_rndis_interrupt_endpoint->ux_slave_endpoint_transfer_request; + + /* Build the Network Notification response. */ + notification_buffer = interrupt_transfer->ux_slave_transfer_request_data_pointer; + + /* Set the request type. */ + *(notification_buffer + UX_SETUP_REQUEST_TYPE) = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + + /* Set the request itself. */ + *(notification_buffer + UX_SETUP_REQUEST) = 0; + + /* Set the value. It is the network link. */ + _ux_utility_short_put(notification_buffer + UX_SETUP_VALUE, (USHORT)(rndis_device->ux_slave_class_rndis_link_state)); + + /* Set the Index. It is interface. The interface used is the DATA interface. Here we simply take the interface number of the CONTROL and add 1 to it + as it is assumed the classes are contiguous in number. */ + _ux_utility_short_put(notification_buffer + UX_SETUP_INDEX, (USHORT)(rndis_device->ux_slave_class_rndis_interface->ux_slave_interface_descriptor.bInterfaceNumber + 1)); + + /* And the length is zero. */ + *(notification_buffer + UX_SETUP_LENGTH) = 0; + + /* Send the request to the device controller. */ + status = _ux_device_stack_transfer_request(interrupt_transfer, UX_DEVICE_CLASS_CDC_ECM_INTERRUPT_RESPONSE_LENGTH, + UX_DEVICE_CLASS_CDC_ECM_INTERRUPT_RESPONSE_LENGTH); + /* Check error code. */ + if (status != UX_SUCCESS) + test_control_return(0); + } + + for (num_iters = 0; num_iters < 100; num_iters++) + { + + for (i = 0; i < 10; i++) + write_packet_udp(&udp_socket_device, &packet_pool_device, HOST_IP_ADDRESS, HOST_SOCKET_PORT_UDP, global_basic_test_num_writes_device++, "device"); + + for (i = 0; i < 10; i++) + read_packet_udp(&udp_socket_device, global_basic_test_num_reads_device++, "device"); + } +} \ No newline at end of file diff --git a/test/regression/usbx_msrc_81024_host_cdc_ecm_rx_length_less_than_14.c b/test/regression/usbx_msrc_81024_host_cdc_ecm_rx_length_less_than_14.c new file mode 100644 index 00000000..774f4796 --- /dev/null +++ b/test/regression/usbx_msrc_81024_host_cdc_ecm_rx_length_less_than_14.c @@ -0,0 +1,80 @@ +/* Include necessary system files. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static UCHAR device_is_finished; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_msrc_81024_host_cdc_ecm_rx_length_less_than_14_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running MSRC 81024 - Host CDC ECM RX length less than 14 Test....... "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static void msrc_81024_test(void) +{ +NX_PACKET_POOL *packet_pool; +NX_PACKET *packet; +UINT i; + + packet_pool = cdc_ecm_device->ux_slave_class_cdc_ecm_packet_pool; + UX_TEST_ASSERT(packet_pool != UX_NULL); + + /* Simulate a packet with less than 14 bytes data on host side. */ + for (i = 0; i < 100; i ++) + { + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CLASS_MALFORMED_PACKET_RECEIVED_ERROR)); + + UX_TEST_CHECK_SUCCESS(nx_packet_allocate(packet_pool, &packet, 20, UX_MS_TO_TICK(UX_HOST_CLASS_CDC_ECM_PACKET_POOL_WAIT))); + *packet->nx_packet_append_ptr ++= 0; packet->nx_packet_length = 1; + UX_TEST_CHECK_SUCCESS(_ux_device_class_cdc_ecm_write(cdc_ecm_device, packet)); + tx_thread_sleep(1); + } +} + +static void post_init_host() +{ + + /* Running TCP test. */ + stepinfo("running TCP test.\n"); + cdc_ecm_basic_test(BASIC_TEST_HOST, BASIC_TEST_TCP); + + /* Running UDP test. */ + stepinfo("running UDP test.\n"); + cdc_ecm_basic_test(BASIC_TEST_HOST, BASIC_TEST_UDP); + + /* Wait for device to finish. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uchar(&device_is_finished, UX_TRUE)); + + /* Disconnect. */ + ux_test_disconnect_slave_and_host_wait_for_enum_completion(); + + /* Connect with null system change function. */ + _ux_system_host->ux_system_host_change_function = UX_NULL; + + /* Connect. */ + ux_test_connect_slave_and_host_wait_for_enum_completion(); + + /* We're done. */ +} + +static void post_init_device() +{ + + /* Test MSRC 81024, packet should be discarded service continue. */ + msrc_81024_test(); + + cdc_ecm_basic_test(BASIC_TEST_DEVICE, BASIC_TEST_TCP); + cdc_ecm_basic_test(BASIC_TEST_DEVICE, BASIC_TEST_UDP); + + device_is_finished = UX_TRUE; +} \ No newline at end of file diff --git a/test/regression/usbx_msrc_81108_pictbridge_object_parse_test.c b/test/regression/usbx_msrc_81108_pictbridge_object_parse_test.c new file mode 100644 index 00000000..11735096 --- /dev/null +++ b/test/regression/usbx_msrc_81108_pictbridge_object_parse_test.c @@ -0,0 +1,908 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#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_pictbridge.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" + +#include "ux_test_jpeg_image.h" + +/* Define constants. */ +#define UX_TEST_STACK_SIZE (2*1024) +#define UX_TEST_MEMORY_SIZE (512*1024) + +/* Define local/extern function prototypes. */ + +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_pima_instance_activate(VOID *pima_instance); +static VOID test_pima_instance_deactivate(VOID *pima_instance); + + +/* 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_PICTBRIDGE pictbridge_device; +static UX_PICTBRIDGE_PRINTINFO printinfo; +static UX_PICTBRIDGE_JOBINFO *jobinfo; +static UX_SLAVE_CLASS_PIMA_OBJECT *object; +static TX_SEMAPHORE print_semaphore; +static ULONG pictbridge_device_copy_count = 0; + +static UX_HOST_CLASS_PIMA *pima_host; +static UX_PICTBRIDGE pictbridge_host; +static ULONG pictbridge_host_copy_count = 0; +static TX_SEMAPHORE wait_semaphore; + +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; + +/* 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, + +}; +#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) + +/* Pima device info manufacture string (Unicode). */ +UCHAR string_pima_manufacturer[] = +{ + 0x0C, + 0x45, 0x00, 0x78, 0x00, 0x70, 0x00, 0x72, 0x00, + 0x65, 0x00, 0x73, 0x00, 0x20, 0x00, 0x4c, 0x00, + 0x6f, 0x00, 0x67, 0x00, 0x69, 0x00, 0x63, 0x00 +}; + +/* Pima device info Model string (Unicode). */ +UCHAR string_pima_model[] = +{ + 0x0C, + 0x50, 0x00, 0x69, 0x00, 0x6D, 0x00, 0x61, 0x00, + 0x20, 0x00, 0x43, 0x00, 0x61, 0x00, 0x6D, 0x00, + 0x65, 0x00, 0x72, 0x00, 0x61, 0x00, 0x20, 0x00 +}; + +/* Pima device info Device version (Unicode). */ +UCHAR string_pima_device_version[] = +{ + 0x04, + 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x31, 0x00 +}; + +/* Pima device info Device serial number (Unicode). */ +UCHAR string_pima_serial_number[] = +{ + 0x04, + 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00 +}; + +UCHAR string_pima_storage_description[] = +{ + 0x0b, + 0x56, 0x00, 0x69, 0x00, 0x72, 0x00, 0x74, 0x00, + 0x75, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x20, 0x00, + 0x44, 0x00, 0x69, 0x00, 0x73, 0x00, 0x6b, 0x00 +}; + +UCHAR string_pima_storage_volume_label[] = +{ + 0x09, + 0x4d, 0x00, 0x79, 0x00, 0x20, 0x00, 0x56, 0x00, + 0x6f, 0x00, 0x6c, 0x00, 0x75, 0x00, 0x6d, 0x00, + 0x65, 0x00 +}; + +/* 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_msrc_81108_msrc_parse_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +ULONG test_n; + + /* Inform user. */ + printf("Running MSRC 81108 - Pictbridge Object Parse 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(); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Register PIMA class. */ + status = ux_host_stack_class_register(_ux_system_host_class_pima_name, ux_host_class_pima_entry); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Initialize the Pictbridge string components. */ + ux_utility_memory_copy(pictbridge_device.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_vendor_name, "ExpressLogic",13); + ux_utility_memory_copy(pictbridge_device.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_product_name, "EL_Pictbridge_Camera",21); + ux_utility_memory_copy(pictbridge_device.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_serial_no, "ABC_123",7); + ux_utility_memory_copy(pictbridge_device.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dpsversions, "1.0 1.1",7); + pictbridge_device.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_vendor_specific_version = 0x0100; + + pictbridge_device.ux_pictbridge_pima_parameter.ux_device_class_pima_instance_activate = test_pima_instance_activate; + pictbridge_device.ux_pictbridge_pima_parameter.ux_device_class_pima_instance_deactivate = test_pima_instance_deactivate; + + pictbridge_device.ux_pictbridge_pima_parameter.ux_device_class_pima_parameter_device_version = "0.0"; + + /* Start the Pictbridge client. */ + status = ux_pictbridge_dpsclient_start(&pictbridge_device); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Create a semaphore for the demo. */ + status = tx_semaphore_create(&wait_semaphore,"Wait Semaphore", 0); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); +} + +/* Copy the object data. */ +static UINT test_pictbridge_host_object_data_write(UX_PICTBRIDGE *pictbridge,UCHAR *object_buffer, ULONG offset, ULONG total_length, ULONG length) +{ + pictbridge_host_copy_count ++; + + /* We have copied the requested data. Return OK. */ + return(UX_SUCCESS); + +} + +static ULONG ux_test_command_count = 0; +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_cmd_n_obj = 96; + +void replace_pima_cmd_thread_entry(ULONG arg) +{ +UINT status; +ULONG actual_flags; +ULONG temp; + while(1) + { + tx_semaphore_get(&replace_pima_cmd_semaphore, TX_WAIT_FOREVER); + switch(ux_test_command_count) + { + case 4: + /* GetNumObjects. */ + // printf("GetNumObjects\n"); + pima_host -> ux_host_class_pima_bulk_out_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_actual_length = pima_host -> ux_host_class_pima_bulk_out_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_requested_length; + pima_host -> ux_host_class_pima_bulk_out_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_completion_code = UX_SUCCESS; + tx_semaphore_put(&pima_host -> ux_host_class_pima_bulk_out_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_semaphore); + status = _ux_device_class_pima_response_send(pima_device, UX_DEVICE_CLASS_PIMA_RC_OK, 1, replace_pima_cmd_n_obj, 0, 0); + UX_TEST_CHECK_SUCCESS(status); + ux_test_command_count ++; + break; + case 5: + /* GetObjectHandles. */ + // printf("GetNumObjectHandles\n"); + pima_host -> ux_host_class_pima_bulk_out_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_actual_length = pima_host -> ux_host_class_pima_bulk_out_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_requested_length; + pima_host -> ux_host_class_pima_bulk_out_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_completion_code = UX_SUCCESS; + tx_semaphore_put(&pima_host -> ux_host_class_pima_bulk_out_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_semaphore); + status = _ux_device_class_pima_object_handles_send(pima_device, pima_device->ux_device_class_pima_storage_id, UX_PICTBRIDGE_OBJECT_SCRIPT, 0); + UX_TEST_CHECK_SUCCESS(status); + ux_test_command_count ++; + break; + } + } +} +static VOID ux_test_pima_command(UX_TEST_ACTION *action, VOID *params) +{ +UINT status; + // printf("PIMA command #%ld\n", ux_test_command_count); + switch(ux_test_command_count) + { + case 4: + tx_semaphore_put(&replace_pima_cmd_semaphore); + return; + } + ux_test_command_count ++; +} + +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_TRUE}, /* 1. _device_info_get */ +{ 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_TRUE}, /* 2. _session_open */ +{ 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_TRUE}, /* 3. _storage_ids_get */ +{ 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_TRUE}, /* 4. _storage_info_get */ +{ 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}, /* 5. _num_objects_get */ +{ 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_TRUE}, /* 6. _num_objects_get */ +{ 0 } +}; + + +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); + } + + /* Initialize the dpshost structure with the printer vendor info. */ + ux_utility_memory_copy(pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_vendor_name, "ExpressLogic",13); + ux_utility_memory_copy(pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_product_name, "EL_Pictbridge_Printer",21); + ux_utility_memory_copy(pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_serial_no, "ABC_123",7); + + /* Set supported versions. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dpsversions[0] = 0x00010000; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dpsversions[1] = 0x00010001; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dpsversions[2] = 0; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_vendor_specific_version = 0x00010000; + + /* Set print services to TRUE. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_print_service_available = 0x30010000; + + /* Set Qualities. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_qualities[0] = UX_PICTBRIDGE_QUALITIES_DEFAULT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_qualities[1] = UX_PICTBRIDGE_QUALITIES_NORMAL; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_qualities[2] = UX_PICTBRIDGE_QUALITIES_DRAFT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_qualities[3] = UX_PICTBRIDGE_QUALITIES_FINE; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_qualities[4] = 0; + + /* Set Paper Sizes. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_papersizes[0] = UX_PICTBRIDGE_PAPER_SIZES_DEFAULT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_papersizes[1] = UX_PICTBRIDGE_PAPER_SIZES_4IX6I; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_papersizes[2] = UX_PICTBRIDGE_PAPER_SIZES_L; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_papersizes[3] = UX_PICTBRIDGE_PAPER_SIZES_2L; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_papersizes[4] = UX_PICTBRIDGE_PAPER_SIZES_LETTER; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_papersizes[5] = 0; + + /* Set Paper Types. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_papertypes[0] = UX_PICTBRIDGE_PAPER_TYPES_DEFAULT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_papertypes[1] = UX_PICTBRIDGE_PAPER_TYPES_PLAIN; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_papertypes[2] = UX_PICTBRIDGE_PAPER_TYPES_PHOTO; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_papertypes[3] = 0; + + /* Set File Types. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_filetypes[0] = UX_PICTBRIDGE_FILE_TYPES_DEFAULT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_filetypes[1] = UX_PICTBRIDGE_FILE_TYPES_EXIF_JPEG; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_filetypes[2] = UX_PICTBRIDGE_FILE_TYPES_JFIF; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_filetypes[3] = UX_PICTBRIDGE_FILE_TYPES_DPOF; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_filetypes[4] = 0; + + /* Set Date Prints. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dateprints[0] = UX_PICTBRIDGE_DATE_PRINTS_DEFAULT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dateprints[1] = UX_PICTBRIDGE_DATE_PRINTS_OFF; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dateprints[2] = UX_PICTBRIDGE_DATE_PRINTS_ON; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dateprints[3] = 0; + + /* Set File Name Prints. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_filenameprints[0] = UX_PICTBRIDGE_FILE_NAME_PRINTS_DEFAULT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_filenameprints[1] = UX_PICTBRIDGE_FILE_NAME_PRINTS_OFF; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_filenameprints[2] = UX_PICTBRIDGE_FILE_NAME_PRINTS_ON; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_filenameprints[3] = 0; + + /* Set Image optimizes. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_imageoptimizes[0] = UX_PICTBRIDGE_IMAGE_OPTIMIZES_DEFAULT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_imageoptimizes[1] = UX_PICTBRIDGE_IMAGE_OPTIMIZES_OFF; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_imageoptimizes[2] = UX_PICTBRIDGE_IMAGE_OPTIMIZES_ON; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_imageoptimizes[3] = 0; + + /* Set Layouts. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_layouts[0] = UX_PICTBRIDGE_LAYOUTS_DEFAULT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_layouts[1] = UX_PICTBRIDGE_LAYOUTS_1_UP_BORDER; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_layouts[2] = UX_PICTBRIDGE_LAYOUTS_INDEX_PRINT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_layouts[3] = UX_PICTBRIDGE_LAYOUTS_1_UP_BORDERLESS; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_layouts[4] = 0; + + /* Set Fixed Sizes. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_fixedsizes[0] = UX_PICTBRIDGE_FIXED_SIZE_DEFAULT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_fixedsizes[1] = UX_PICTBRIDGE_FIXED_SIZE_35IX5I; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_fixedsizes[2] = UX_PICTBRIDGE_FIXED_SIZE_4IX6I; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_fixedsizes[3] = UX_PICTBRIDGE_FIXED_SIZE_5IX7I; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_fixedsizes[4] = UX_PICTBRIDGE_FIXED_SIZE_7CMX10CM; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_fixedsizes[5] = UX_PICTBRIDGE_FIXED_SIZE_LETTER; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_fixedsizes[6] = UX_PICTBRIDGE_FIXED_SIZE_A4; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_fixedsizes[7] = 0; + + /* Set croppings. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_croppings[0] = UX_PICTBRIDGE_CROPPINGS_DEFAULT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_croppings[1] = UX_PICTBRIDGE_CROPPINGS_OFF; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_croppings[2] = UX_PICTBRIDGE_CROPPINGS_ON; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_croppings[3] = 0; + + /* Set Print Service Status to idle. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dpsprintservicestatus = UX_PICTBRIDGE_DPS_PRINTSERVICE_STATUS_IDLE; + + /* Set Job End Reason. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_jobendreason = UX_PICTBRIDGE_JOB_END_REASON_NOT_ENDED; + + /* Set Error Status. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_errorstatus = UX_PICTBRIDGE_ERROR_STATUS_NO_ERROR; + + /* Set Error Reason. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_errorreason = UX_PICTBRIDGE_ERROR_REASON_NO_REASON; + + /* Set Disconnection Enable. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_disconnectenable = UX_PICTBRIDGE_DISCONNECT_ENABLE_TRUE; + + /* Set Capability Changed. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_capabilitychanged = UX_PICTBRIDGE_CAPABILITY_CHANGED_FALSE; + + /* Set New Job OK. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_newjobok = UX_PICTBRIDGE_NEW_JOB_TRUE; + + /* Set a callback when an object is being received. */ + pictbridge_host.ux_pictbridge_application_object_data_write = test_pictbridge_host_object_data_write; + +/* +During initialization the host pictbridge application queries the device for +number of objects and later retrieves the object handles. One may observe that +the pictbridge -> ux_pictbridge_object_handles_array array is hardcoded to be 64 +elements ULONG large. In case a malicious pima device provides a number of +object larger than 64 a buffer overflow during retrieval of object handles will +occur as the buffer size is set to 4 * ux_host_class_pima_session_nb_objects, +where ux_host_class_pima_session_nb_objects is attacker controlled. + +In example if a malicious device provides object count of 256, +pima_session -> ux_host_class_pima_session_nb_objects will be set to 256 and +256 * 4 bytes of payload will be retrieved from the device and stored in the +64 * 4 byte large pictbridge -> ux_pictbridge_object_handles_array array +resulting in an overflow of 768 bytes. +Since ux_host_class_pima_session_nb_objects is controlled by the attacker the +actual size of the overflow may be quite larger. One may attempt to achieve +execution of arbitrary code e.g., by overwriting one of the void pointers +present in the UX_PICTBRIDGE_STRUCT struct (the +ux_pictbridge_object_handles_array array is a member of this struct). + +``` +status = _ux_host_class_pima_num_objects_get(pima, pima_session, +UX_PICTBRIDGE_ALL_CONTAINERS, UX_PICTBRIDGE_OBJECT_SCRIPT); +if (status != UX_SUCCESS) +{ + _ux_host_class_pima_session_close(pima, pima_session); + return(UX_PICTBRIDGE_ERROR_STORE_NOT_AVAILABLE); +} +status = _ux_host_class_pima_object_handles_get(pima, pima_session, +pictbridge -> ux_pictbridge_object_handles_array, +4 * pima_session -> ux_host_class_pima_session_nb_objects, +UX_PICTBRIDGE_ALL_CONTAINERS, UX_PICTBRIDGE_OBJECT_SCRIPT, 0); +``` + +The implementation does not assure that the number of provided objects can +actually fit the pictbridge -> ux_pictbridge_object_handles_array array. + +*Impact* + +The vulnerability may be exploited to execute arbitrary code or crash the +pictbridge host application. + +*Reproduction steps* + +- Connect a malicious device to the host running pictbridge application +- Provide a response with a number of objects larger than 64 (size of +pictbridge -> ux_pictbridge_object_handles_array) +- Observe a buffer overflow during retrieval of object handles +*/ + + /* Hook requests to replace answers. */ + 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); + replace_pima_cmd_n_obj = 256; + ux_test_hcd_sim_host_set_actions(replace_bulk_out_transfer); + + /* Activate the pictbridge dpshost. */ + status = _ux_pictbridge_dpshost_start(&pictbridge_host, pima_host); + UX_TEST_CHECK_NOT_SUCCESS(status); + + tx_thread_sleep(5); + + /* Test object parse. + * Tag format: */ +UCHAR ux_test_xml[4096] = {0}; +UCHAR *tag = ""; +UCHAR *tag_end = ""; + for (i = 0; i <= UX_PICTBRIDGE_MAX_TAG_DEPTH; i ++) + strcat(ux_test_xml, tag); + for (i = 0; i <= UX_PICTBRIDGE_MAX_TAG_DEPTH; i ++) + strcat(ux_test_xml, tag_end); +ULONG ux_test_xml_length = ux_utility_string_length_get(ux_test_xml); + status = _ux_pictbridge_object_parse(&pictbridge_host, ux_test_xml, ux_test_xml_length); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + 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); + +} + +static UINT test_pictbridge_device_object_data_copy(UX_PICTBRIDGE *pictbridge, ULONG object_handle, UCHAR *object_buffer, ULONG object_offset, ULONG object_length, ULONG *actual_length) +{ + pictbridge_device_copy_count ++; + + /* Copy the demanded object data portion. */ + ux_utility_memory_copy(object_buffer, ux_test_jpeg_image + object_offset, object_length); + + /* Update the actual length. */ + *actual_length = object_length; + + /* We have copied the requested data. Return OK. */ + return(UX_SUCCESS); + +} + + +UINT test_pictbridge_device_event_callback(struct UX_PICTBRIDGE_STRUCT *pictbridge, UINT event_flag) +{ + + /* Check if we received NotifyDeviceStatus event. */ + if (event_flag & UX_PICTBRIDGE_EVENT_FLAG_NOTIFY_DEVICE_STATUS) + { + + /* Check if the printer can accept new job. */ + if (pictbridge -> ux_pictbridge_dpsclient.ux_pictbridge_devinfo_newjobok == UX_PICTBRIDGE_NEW_JOB_TRUE) + { + + /* Let the demo thread to send a new job. */ + tx_semaphore_put(&print_semaphore); + } + } + + return UX_SUCCESS; +} + + +void test_thread_device_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG actual_flags; + + /* Create a semaphore for the demo. */ + status = tx_semaphore_create(&print_semaphore,"Print Semaphore", 0); + UX_TEST_CHECK_SUCCESS(status); + + while(1) + { + + /* We should wait for the host and the client to discover one another. */ + status = ux_utility_event_flags_get(&pictbridge_device.ux_pictbridge_event_flags_group, UX_PICTBRIDGE_EVENT_FLAG_DISCOVERY, + TX_AND_CLEAR, &actual_flags, UX_PICTBRIDGE_EVENT_TIMEOUT); + + /* Check status. */ + if (status == UX_SUCCESS) + { + + /* Check if the pictbridge state machine has changed to discovery complete. */ + if (pictbridge_device.ux_pictbridge_discovery_state == UX_PICTBRIDGE_DPSCLIENT_DISCOVERY_COMPLETE) + { + + /* We can now communicate using XML scripts with the printer. First get information on capabilities. */ + status = ux_pictbridge_dpsclient_api_configure_print_service(&pictbridge_device); + UX_TEST_CHECK_SUCCESS(status); + + /* Check status. */ + if (status == UX_SUCCESS) + { + + /* Get the printer capabilities : Qualities. */ + status = ux_pictbridge_dpsclient_api_capability(&pictbridge_device, UX_PICTBRIDGE_API_QUALITIES, 0); + UX_TEST_CHECK_SUCCESS(status); + + /* Get the printer capabilities : PaperSizes. */ + status = ux_pictbridge_dpsclient_api_capability(&pictbridge_device, UX_PICTBRIDGE_API_PAPER_SIZES, 0); + UX_TEST_CHECK_SUCCESS(status); + + /* Get the printer capabilities : FileTypes. */ + status = ux_pictbridge_dpsclient_api_capability(&pictbridge_device, UX_PICTBRIDGE_API_FILE_TYPES, 0); + UX_TEST_CHECK_SUCCESS(status); + + /* Get the printer capabilities : DatePrints. */ + status = ux_pictbridge_dpsclient_api_capability(&pictbridge_device, UX_PICTBRIDGE_API_DATE_PRINTS, 0); + UX_TEST_CHECK_SUCCESS(status); + + /* Get the printer capabilities : FileNamePrints. */ + status = ux_pictbridge_dpsclient_api_capability(&pictbridge_device, UX_PICTBRIDGE_API_FILE_NAME_PRINTS, 0); + UX_TEST_CHECK_SUCCESS(status); + + /* Get the printer capabilities : ImageOptimizes. */ + status = ux_pictbridge_dpsclient_api_capability(&pictbridge_device, UX_PICTBRIDGE_API_IMAGE_OPTIMIZES, 0); + UX_TEST_CHECK_SUCCESS(status); + + /* Get the printer capabilities : Layouts. */ + status = ux_pictbridge_dpsclient_api_capability(&pictbridge_device, UX_PICTBRIDGE_API_LAYOUTS, 0); + UX_TEST_CHECK_SUCCESS(status); + + /* Get the printer capabilities : FixedSizes. */ + status = ux_pictbridge_dpsclient_api_capability(&pictbridge_device, UX_PICTBRIDGE_API_FIXED_SIZES, 0); + UX_TEST_CHECK_SUCCESS(status); + + /* Get the printer capabilities : Croppings. */ + status = ux_pictbridge_dpsclient_api_capability(&pictbridge_device, UX_PICTBRIDGE_API_CROPPINGS, 0); + UX_TEST_CHECK_SUCCESS(status); + + /* We have all the printer capabilities, get the device status. */ + status = ux_pictbridge_dpsclient_api_device_status(&pictbridge_device); + UX_TEST_CHECK_SUCCESS(status); + + /* Check status. */ + if (status == UX_SUCCESS) + { + + /* Check if the printer is ready for a pring job. */ + if (pictbridge_device.ux_pictbridge_dpsclient.ux_pictbridge_devinfo_newjobok == UX_PICTBRIDGE_NEW_JOB_TRUE) + { + + /* We can start a new job. Fill in the JobConfig and PrintInfo structures. */ + jobinfo = &pictbridge_device.ux_pictbridge_jobinfo; + + /* Attach a printinfo structure to the job. */ + jobinfo -> ux_pictbridge_jobinfo_printinfo_start = &printinfo; + + + /* Set the default values for print job. */ + jobinfo -> ux_pictbridge_jobinfo_quality = UX_PICTBRIDGE_QUALITIES_DEFAULT; + jobinfo -> ux_pictbridge_jobinfo_papersize = UX_PICTBRIDGE_PAPER_SIZES_DEFAULT; + jobinfo -> ux_pictbridge_jobinfo_papertype = UX_PICTBRIDGE_PAPER_TYPES_DEFAULT; + jobinfo -> ux_pictbridge_jobinfo_filetype = UX_PICTBRIDGE_FILE_TYPES_DEFAULT; + jobinfo -> ux_pictbridge_jobinfo_dateprint = UX_PICTBRIDGE_DATE_PRINTS_DEFAULT; + jobinfo -> ux_pictbridge_jobinfo_filenameprint = UX_PICTBRIDGE_FILE_NAME_PRINTS_DEFAULT; + jobinfo -> ux_pictbridge_jobinfo_imageoptimize = UX_PICTBRIDGE_IMAGE_OPTIMIZES_OFF; + jobinfo -> ux_pictbridge_jobinfo_layout = UX_PICTBRIDGE_LAYOUTS_DEFAULT; + jobinfo -> ux_pictbridge_jobinfo_fixedsize = UX_PICTBRIDGE_FIXED_SIZE_DEFAULT; + jobinfo -> ux_pictbridge_jobinfo_cropping = UX_PICTBRIDGE_CROPPINGS_DEFAULT; + + /* Program the callback function for reading the object data. */ + jobinfo -> ux_pictbridge_jobinfo_object_data_read = test_pictbridge_device_object_data_copy; + + /* This is a demo, the fileID is hardwired (1 and 2 for scripts, 3 for photo to be printed. */ + printinfo.ux_pictbridge_printinfo_fileid = UX_PICTBRIDGE_OBJECT_HANDLE_PRINT; + ux_utility_memory_copy(printinfo.ux_pictbridge_printinfo_filename, "Pictbridge demo file", 20); + ux_utility_memory_copy(printinfo.ux_pictbridge_printinfo_date, "01/01/2008", 10); + + /* Fill in the object info to be printed. First get the pointer to the object container in the job info structure. */ + object = (UX_SLAVE_CLASS_PIMA_OBJECT *) jobinfo -> ux_pictbridge_jobinfo_object; + + /* Store the object format : JPEG picture. */ + object -> ux_device_class_pima_object_format = UX_DEVICE_CLASS_PIMA_OFC_EXIF_JPEG; + object -> ux_device_class_pima_object_compressed_size = UX_TEST_JPEG_IMAGE_LENGTH; + object -> ux_device_class_pima_object_offset = 0; + object -> ux_device_class_pima_object_handle_id = UX_PICTBRIDGE_OBJECT_HANDLE_PRINT; + object -> ux_device_class_pima_object_length = UX_TEST_JPEG_IMAGE_LENGTH; + + /* File name is in Unicode. */ + ux_utility_string_to_unicode("JPEG Image", object -> ux_device_class_pima_object_filename); + + /* And start the job. */ + status = ux_pictbridge_dpsclient_api_start_job(&pictbridge_device); + UX_TEST_CHECK_SUCCESS(status); + + /* Register the callback function to receive events from the printer. */ + ux_pictbridge_dpsclient_register_event_callback_function(&pictbridge_device, test_pictbridge_device_event_callback); + + /* Wait for the job to complete. */ + status = tx_semaphore_get(&print_semaphore, 30000); + UX_TEST_CHECK_SUCCESS(status); + + if (status == TX_SUCCESS) + { + + /* Print the job again to demo the use of callback function. */ + status = ux_pictbridge_dpsclient_api_start_job(&pictbridge_device); + UX_TEST_CHECK_SUCCESS(status); + + /* Let host thread run to end. */ + tx_semaphore_put(&wait_semaphore); + } + + /* Unregister the callback function by passing a Null pointer. */ + ux_pictbridge_dpsclient_register_event_callback_function(&pictbridge_device, UX_NULL); + } + } + } + } + } + } +} diff --git a/test/regression/usbx_msrc_81109_pictbridge_array_element_to_hexa_test.c b/test/regression/usbx_msrc_81109_pictbridge_array_element_to_hexa_test.c new file mode 100644 index 00000000..404f5f5f --- /dev/null +++ b/test/regression/usbx_msrc_81109_pictbridge_array_element_to_hexa_test.c @@ -0,0 +1,207 @@ +/* This test is designed to test the ux_utility_descriptor_parse. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_test.h" + +#include "ux_pictbridge.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +static UCHAR element_buffer[UX_PICTBRIDGE_MAX_ELEMENT_SIZE + 8]; +static ULONG hexa_buffer[UX_PICTBRIDGE_MAX_DEVINFO_ARRAY_SIZE + 8]; + + +/* Define USBX test global variables. */ + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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); + } + } +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_msrc_81109_pictbridge_array_element_to_hexa_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; + + /* Inform user. */ + printf("Running MSRC 81109 - Pictbridge array element to hexa Test.......... "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ +UINT i; + + stepinfo(">>>>>>>>> Normal case\n"); + ux_utility_memory_set(element_buffer, 0, sizeof(element_buffer)); + ux_utility_memory_set(hexa_buffer, 0xFF, sizeof(hexa_buffer)); + strcat(element_buffer, "88 99 10"); + UX_TEST_CHECK_SUCCESS(_ux_pictbridge_array_element_to_array_hexa(element_buffer, hexa_buffer)); + UX_TEST_ASSERT(hexa_buffer[0] == 0x88); + UX_TEST_ASSERT(hexa_buffer[1] == 0x99); + UX_TEST_ASSERT(hexa_buffer[2] == 0x10); + for(i = 3; i < UX_PICTBRIDGE_MAX_DEVINFO_ARRAY_SIZE; i ++) /* Remaining array items are 0. */ + UX_TEST_ASSERT_MESSAGE(hexa_buffer[i] == 0, "%d:%lx", i, hexa_buffer[i]); + for ( ; i < sizeof(hexa_buffer)/sizeof(ULONG); i ++) /* Array outside is not touched. */ + UX_TEST_ASSERT_MESSAGE(hexa_buffer[i] == 0xFFFFFFFF, "%d:%lx", i, hexa_buffer[i]); + + stepinfo(">>>>>>>>> No delimiter case (expect error)\n"); + ux_utility_memory_set(element_buffer, 0, sizeof(element_buffer)); + ux_utility_memory_set(hexa_buffer, 0x5A, sizeof(hexa_buffer)); + strcat(element_buffer, "111111112222222233333333444444445555555566666666777777778888888899999999aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffff1111111100000000"); + UX_TEST_CHECK_NOT_SUCCESS(_ux_pictbridge_array_element_to_array_hexa(element_buffer, hexa_buffer)); + for (i = 0; i < sizeof(hexa_buffer)/sizeof(ULONG); i ++) + UX_TEST_ASSERT_MESSAGE(hexa_buffer[i] == 0x5a5a5a5a, "%d:%lx", i, hexa_buffer[i]); + + stepinfo(">>>>>>>>> Invalid char case (expect error)\n"); + ux_utility_memory_set(element_buffer, 0, sizeof(element_buffer)); + ux_utility_memory_set(hexa_buffer, 0x5A, sizeof(hexa_buffer)); + strcat(element_buffer, "1111 ss"); + UX_TEST_CHECK_NOT_SUCCESS(_ux_pictbridge_array_element_to_array_hexa(element_buffer, hexa_buffer)); + UX_TEST_ASSERT(hexa_buffer[0] == 0x1111); + UX_TEST_ASSERT(hexa_buffer[1] == 0); + for (i = 2; i < sizeof(hexa_buffer)/sizeof(ULONG); i ++) + UX_TEST_ASSERT_MESSAGE(hexa_buffer[i] == 0x5a5a5a5a, "%d:%lx", i, hexa_buffer[i]); + + stepinfo(">>>>>>>>> Too many elements (only first hexas are filled)\n"); + ux_utility_memory_set(element_buffer, 0, sizeof(element_buffer)); + ux_utility_memory_set(hexa_buffer, 0x5A, sizeof(hexa_buffer)); + strcat(element_buffer, "11111111 22222222 33 44 55 66 77 88 99 aaa bbb ccc ddd eeee ffff 00 11 22 33"); + UX_TEST_CHECK_SUCCESS(_ux_pictbridge_array_element_to_array_hexa(element_buffer, hexa_buffer)); + UX_TEST_ASSERT(hexa_buffer[0] == 0x11111111); + UX_TEST_ASSERT(hexa_buffer[1] == 0x22222222); + UX_TEST_ASSERT(hexa_buffer[2] == 0x33); + UX_TEST_ASSERT(hexa_buffer[3] == 0x44); + UX_TEST_ASSERT(hexa_buffer[4] == 0x55); + UX_TEST_ASSERT(hexa_buffer[5] == 0x66); + UX_TEST_ASSERT(hexa_buffer[6] == 0x77); + UX_TEST_ASSERT(hexa_buffer[7] == 0x88); + UX_TEST_ASSERT(hexa_buffer[8] == 0x99); + UX_TEST_ASSERT(hexa_buffer[9] == 0xaaa); + UX_TEST_ASSERT(hexa_buffer[10] == 0xbbb); + UX_TEST_ASSERT(hexa_buffer[11] == 0xccc); + UX_TEST_ASSERT(hexa_buffer[12] == 0xddd); + UX_TEST_ASSERT(hexa_buffer[13] == 0xeeee); + UX_TEST_ASSERT(hexa_buffer[14] == 0xffff); + UX_TEST_ASSERT(hexa_buffer[15] == 0x00); + for (i = UX_PICTBRIDGE_MAX_DEVINFO_ARRAY_SIZE; i < sizeof(hexa_buffer)/sizeof(ULONG); i ++) /* Array outside is not touched. */ + UX_TEST_ASSERT_MESSAGE(hexa_buffer[i] == 0x5a5a5a5a, "%d:%lx", i, hexa_buffer[i]); + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_msrc_81112_host_cdc_ecm_endpoints_get_tests.c b/test/regression/usbx_msrc_81112_host_cdc_ecm_endpoints_get_tests.c new file mode 100644 index 00000000..e96673f4 --- /dev/null +++ b/test/regression/usbx_msrc_81112_host_cdc_ecm_endpoints_get_tests.c @@ -0,0 +1,504 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_device_class_dummy.h" +#include "ux_device_stack.h" +#include "ux_host_class_cdc_ecm.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); + +static VOID ux_test_hcd_entry_should_not_be_called(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_disconnect(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 4)]; + +static UX_DEVICE *device = UX_NULL; +static UINT device_stall_count = 3; + +static UX_HOST_CLASS_CDC_ECM *host_cdc_ecm = UX_NULL; + +static ULONG host_device_insertion_counter = 0; +static ULONG host_device_removal_counter = 0; + +static ULONG enum_counter; + +static ULONG error_counter; +static ULONG error_callback_counter = 0; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_on_set_cfg; +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_enum_mem_alloc_count; + +static ULONG rsc_test_sem_usage; +static ULONG rsc_test_sem_get_count; +static ULONG rsc_test_mutex_usage; +static ULONG rsc_test_mem_alloc_count; + +static UX_DEVICE_CLASS_DUMMY *device_dummy = UX_NULL; +static UX_DEVICE_CLASS_DUMMY_PARAMETER device_dummy_parameter; + + +/* Define device framework. */ + +#define _W0(w) ( (w) & 0xFF) +#define _W1(w) (((w) >> 8) & 0xFF) + +#define _CONFIGURATION_DESCRIPTOR(total_len, n_ifc, cfg_val) \ + 0x09, 0x02, _W0(total_len), _W1(total_len), (n_ifc), (cfg_val), \ + 0x00, 0xc0, 0x32, + +#define _INTERFACE_DESCRIPTOR(ifc_n, alt, n_ep, cls, sub, protocol) \ + 0x09, 0x04, (ifc_n), (alt), (n_ep), (cls), (sub), (protocol), 0x00, + +#define _ENDPOINT_DESCRIPTOR(addr, attr, pktsize, interval) \ + 0x07, 0x05, (addr), (attr), _W0(pktsize), _W1(pktsize), (interval), + +#define _CFG_TOTAL_LEN (9+8 +9+5+13+5+7+ 9+9+7) + +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0xEF bDeviceClass: Composite class code + 0x02 bDeviceSubclass: class sub code + 0x00 bDeviceProtocol: Device protocol + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, /* bLength */ + 0x01, /* bDescriptorType */ + 0x10, 0x01, /* bcdUSB */ + 0xef, /* bDeviceClass - Depends on bDeviceSubClass */ + 0x02, /* bDeviceSubClass - Depends on bDeviceProtocol */ + 0x01, /* bDeviceProtocol - There's an IAD */ + 0x40, /* bMaxPacketSize0 */ + 0x70, 0x07, /* idVendor */ + 0x42, 0x10, /* idProduct */ + 0x00, 0x01, /* bcdDevice */ + 0x01, /* iManufacturer */ + 0x02, /* iProduct */ + 0x03, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ + + _CONFIGURATION_DESCRIPTOR(_CFG_TOTAL_LEN, 1, 1) + + /* Interface Association Descriptor @ 18+9=27 */ + 0x08, /* bLength */ + 0x0b, /* bDescriptorType */ + 0x00, /* bFirstInterface */ + 0x02, /* bInterfaceCount */ + 0x02, /* bFunctionClass - CDC - Communication */ + 0x06, /* bFunctionSubClass - ECM */ + 0x00, /* bFunctionProtocol - No class specific protocol required */ + 0x00, /* iFunction */ + + _INTERFACE_DESCRIPTOR(0, 0, 1, 0x02, 0x06, 0x00) + /* CDC Header Functional Descriptor @ 35+9=44 */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x00, /* bDescriptorSubType */ + 0x10, 0x01, /* bcdCDC */ + /* CDC ECM Functional Descriptor @ 44+5=49 */ + 0x0d, /* bLength */ + 0x24, /* bDescriptorType */ + 0x0f, /* bDescriptorSubType */ + 0x04, /* iMACAddress */ + 0x00, 0x00, 0x00, 0x00, /* bmEthernetStatistics */ + 0xea, 0x05, /* wMaxSegmentSize */ + 0x00, 0x00, /* wNumberMCFilters */ + 0x00, /* bNumberPowerFilters */ + /* CDC Union Functional Descriptor @ 49+13=62 */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x06, /* bDescriptorSubType */ + 0x00, /* bmMasterInterface */ + 0x01, /* bmSlaveInterface0 */ + _ENDPOINT_DESCRIPTOR(0x83, 0x03, 8, 0x0B) + + _INTERFACE_DESCRIPTOR(1, 0, 0, 0x0a, 0x00, 0x00) + _INTERFACE_DESCRIPTOR(1, 1, 2, 0x0a, 0x00, 0x00) + _ENDPOINT_DESCRIPTOR(0x02, 0x02, 64, 0x00) +}; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_full_speed) +#define device_framework_high_speed device_framework_full_speed + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "AzureRTOS" */ + 0x09, 0x04, 0x01, 9, + 'A','z','u','r','e','R','T','O','S', + + /* Product string descriptor : Index 2 - "Test device" */ + 0x09, 0x04, 0x02, 14, + 'T','e','s','t',' ',' ',' ',' ','d','e','v','i','c','e', + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31, + + /* MAC Address string descriptor : Index 4 - "001E5841B879" */ + 0x09, 0x04, 0x04, 0x0C, + 0x30, 0x30, 0x31, 0x45, 0x35, 0x38, + 0x34, 0x31, 0x42, 0x38, 0x37, 0x39, + +}; + + /* 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +/* Test interactions */ + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT test_slave_change_function(ULONG change) +{ + return 0; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ECM *cdc_ecm_inst = (UX_HOST_CLASS_CDC_ECM *) inst; + // printf("test_host_change_function: event %lx, cls %p, inst %p\n", event, (void*)cls, (void*)inst); + switch(event) + { + + case UX_DEVICE_INSERTION: + host_device_insertion_counter ++; + host_cdc_ecm = cdc_ecm_inst; + break; + + case UX_DEVICE_REMOVAL: + host_device_removal_counter ++; + if (host_cdc_ecm == cdc_ecm_inst) + host_cdc_ecm = UX_NULL; + break; + + case UX_DEVICE_CONNECTION: + device = (UX_DEVICE *)inst; + break; + + case UX_DEVICE_DISCONNECTION: + if ((VOID *)device == inst) + device = UX_NULL; + break; + +#if defined(UX_HOST_STANDALONE) + case UX_STANDALONE_WAIT_BACKGROUND_TASK: + tx_thread_relinquish(); + break; +#endif + + default: + break; + } + return 0; +} + +static VOID test_dummy_instance_activate(VOID *dummy_instance) +{ + if (device_dummy == UX_NULL) + device_dummy = (UX_DEVICE_CLASS_DUMMY *)dummy_instance; +} +static VOID test_dummy_instance_deactivate(VOID *dummy_instance) +{ + if ((VOID*)device_dummy == dummy_instance) + device_dummy = UX_NULL; +} +static VOID test_dummy_control_request(UX_DEVICE_CLASS_DUMMY *dummy_instance, UX_SLAVE_TRANSFER *transfer_request) +{ +UINT i; +ULONG cmd_type = transfer_request -> ux_slave_transfer_request_setup[0] | + (transfer_request -> ux_slave_transfer_request_setup[1] << 8); +UCHAR *cmd_buf = transfer_request -> ux_slave_transfer_request_data_pointer; + + if (device_dummy == dummy_instance) + { + + switch(cmd_type) + { + + default: + printf("_dummy_CREQ:"); + for (i = 0; i < 8; i ++) + printf(" %02x", transfer_request -> ux_slave_transfer_request_setup[i]); + printf("\n"); + break; + } + } +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + error_callback_counter ++; +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_enum_sem_get_count = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_msrc_81112_host_cdc_ecm_endpoints_get_tests_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + printf("Running MSRC 81112 - Host CDC ECM EPs Get Test...................... "); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* Initialize the free memory pointer */ + stack_pointer = (CHAR *) usbx_memory; + memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 4); + + /* Initialize USBX Memory */ + status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL,0); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_system_initialize failed 0x%x\n", status); + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_host_stack_initialize failed 0x%x\n", status); + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_ecm_name, _ux_host_class_cdc_ecm_entry); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_host_stack_class_register failed 0x%x\n", status); + + /* 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, + test_slave_change_function); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_device_stack_initialize failed 0x%x\n", status); + + /* Set the parameters for callback when insertion/extraction of a dummy device. */ + _ux_utility_memory_set(&device_dummy_parameter, 0, sizeof(device_dummy_parameter)); + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_instance_activate = test_dummy_instance_activate; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_instance_deactivate = test_dummy_instance_deactivate; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_control_request = test_dummy_control_request; + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_device_class_dummy_name, + _ux_device_class_dummy_entry, + 1, 0, &device_dummy_parameter); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_device_stack_class_register failed 0x%x\n", status); + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "_ux_test_dcd_sim_slave_initialize failed 0x%x\n", status); + + /* 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); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_host_stack_hcd_register failed 0x%x\n", status); + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_thread_host_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_ASSERT_MESSAGE(status == TX_SUCCESS, "tx_thread_create failed 0x%x\n", status); + + /* Create the main slave simulation thread. */ + stack_pointer += UX_DEMO_STACK_SIZE; + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_ASSERT_MESSAGE(status == TX_SUCCESS, "tx_thread_create failed 0x%x\n", status); + +} + +static UINT _test_check_host_connection_error(VOID) +{ + if (device_dummy && host_cdc_ecm) + return(UX_SUCCESS); + if (error_callback_counter >= 3) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_connection_success(VOID) +{ + if (device_dummy && host_cdc_ecm) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_disconnection_success(VOID) +{ + if (device_dummy == UX_NULL && host_cdc_ecm == UX_NULL) + return(UX_SUCCESS); + return(UX_ERROR); +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +ULONG mem_free; +ULONG loop; +ULONG parameter_u32[64/4]; +USHORT *parameter_u16 = (USHORT*)parameter_u32; +UCHAR *parameter_u8 = (UCHAR*)parameter_u32; +UX_INTERFACE *interface; + + + stepinfo("\n"); + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + status = ux_test_sleep_break_on_success(10000, _test_check_host_connection_error); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT_MESSAGE((host_device_insertion_counter == 0 && host_device_removal_counter == 0), + "Expect no INS(%ld)/RM(%ld) detection\n", host_device_insertion_counter, host_device_removal_counter); + UX_TEST_ASSERT_MESSAGE(device, "Expect device\n"); + UX_TEST_ASSERT_MESSAGE(device -> ux_device_class_instance == UX_NULL, "Expect no device class instance\n"); + interface = device -> ux_device_current_configuration -> ux_configuration_first_interface; + UX_TEST_ASSERT_MESSAGE(interface, "Expect interface\n"); + while(interface) + { + UX_TEST_ASSERT_MESSAGE(interface -> ux_interface_class_instance == UX_NULL, "Expect no interface class instance\n"); + interface = interface -> ux_interface_next_interface; + } + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_device_class_dummy_name, _ux_device_class_dummy_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); + tx_thread_relinquish(); +#else + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); +#endif + } +} diff --git a/test/regression/usbx_msrc_81142_host_storage_endpoints_get_tests.c b/test/regression/usbx_msrc_81142_host_storage_endpoints_get_tests.c new file mode 100644 index 00000000..4a5674e4 --- /dev/null +++ b/test/regression/usbx_msrc_81142_host_storage_endpoints_get_tests.c @@ -0,0 +1,469 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_device_class_dummy.h" +#include "ux_device_stack.h" +#include "ux_host_class_storage.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); + +static VOID ux_test_hcd_entry_should_not_be_called(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_disconnect(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 4)]; + +static UX_DEVICE *device = UX_NULL; +static UINT device_stall_count = 3; + +static UX_HOST_CLASS_STORAGE *host_storage = UX_NULL; + +static ULONG host_device_insertion_counter = 0; +static ULONG host_device_removal_counter = 0; + +static ULONG enum_counter; + +static ULONG error_counter; +static ULONG error_callback_counter = 0; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_on_set_cfg; +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_enum_mem_alloc_count; + +static ULONG rsc_test_sem_usage; +static ULONG rsc_test_sem_get_count; +static ULONG rsc_test_mutex_usage; +static ULONG rsc_test_mem_alloc_count; + +static UX_DEVICE_CLASS_DUMMY *device_dummy = UX_NULL; +static UX_DEVICE_CLASS_DUMMY_PARAMETER device_dummy_parameter; + + +/* Define device framework. */ + +#define _W0(w) ( (w) & 0xFF) +#define _W1(w) (((w) >> 8) & 0xFF) + +#define _CONFIGURATION_DESCRIPTOR(total_len, n_ifc, cfg_val) \ + 0x09, 0x02, _W0(total_len), _W1(total_len), (n_ifc), (cfg_val), \ + 0x00, 0xc0, 0x32, + +#define _INTERFACE_DESCRIPTOR(ifc_n, alt, n_ep, cls, sub, protocol) \ + 0x09, 0x04, (ifc_n), (alt), (n_ep), (cls), (sub), (protocol), 0x00, + +#define _ENDPOINT_DESCRIPTOR(addr, attr, pktsize, interval) \ + 0x07, 0x05, (addr), (attr), _W0(pktsize), _W1(pktsize), (interval), + +#define _CFG_TOTAL_LEN (9 +9+7) + +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0xEF bDeviceClass: Composite class code + 0x02 bDeviceSubclass: class sub code + 0x00 bDeviceProtocol: Device protocol + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, /* bLength */ + 0x01, /* bDescriptorType */ + 0x10, 0x01, /* bcdUSB */ + 0xef, /* bDeviceClass - Depends on bDeviceSubClass */ + 0x02, /* bDeviceSubClass - Depends on bDeviceProtocol */ + 0x01, /* bDeviceProtocol - There's an IAD */ + 0x40, /* bMaxPacketSize0 */ + 0x70, 0x07, /* idVendor */ + 0x42, 0x10, /* idProduct */ + 0x00, 0x01, /* bcdDevice */ + 0x01, /* iManufacturer */ + 0x02, /* iProduct */ + 0x03, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ + + _CONFIGURATION_DESCRIPTOR(_CFG_TOTAL_LEN, 1, 1) + _INTERFACE_DESCRIPTOR(0, 0, 1, 0x08, 0x06, 0x50) + _ENDPOINT_DESCRIPTOR(0x02, 0x02, 64, 0x00) +}; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_full_speed) +#define device_framework_high_speed device_framework_full_speed + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "AzureRTOS" */ + 0x09, 0x04, 0x01, 9, + 'A','z','u','r','e','R','T','O','S', + + /* Product string descriptor : Index 2 - "Test device" */ + 0x09, 0x04, 0x02, 14, + 'T','e','s','t',' ',' ',' ',' ','d','e','v','i','c','e', + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31, + + /* MAC Address string descriptor : Index 4 - "001E5841B879" */ + 0x09, 0x04, 0x04, 0x0C, + 0x30, 0x30, 0x31, 0x45, 0x35, 0x38, + 0x34, 0x31, 0x42, 0x38, 0x37, 0x39, + +}; + + /* 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +/* Test interactions */ + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT test_slave_change_function(ULONG change) +{ + return 0; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_STORAGE *storage_inst = (UX_HOST_CLASS_STORAGE *) inst; + printf("test_host_change_function: event %lx, cls %p, inst %p\n", event, (void*)cls, (void*)inst); + switch(event) + { + + case UX_DEVICE_INSERTION: + host_device_insertion_counter ++; + host_storage = storage_inst; + break; + + case UX_DEVICE_REMOVAL: + host_device_removal_counter ++; + if (host_storage == storage_inst) + host_storage = UX_NULL; + break; + + case UX_DEVICE_CONNECTION: + device = (UX_DEVICE *)inst; + break; + + case UX_DEVICE_DISCONNECTION: + if ((VOID *)device == inst) + device = UX_NULL; + break; + +#if defined(UX_HOST_STANDALONE) + case UX_STANDALONE_WAIT_BACKGROUND_TASK: + tx_thread_relinquish(); + break; +#endif + + default: + break; + } + return 0; +} + +static VOID test_dummy_instance_activate(VOID *dummy_instance) +{ + if (device_dummy == UX_NULL) + device_dummy = (UX_DEVICE_CLASS_DUMMY *)dummy_instance; +} +static VOID test_dummy_instance_deactivate(VOID *dummy_instance) +{ + if ((VOID*)device_dummy == dummy_instance) + device_dummy = UX_NULL; +} +static VOID test_dummy_control_request(UX_DEVICE_CLASS_DUMMY *dummy_instance, UX_SLAVE_TRANSFER *transfer_request) +{ +UINT i; +ULONG cmd_type = transfer_request -> ux_slave_transfer_request_setup[0] | + (transfer_request -> ux_slave_transfer_request_setup[1] << 8); +UCHAR *cmd_buf = transfer_request -> ux_slave_transfer_request_data_pointer; + + if (device_dummy == dummy_instance) + { + + switch(cmd_type) + { + + default: + printf("_dummy_CREQ:"); + for (i = 0; i < 8; i ++) + printf(" %02x", transfer_request -> ux_slave_transfer_request_setup[i]); + printf("\n"); + break; + } + } +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + error_callback_counter ++; +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_enum_sem_get_count = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_msrc_81142_host_storage_endpoints_get_tests_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + printf("Running MSRC 81112 - Host Storage EPs Get Test...................... "); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* Initialize the free memory pointer */ + stack_pointer = (CHAR *) usbx_memory; + memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 4); + + /* Initialize USBX Memory */ + status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL,0); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_system_initialize failed 0x%x\n", status); + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_host_stack_initialize failed 0x%x\n", status); + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, _ux_host_class_storage_entry); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_host_stack_class_register failed 0x%x\n", status); + + /* 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, + test_slave_change_function); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_device_stack_initialize failed 0x%x\n", status); + + /* Set the parameters for callback when insertion/extraction of a dummy device. */ + _ux_utility_memory_set(&device_dummy_parameter, 0, sizeof(device_dummy_parameter)); + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_instance_activate = test_dummy_instance_activate; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_instance_deactivate = test_dummy_instance_deactivate; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_control_request = test_dummy_control_request; + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_device_class_dummy_name, + _ux_device_class_dummy_entry, + 1, 0, &device_dummy_parameter); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_device_stack_class_register failed 0x%x\n", status); + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "_ux_test_dcd_sim_slave_initialize failed 0x%x\n", status); + + /* 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); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_host_stack_hcd_register failed 0x%x\n", status); + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_thread_host_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_ASSERT_MESSAGE(status == TX_SUCCESS, "tx_thread_create failed 0x%x\n", status); + + /* Create the main slave simulation thread. */ + stack_pointer += UX_DEMO_STACK_SIZE; + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_ASSERT_MESSAGE(status == TX_SUCCESS, "tx_thread_create failed 0x%x\n", status); + +} + +static UINT _test_check_host_connection_error(VOID) +{ + if (device_dummy && host_storage) + return(UX_SUCCESS); + if (error_callback_counter >= 3) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_connection_success(VOID) +{ + if (device_dummy && host_storage) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_disconnection_success(VOID) +{ + if (device_dummy == UX_NULL && host_storage == UX_NULL) + return(UX_SUCCESS); + return(UX_ERROR); +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +ULONG mem_free; +ULONG loop; +ULONG parameter_u32[64/4]; +USHORT *parameter_u16 = (USHORT*)parameter_u32; +UCHAR *parameter_u8 = (UCHAR*)parameter_u32; +UX_INTERFACE *interface; + + + stepinfo("\n"); + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + status = ux_test_sleep_break_on_success(10000, _test_check_host_connection_error); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT_MESSAGE((host_device_insertion_counter == 0 && host_device_removal_counter == 0), + "Expect no INS(%ld)/RM(%ld) detection\n", host_device_insertion_counter, host_device_removal_counter); + UX_TEST_ASSERT_MESSAGE(device, "Expect device\n"); + UX_TEST_ASSERT_MESSAGE(device -> ux_device_class_instance == UX_NULL, "Expect no device class instance\n"); + interface = device -> ux_device_current_configuration -> ux_configuration_first_interface; + UX_TEST_ASSERT_MESSAGE(interface, "Expect interface\n"); + while(interface) + { + UX_TEST_ASSERT_MESSAGE(interface -> ux_interface_class_instance == UX_NULL, "Expect no interface class instance\n"); + interface = interface -> ux_interface_next_interface; + } + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_device_class_dummy_name, _ux_device_class_dummy_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); + tx_thread_relinquish(); +#else + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); +#endif + } +} diff --git a/test/regression/usbx_msrc_81143_host_cdc_acm_endpoints_get_tests.c b/test/regression/usbx_msrc_81143_host_cdc_acm_endpoints_get_tests.c new file mode 100644 index 00000000..f4641caa --- /dev/null +++ b/test/regression/usbx_msrc_81143_host_cdc_acm_endpoints_get_tests.c @@ -0,0 +1,504 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_device_class_dummy.h" +#include "ux_device_stack.h" +#include "ux_host_class_cdc_acm.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); + +static VOID ux_test_hcd_entry_should_not_be_called(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_disconnect(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 4)]; + +static UX_DEVICE *device = UX_NULL; +static UINT device_stall_count = 3; + +static UX_HOST_CLASS_CDC_ACM *host_cdc_acm = UX_NULL; + +static ULONG host_device_insertion_counter = 0; +static ULONG host_device_removal_counter = 0; + +static ULONG enum_counter; + +static ULONG error_counter; +static ULONG error_callback_counter = 0; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_on_set_cfg; +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_enum_mem_alloc_count; + +static ULONG rsc_test_sem_usage; +static ULONG rsc_test_sem_get_count; +static ULONG rsc_test_mutex_usage; +static ULONG rsc_test_mem_alloc_count; + +static UX_DEVICE_CLASS_DUMMY *device_dummy = UX_NULL; +static UX_DEVICE_CLASS_DUMMY_PARAMETER device_dummy_parameter; + + +/* Define device framework. */ + +#define _W0(w) ( (w) & 0xFF) +#define _W1(w) (((w) >> 8) & 0xFF) + +#define _CONFIGURATION_DESCRIPTOR(total_len, n_ifc, cfg_val) \ + 0x09, 0x02, _W0(total_len), _W1(total_len), (n_ifc), (cfg_val), \ + 0x00, 0xc0, 0x32, + +#define _INTERFACE_DESCRIPTOR(ifc_n, alt, n_ep, cls, sub, protocol) \ + 0x09, 0x04, (ifc_n), (alt), (n_ep), (cls), (sub), (protocol), 0x00, + +#define _ENDPOINT_DESCRIPTOR(addr, attr, pktsize, interval) \ + 0x07, 0x05, (addr), (attr), _W0(pktsize), _W1(pktsize), (interval), + +#define _CFG_TOTAL_LEN (9+8 +9+5+4+5+5+7+ 9+7) + +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0xEF bDeviceClass: Composite class code + 0x02 bDeviceSubclass: class sub code + 0x00 bDeviceProtocol: Device protocol + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, /* bLength */ + 0x01, /* bDescriptorType */ + 0x10, 0x01, /* bcdUSB */ + 0xef, /* bDeviceClass - Depends on bDeviceSubClass */ + 0x02, /* bDeviceSubClass - Depends on bDeviceProtocol */ + 0x01, /* bDeviceProtocol - There's an IAD */ + 0x40, /* bMaxPacketSize0 */ + 0x84, 0x84, /* idVendor */ + 0x42, 0x10, /* idProduct */ + 0x00, 0x01, /* bcdDevice */ + 0x01, /* iManufacturer */ + 0x02, /* iProduct */ + 0x03, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ + + _CONFIGURATION_DESCRIPTOR(_CFG_TOTAL_LEN, 1, 1) + + /* Interface Association Descriptor @ 18+9=27 */ + 0x08, /* bLength */ + 0x0b, /* bDescriptorType */ + 0x00, /* bFirstInterface */ + 0x02, /* bInterfaceCount */ + 0x02, /* bFunctionClass - CDC - Communication */ + 0x02, /* bFunctionSubClass - ACM */ + 0x00, /* bFunctionProtocol - No class specific protocol required */ + 0x00, /* iFunction */ + + _INTERFACE_DESCRIPTOR(0, 0, 1, 0x02, 0x02, 0x01) + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + _ENDPOINT_DESCRIPTOR(0x83, 0x03, 8, 0x0B) + + _INTERFACE_DESCRIPTOR(1, 0, 2, 0x0a, 0x00, 0x00) + _ENDPOINT_DESCRIPTOR(0x02, 0x02, 64, 0x00) +}; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_full_speed) +#define device_framework_high_speed device_framework_full_speed + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "AzureRTOS" */ + 0x09, 0x04, 0x01, 9, + 'A','z','u','r','e','R','T','O','S', + + /* Product string descriptor : Index 2 - "Test device" */ + 0x09, 0x04, 0x02, 14, + 'T','e','s','t',' ',' ',' ',' ','d','e','v','i','c','e', + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31, + + /* MAC Address string descriptor : Index 4 - "001E5841B879" */ + 0x09, 0x04, 0x04, 0x0C, + 0x30, 0x30, 0x31, 0x45, 0x35, 0x38, + 0x34, 0x31, 0x42, 0x38, 0x37, 0x39, + +}; + + /* 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +/* Test interactions */ + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT test_slave_change_function(ULONG change) +{ + return 0; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm_inst = (UX_HOST_CLASS_CDC_ACM *) inst; + printf("test_host_change_function: event %lx, cls %p, inst %p\n", event, (void*)cls, (void*)inst); + switch(event) + { + + case UX_DEVICE_INSERTION: + /* Skip control interface. */ + if (cdc_acm_inst->ux_host_class_cdc_acm_interface->ux_interface_descriptor.bInterfaceClass==0x02) + break; + host_device_insertion_counter ++; + host_cdc_acm = cdc_acm_inst; + break; + + case UX_DEVICE_REMOVAL: + /* Skip control interface. */ + if (cdc_acm_inst->ux_host_class_cdc_acm_interface->ux_interface_descriptor.bInterfaceClass==0x02) + break; + host_device_removal_counter ++; + if (host_cdc_acm == cdc_acm_inst) + host_cdc_acm = UX_NULL; + break; + + case UX_DEVICE_CONNECTION: + device = (UX_DEVICE *)inst; + break; + + case UX_DEVICE_DISCONNECTION: + if ((VOID *)device == inst) + device = UX_NULL; + break; + +#if defined(UX_HOST_STANDALONE) + case UX_STANDALONE_WAIT_BACKGROUND_TASK: + tx_thread_relinquish(); + break; +#endif + + default: + break; + } + return 0; +} + +static VOID test_dummy_instance_activate(VOID *dummy_instance) +{ + if (device_dummy == UX_NULL) + device_dummy = (UX_DEVICE_CLASS_DUMMY *)dummy_instance; +} +static VOID test_dummy_instance_deactivate(VOID *dummy_instance) +{ + if ((VOID*)device_dummy == dummy_instance) + device_dummy = UX_NULL; +} +static VOID test_dummy_control_request(UX_DEVICE_CLASS_DUMMY *dummy_instance, UX_SLAVE_TRANSFER *transfer_request) +{ +UINT i; +ULONG cmd_type = transfer_request -> ux_slave_transfer_request_setup[0] | + (transfer_request -> ux_slave_transfer_request_setup[1] << 8); +UCHAR *cmd_buf = transfer_request -> ux_slave_transfer_request_data_pointer; + + if (device_dummy == dummy_instance) + { + + switch(cmd_type) + { + + default: + printf("_dummy_CREQ:"); + for (i = 0; i < 8; i ++) + printf(" %02x", transfer_request -> ux_slave_transfer_request_setup[i]); + printf("\n"); + break; + } + } +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + error_callback_counter ++; +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_enum_sem_get_count = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_msrc_81143_host_cdc_acm_endpoints_get_tests_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + printf("Running MSRC 81143 - Host CDC ACM EPs Get Test...................... "); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* Initialize the free memory pointer */ + stack_pointer = (CHAR *) usbx_memory; + memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 4); + + /* Initialize USBX Memory */ + status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL,0); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_system_initialize failed 0x%x\n", status); + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_host_stack_initialize failed 0x%x\n", status); + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, _ux_host_class_cdc_acm_entry); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_host_stack_class_register failed 0x%x\n", status); + + /* 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, + test_slave_change_function); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_device_stack_initialize failed 0x%x\n", status); + + /* Set the parameters for callback when insertion/extraction of a dummy device. */ + _ux_utility_memory_set(&device_dummy_parameter, 0, sizeof(device_dummy_parameter)); + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_instance_activate = test_dummy_instance_activate; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_instance_deactivate = test_dummy_instance_deactivate; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_control_request = test_dummy_control_request; + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_device_class_dummy_name, + _ux_device_class_dummy_entry, + 1, 0, &device_dummy_parameter); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_device_stack_class_register failed 0x%x\n", status); + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "_ux_test_dcd_sim_slave_initialize failed 0x%x\n", status); + + /* 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); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_host_stack_hcd_register failed 0x%x\n", status); + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_thread_host_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_ASSERT_MESSAGE(status == TX_SUCCESS, "tx_thread_create failed 0x%x\n", status); + + /* Create the main slave simulation thread. */ + stack_pointer += UX_DEMO_STACK_SIZE; + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_ASSERT_MESSAGE(status == TX_SUCCESS, "tx_thread_create failed 0x%x\n", status); + +} + +static UINT _test_check_host_connection_error(VOID) +{ + if (device_dummy && host_cdc_acm) + return(UX_SUCCESS); + if (error_callback_counter >= 7) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_connection_success(VOID) +{ + if (device_dummy && host_cdc_acm) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_disconnection_success(VOID) +{ + if (device_dummy == UX_NULL && host_cdc_acm == UX_NULL) + return(UX_SUCCESS); + return(UX_ERROR); +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +ULONG mem_free; +ULONG loop; +ULONG parameter_u32[64/4]; +USHORT *parameter_u16 = (USHORT*)parameter_u32; +UCHAR *parameter_u8 = (UCHAR*)parameter_u32; +UX_INTERFACE *interface; + + + stepinfo("\n"); + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + status = ux_test_sleep_break_on_success(10000, _test_check_host_connection_error); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT_MESSAGE((host_device_insertion_counter == 0 && host_device_removal_counter == 0), + "Expect no INS(%ld)/RM(%ld) detection\n", host_device_insertion_counter, host_device_removal_counter); + UX_TEST_ASSERT_MESSAGE(device, "Expect device\n"); + UX_TEST_ASSERT_MESSAGE(device -> ux_device_class_instance == UX_NULL, "Expect no device class instance\n"); + interface = device -> ux_device_current_configuration -> ux_configuration_first_interface; + UX_TEST_ASSERT_MESSAGE(interface, "Expect interface\n"); + while(interface) + { + if (interface != device -> ux_device_current_configuration -> ux_configuration_first_interface) + UX_TEST_ASSERT_MESSAGE(interface -> ux_interface_class_instance == UX_NULL, "Expect no interface class instance\n"); + interface = interface -> ux_interface_next_interface; + } + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_device_class_dummy_name, _ux_device_class_dummy_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); + tx_thread_relinquish(); +#else + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); +#endif + } +} diff --git a/test/regression/usbx_msrc_81184_host_audio_desc_validate_test.c b/test/regression/usbx_msrc_81184_host_audio_desc_validate_test.c new file mode 100644 index 00000000..3db3f405 --- /dev/null +++ b/test/regression/usbx_msrc_81184_host_audio_desc_validate_test.c @@ -0,0 +1,1089 @@ +/* This test is designed to test the simple dpump host/device class operation. */ +/* Compile option requires: + -DUX_HOST_CLASS_AUDIO_2_SUPPORT + -DUX_HOST_CLASS_AUDIO_INTERRUPT_SUPPORT + -DUX_SLAVE_REQUEST_CONTROL_MAX_LENGTH=512 +*/ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" + +#include "fx_api.h" + +#include "ux_device_stack.h" +#include "ux_device_class_dummy.h" + +#include "ux_host_class_audio.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_DEMO_REQUEST_MAX_LENGTH \ + ((UX_HCD_SIM_HOST_MAX_PAYLOAD) > (UX_SLAVE_REQUEST_DATA_MAX_LENGTH) ? \ + (UX_HCD_SIM_HOST_MAX_PAYLOAD) : (UX_SLAVE_REQUEST_DATA_MAX_LENGTH)) + +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_DEMO_REQUEST_MAX_LENGTH + 1) +#define UX_DEMO_MEMORY_SIZE (128*1024) + +#define UX_TEST_LOG_SIZE (64) + + +/* Define local/extern function prototypes. */ +static void test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static void tx_test_thread_host_simulation_entry(ULONG); +static void tx_test_thread_slave_simulation_entry(ULONG); + +static TX_EVENT_FLAGS_GROUP tx_test_events; + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[64]; + +static UX_HOST_CLASS_AUDIO *host_audio_tx = UX_NULL; +static UX_HOST_CLASS_AUDIO *host_audio_rx = UX_NULL; + +static UX_HOST_CLASS_AUDIO *audio = UX_NULL; + +static UX_DEVICE_CLASS_DUMMY *dummy[3]; +static UX_DEVICE_CLASS_DUMMY_PARAMETER dummy_parameter; + +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_mem_alloc_cnt_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_enum_mem_alloc_count; + +static ULONG rsc_audio_sem_usage; +static ULONG rsc_audio_sem_get_count; +static ULONG rsc_audio_mutex_usage; +static ULONG rsc_audio_mem_usage; +static ULONG rsc_audio_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +/* Define device framework. */ + +#define D3(d) ((UCHAR)((d) >> 24)) +#define D2(d) ((UCHAR)((d) >> 16)) +#define D1(d) ((UCHAR)((d) >> 8)) +#define D0(d) ((UCHAR)((d) >> 0)) + +static unsigned char device_framework_full_speed[] = { + +/* --------------------------------------- Device Descriptor */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x02, 0x00, +/* 12 bcdDevice */ D0(0x200),D1(0x200), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* ----------------------------- Device Qualifier Descriptor *//* @18 */ +/* 0 bLength, bDescriptorType */ 10, 0x06, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 bNumConfigurations */ 1, +/* 9 bReserved */ 0, + +/* -------------------------------- Configuration Descriptor *//* 9+8+135+55+62=269 *//* @28 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(269),D1(269), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------ Interface Association Descriptor *//* @37 */ +/* 0 bLength, bDescriptorType */ 8, 0x0B, +/* 2 bFirstInterface, bInterfaceCount */ 0, 3, +/* 4 bFunctionClass, bFunctionSubClass, bFunctionProtocol */ 0x01, 0x00, 0x20, +/* 7 iFunction */ 0, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+126=135) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x20, +/* 8 iInterface */ 0, +/* ---------------- Audio 2.0 AC Interface Header Descriptor *//* (9+8+8+7+17*2+18*2+12*2=126) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x01, +/* 3 bcdADC, bCategory */ D0(0x200),D1(0x200), 0x08, +/* 6 wTotalLength */ D0(126),D1(126), +/* 8 bmControls */ 0x00, +/* -------------------- Audio 2.0 AC Clock Source Descriptor (0x11) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x24, 0x0A, +/* 3 bClockID, bmAttributes, bmControls */ 0x11, 0x05, 0x01, +/* 6 bAssocTerminal, iClockSource */ 0x00, 0, +/* -------------------- Audio 2.0 AC Clock Selector Descriptor (1x1, 0x12) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x24, 0x0B, +/* 3 bClockID, bNrInPins, baCSourceID1 */ 0x12, 0x01, 0x11, +/* 6 bmControls, iClockSelector */ 0x01, 0, +/* -------------------- Audio 2.0 AC Clock Multiplier Descriptor (0x10) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x0C, +/* 3 bClockID, bCSourceID, bmControls */ 0x10, 0x12, 0x05, +/* 6 iClockMultiplier */ 0, +/* ------------------- Audio 2.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 17, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, bCSourceID */ 0x00, 0x10, +/* 8 bNrChannels, bmChannelConfig */ 0x02, D0(0),D1(0),D2(0),D3(0), +/* 13 iChannelNames, bmControls, iTerminal */ 0, D0(0),D1(0), 0, +/* --------------------- Audio 2.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 18, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bmaControls(0), bmaControls(...) ... */ D0(0xF),D1(0xF),D2(0xF),D3(0xF), D0(0),D1(0),D2(0),D3(0), D0(0),D1(0),D2(0),D3(0), +/* . iFeature */ 0, +/* ------------------ Audio 2.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID, bCSourceID */ 0x00, 0x02, 0x10, +/* 9 bmControls, iTerminal */ D0(0),D1(0), 0, +/* ------------------- Audio 2.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 17, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bCSourceID */ 0x00, 0x10, +/* 8 bNrChannels, bmChannelConfig */ 0x02, D0(0),D1(0),D2(0),D3(0), +/* 13 iChannelNames, bmControls, iTerminal */ 0, D0(0),D1(0), 0, +/* --------------------- Audio 2.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 18, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bmaControls(0), bmaControls(...) ... */ D0(0xF),D1(0xF),D2(0xF),D3(0xF), D0(0),D1(0),D2(0),D3(0), D0(0),D1(0),D2(0),D3(0), +/* . iFeature */ 0, +/* ------------------ Audio 2.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID, bCSourceID */ 0x00, 0x05, 0x10, +/* 9 bmControls, iTerminal */ D0(0),D1(0), 0, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+16+6+7+8=55) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------ Audio 2.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 16, 0x24, 0x01, +/* 3 bTerminalLink, bmControls */ 0x03,0x00, +/* 5 bFormatType, bmFormats */ 0x01,D0(1),D1(1),D2(1),D3(1), +/* 10 bNrChannels, bmChannelConfig */ 2, D0(0),D1(0),D2(0),D3(0), +/* 15 iChannelNames */ 0, +/* -------------------- Audio 2.0 AS Format Type I Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 6, 0x24, 0x02, +/* 3 bFormatType, bSubslotSize, bBitResolution */ 0x01, 2, 16, +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x0D, +/* 4 wMaxPacketSize, bInterval */ D0(256),D1(256), 1, +/* ---------- Audio 2.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x25, 0x01, +/* 3 bmAttributes, bmControls */ 0x00, 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+16+6+7+8+7=62) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 2, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------ Audio 2.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 16, 0x24, 0x01, +/* 3 bTerminalLink, bmControls */ 0x04,0x00, +/* 5 bFormatType, bmFormats */ 0x01,D0(1),D1(1),D2(1),D3(1), +/* 10 bNrChannels, bmChannelConfig */ 2, D0(0),D1(0),D2(0),D3(0), +/* 15 iChannelNames */ 0, +/* ---------------------- Audio 2.0 AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 6, 0x24, 0x02, +/* 3 bFormatType, bSubslotSize, bBitResolution */ 0x01, 2, 16, +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x0D, +/* 4 wMaxPacketSize, bInterval */ D0(256),D1(256), 1, +/* ---------- Audio 2.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x25, 0x01, +/* 3 bmAttributes, bmControls */ 0x00, 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x82, 0x11, +/* 4 wMaxPacketSize, bInterval */ D0(4),D1(4), 1, + +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +#define FRAMEWORK_POS_FULL_SPEED_IAD (37) + +static unsigned char device_framework_full_speed_iad_audio10[] = { + +/* --------------------------------------- Device Descriptor *//* @0 */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 0x08, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x01, 0x00, +/* 12 bcdDevice */ D0(0x100),D1(0x100), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* -------------------------------- Configuration Descriptor *//* 9+8+88+52*2=209 *//* @18 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(209),D1(209), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------ Interface Association Descriptor *//* @27 */ +/* 0 bLength, bDescriptorType */ 8, 0x0B, +/* 2 bFirstInterface, bInterfaceCount */ 0, 3, +/* 4 bFunctionClass, bFunctionSubClass, bFunctionProtocol */ 0x01, 0x01, 0x00, +/* 7 iFunction */ 0, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+72+7=88) *//* @35 */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x00, +/* 8 iInterface */ 0, +/* ---------------- Audio 1.0 AC Interface Header Descriptor *//* (10+12*2+10*2+9*2=72) *//* @44 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x01, +/* 3 bcdADC */ 0x00, 0x01, +/* 5 wTotalLength, bInCollection */ D0(72),D1(72), 2, +/* 8 baInterfaceNr(1) ... baInterfaceNr(n) */ 1, 2, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x02, +/* 8 iTerminal */ 0, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x05, +/* 8 iTerminal */ 0, +/* --------------------- Audio 1.0 AC INT Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x83, 0x03, +/* 4 wMaxPacketSize, bInterval */ D0(8),D1(8), 1, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x03, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 1, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x04, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 1, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +}; +#define FRAMEWORK_POS_FULL_SPEED_AC10 (44) +static UCHAR device_framework_modified[2048]; + +static unsigned char device_framework_high_speed[] = { +/* --------------------------------------- Device Descriptor */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 0x08, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x02, 0x00, +/* 12 bcdDevice */ D0(0x200),D1(0x200), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* ----------------------------- Device Qualifier Descriptor */ +/* 0 bLength, bDescriptorType */ 10, 0x06, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 bNumConfigurations */ 1, +/* 9 bReserved */ 0, + +/* -------------------------------- Configuration Descriptor *//* 9+8+135+55+62=269 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(269),D1(269), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------ Interface Association Descriptor */ +/* 0 bLength, bDescriptorType */ 8, 0x0B, +/* 2 bFirstInterface, bInterfaceCount */ 0, 3, +/* 4 bFunctionClass, bFunctionSubClass, bFunctionProtocol */ 0x01, 0x00, 0x20, +/* 7 iFunction */ 0, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+126=135) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x20, +/* 8 iInterface */ 0, +/* ---------------- Audio 2.0 AC Interface Header Descriptor *//* (9+8+8+7+17*2+18*2+12*2=126) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x01, +/* 3 bcdADC, bCategory */ D0(0x200),D1(0x200), 0x08, +/* 6 wTotalLength */ D0(126),D1(126), +/* 8 bmControls */ 0x00, +/* -------------------- Audio 2.0 AC Clock Source Descriptor (0x11) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x24, 0x0A, +/* 3 bClockID, bmAttributes, bmControls */ 0x11, 0x05, 0x01, +/* 6 bAssocTerminal, iClockSource */ 0x00, 0, +/* -------------------- Audio 2.0 AC Clock Selector Descriptor (1x1, 0x12) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x24, 0x0B, +/* 3 bClockID, bNrInPins, baCSourceID1 */ 0x12, 0x01, 0x11, +/* 6 bmControls, iClockSelector */ 0x01, 0, +/* -------------------- Audio 2.0 AC Clock Multiplier Descriptor (0x10) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x0C, +/* 3 bClockID, bCSourceID, bmControls */ 0x10, 0x12, 0x05, +/* 6 iClockMultiplier */ 0, +/* ------------------- Audio 2.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 17, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, bCSourceID */ 0x00, 0x10, +/* 8 bNrChannels, bmChannelConfig */ 0x02, D0(0),D1(0),D2(0),D3(0), +/* 13 iChannelNames, bmControls, iTerminal */ 0, D0(0),D1(0), 0, +/* --------------------- Audio 2.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 18, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bmaControls(0), bmaControls(...) ... */ D0(0xF),D1(0xF),D2(0xF),D3(0xF), D0(0),D1(0),D2(0),D3(0), D0(0),D1(0),D2(0),D3(0), +/* . iFeature */ 0, +/* ------------------ Audio 2.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID, bCSourceID */ 0x00, 0x02, 0x10, +/* 9 bmControls, iTerminal */ D0(0),D1(0), 0, +/* ------------------- Audio 2.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 17, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bCSourceID */ 0x00, 0x10, +/* 8 bNrChannels, bmChannelConfig */ 0x02, D0(0),D1(0),D2(0),D3(0), +/* 13 iChannelNames, bmControls, iTerminal */ 0, D0(0),D1(0), 0, +/* --------------------- Audio 2.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 18, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bmaControls(0), bmaControls(...) ... */ D0(0xF),D1(0xF),D2(0xF),D3(0xF), D0(0),D1(0),D2(0),D3(0), D0(0),D1(0),D2(0),D3(0), +/* . iFeature */ 0, +/* ------------------ Audio 2.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID, bCSourceID */ 0x00, 0x05, 0x10, +/* 9 bmControls, iTerminal */ D0(0),D1(0), 0, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+16+6+7+8=55) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------ Audio 2.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 16, 0x24, 0x01, +/* 3 bTerminalLink, bmControls */ 0x03,0x00, +/* 5 bFormatType, bmFormats */ 0x01,D0(1),D1(1),D2(1),D3(1), +/* 10 bNrChannels, bmChannelConfig */ 2, D0(0),D1(0),D2(0),D3(0), +/* 15 iChannelNames */ 0, +/* -------------------- Audio 2.0 AS Format Type I Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 6, 0x24, 0x02, +/* 3 bFormatType, bSubslotSize, bBitResolution */ 0x01, 2, 16, +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x0D, +/* 4 wMaxPacketSize, bInterval */ D0(256),D1(256), 4, +/* ---------- Audio 2.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x25, 0x01, +/* 3 bmAttributes, bmControls */ 0x00, 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+16+6+7+8+7=62) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 2, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------ Audio 2.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 16, 0x24, 0x01, +/* 3 bTerminalLink, bmControls */ 0x04,0x00, +/* 5 bFormatType, bmFormats */ 0x01,D0(1),D1(1),D2(1),D3(1), +/* 10 bNrChannels, bmChannelConfig */ 2, D0(0),D1(0),D2(0),D3(0), +/* 15 iChannelNames */ 0, +/* ---------------------- Audio 2.0 AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 6, 0x24, 0x02, +/* 3 bFormatType, bSubslotSize, bBitResolution */ 0x01, 2, 16, +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x0D, +/* 4 wMaxPacketSize, bInterval */ D0(256),D1(256), 4, +/* ---------- Audio 2.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x25, 0x01, +/* 3 bmAttributes, bmControls */ 0x00, 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x82, 0x11, +/* 4 wMaxPacketSize, bInterval */ D0(4),D1(4), 1, + +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + +/* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + +/* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + +/* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; +static UX_TEST_SETUP _GetCfgDescr = UX_TEST_SETUP_GetCfgDescr; +static UX_TEST_SETUP _SetAddress = UX_TEST_SETUP_SetAddress; +static UX_TEST_SETUP _GetDeviceDescriptor = UX_TEST_SETUP_GetDevDescr; +static UX_TEST_SETUP _GetConfigDescriptor = UX_TEST_SETUP_GetCfgDescr; + +/* Interaction define */ + +/* Hooks define */ + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* 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 ++; + printf("Error #%d, system_level: %d, system_context: %d, error_code: 0x%x\n", __LINE__, system_level, system_context, error_code); + + if (!error_callback_ignore) + { + { + /* Failed test. */ + 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_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_AUDIO *audio = (UX_HOST_CLASS_AUDIO *) inst; + + // printf("CHG:%lx,%p,%p\n", event, cls, inst); + switch(event) + { + + case UX_DEVICE_INSERTION: + + // printf("hINS:%p,%p:%lx\n", cls, inst, ux_host_class_audio_type_get(audio)); + if (ux_host_class_audio_subclass_get(audio) != UX_HOST_CLASS_AUDIO_CLASS) + { + if (ux_host_class_audio_type_get(audio) == UX_HOST_CLASS_AUDIO_INPUT) + host_audio_rx = audio; + else + host_audio_tx = audio; + } + break; + + case UX_DEVICE_REMOVAL: + + // printf("hRMV:%p,%p:%lx\n", cls, inst, ux_host_class_audio_type_get(audio)); + if (ux_host_class_audio_subclass_get(audio) != UX_HOST_CLASS_AUDIO_CLASS) + { + if (audio == host_audio_rx) + host_audio_rx = UX_NULL; + if (audio == host_audio_tx) + host_audio_tx = UX_NULL; + } + break; + + default: + break; + } + return 0; +} + + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_mem_free_on_set_cfg = ux_test_regular_memory_free(); + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_msrc_81184_host_audio_desc_validate_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running Audio 2.0 Host Basic Functionality Test..................... "); + +#if !UX_TEST_MULTI_IFC_ON || !UX_TEST_MULTI_ALT_ON || !UX_TEST_MULTI_CLS_ON || \ + !defined(UX_HOST_CLASS_AUDIO_2_SUPPORT) || \ + !defined(UX_HOST_CLASS_AUDIO_INTERRUPT_SUPPORT) || \ + (UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH < 260) + printf("SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + + stepinfo("\n"); + + /* 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(); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* 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_host_change_function); + UX_TEST_CHECK_SUCCESS(status); + + /* Register Audio class. */ + status = ux_host_stack_class_register(_ux_system_host_class_audio_name, ux_host_class_audio_entry); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Set the parameters for DUMMY. */ + ux_utility_memory_set(&dummy_parameter, 0, sizeof(UX_DEVICE_CLASS_DUMMY_PARAMETER)); + + /* Initialize the device DUMMY class. This class owns interfaces starting with 0, 1, 2. */ + status = ux_device_stack_class_register(_ux_device_class_dummy_name, _ux_device_class_dummy_entry, + 1, 0, &dummy_parameter); + UX_TEST_CHECK_SUCCESS(status); + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main event group. */ + status = tx_event_flags_create(&tx_test_events, "tx_test_events"); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx demo host simulation", tx_test_thread_host_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx demo slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_CHECK_SUCCESS(status); +} + +static UINT test_wait_until_expected(VOID **ptr, ULONG loop, VOID *expected) +{ + while(loop) + { + _ux_utility_delay_ms(10); + if (*ptr == expected) + return UX_SUCCESS; + } + return UX_ERROR; +} +static UINT test_wait_until_not_expected(VOID **ptr, ULONG loop, VOID *expected) +{ + while(loop) + { + _ux_utility_delay_ms(10); + if (*ptr != expected) + return UX_SUCCESS; + } + return UX_ERROR; +} +#define test_wait_until_not_null(ptr, loop) test_wait_until_not_expected(ptr, loop, UX_NULL) +#define test_wait_until_null(ptr, loop) test_wait_until_expected(ptr, loop, UX_NULL) + +static void _memory_tests(void) +{ +ULONG test_n; +ULONG mem_free; + + /* Test disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Reset testing counts. */ + ux_test_utility_sim_mutex_create_count_reset(); + ux_test_utility_sim_sem_create_count_reset(); + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + /* Save free memory usage. */ + mem_free = ux_test_regular_memory_free(); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + tx_thread_sleep(100); + /* Log create counts for further tests. */ + rsc_enum_mutex_usage = rsc_mutex_on_set_cfg; + rsc_enum_sem_usage = rsc_sem_on_set_cfg; + rsc_enum_mem_usage = mem_free - rsc_mem_free_on_set_cfg; + rsc_enum_mem_alloc_count = rsc_mem_alloc_cnt_on_set_cfg; + /* Log create counts when instances active for further tests. */ + rsc_audio_mutex_usage = ux_test_utility_sim_mutex_create_count() - rsc_enum_mutex_usage; + rsc_audio_sem_usage = ux_test_utility_sim_sem_create_count() - rsc_enum_sem_usage; + rsc_audio_mem_usage = rsc_mem_free_on_set_cfg - ux_test_regular_memory_free(); + rsc_audio_mem_alloc_count = ux_test_utility_sim_mem_alloc_count() - rsc_enum_mem_alloc_count; + stepinfo("mem free: %ld\n", ux_test_regular_memory_free()); + + /* Lock log base for tests. */ + ux_test_utility_sim_mem_alloc_log_lock(); + + stepinfo("enum mem: %ld\n", rsc_enum_mem_alloc_count); + stepinfo("cdc mem : %ld\n", rsc_audio_mem_alloc_count); + stepinfo("mem free: %ld, %ld\n", ux_test_regular_memory_free(), _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available); + + /* Simulate detach and attach for FS enumeration, + and check if there is memory error in normal enumeration. + */ + stepinfo(">>>>>>>>>>>> Enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < 3; test_n++) + { + stepinfo("%4ld / 2\n", test_n); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = ux_test_regular_memory_free(); + else if (mem_free != ux_test_regular_memory_free()) + { + + printf("ERROR #11.%ld: Memory level different after re-enumerations %ld <> %ld\n", test_n, mem_free, ux_test_regular_memory_free()); + test_control_return(1); + } + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on error. */ + ux_test_breakable_sleep(100, sleep_break_on_error); + + /* Check */ + if (!host_audio_tx || !host_audio_rx) + { + + printf("ERROR #12.%ld: Enumeration fail\n", test_n); + test_control_return(1); + } + } + + /* Simulate detach and attach for FS enumeration, + and test possible memory allocation error handlings. + */ + if (rsc_audio_mem_alloc_count) stepinfo(">>>>>>>>>>>> Memory errors enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_audio_mem_alloc_count; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_audio_mem_alloc_count - 1); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = ux_test_regular_memory_free(); + else if (mem_free != ux_test_regular_memory_free()) + { + + printf("ERROR #11.%ld: Memory level different after re-enumerations %ld <> %ld\n", test_n, mem_free, ux_test_regular_memory_free()); + test_control_return(1); + } + + /* Set memory error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n + rsc_enum_mem_alloc_count); + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on errors. */ + ux_test_breakable_sleep(100, sleep_break_on_error); + + /* Check error */ + if (host_audio_tx && host_audio_rx) + { + + printf("ERROR #12.%ld: device detected when there is memory error\n", test_n); + test_control_return(1); + } + stepinfo("mem free: %ld\n", ux_test_regular_memory_free()); + } + ux_test_utility_sim_mem_alloc_error_generation_stop(); + if (rsc_audio_mem_alloc_count) stepinfo("\n"); +} + +static void _audio_desc_tests(void) +{ +ULONG mem_free; + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + UX_TEST_ASSERT(host_audio_rx == UX_NULL && host_audio_tx == UX_NULL); + + /* Set framework. */ + _ux_system_slave -> ux_system_slave_device_framework_full_speed = device_framework_modified; + + stepinfo(">>>>>>>>>> Fake descriptor tests - IAD::bInterfaceCount\n"); + + /* Prepare descriptor IAD. */ + _ux_utility_memory_copy(device_framework_modified, device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED); + UX_TEST_ASSERT(device_framework_modified[FRAMEWORK_POS_FULL_SPEED_IAD] == 0x08); + UX_TEST_ASSERT(device_framework_modified[FRAMEWORK_POS_FULL_SPEED_IAD + 1] == 0x0B); + UX_TEST_ASSERT(device_framework_modified[FRAMEWORK_POS_FULL_SPEED_IAD + 3] >= 0x02);/* bInterfaceCount */ + + /* Log memory. */ + mem_free = ux_test_regular_memory_free(); + + stepinfo(">>>>>>>>>> Fake descriptor tests - IAD::bInterfaceCount = 0\n"); + device_framework_modified[FRAMEWORK_POS_FULL_SPEED_IAD + 3] = 0; + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + /* Wait and break on error. */ + ux_test_breakable_sleep(100, sleep_break_on_error); + /* Check connection. */ + UX_TEST_ASSERT(host_audio_rx == UX_NULL && host_audio_tx == UX_NULL); + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + /* Check memory. */ + UX_TEST_ASSERT(mem_free == ux_test_regular_memory_free()); + + stepinfo(">>>>>>>>>> Fake descriptor tests - IAD::bInterfaceCount = 1\n"); + device_framework_modified[FRAMEWORK_POS_FULL_SPEED_IAD + 3] = 1; + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + /* Wait and break on error. */ + ux_test_breakable_sleep(100, sleep_break_on_error); + /* Check connection. */ + UX_TEST_ASSERT(host_audio_rx == UX_NULL && host_audio_tx == UX_NULL); + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + /* Check memory. */ + UX_TEST_ASSERT(mem_free == ux_test_regular_memory_free()); + + /* Prepare descriptor AC Header. */ + _ux_utility_memory_copy(device_framework_modified, device_framework_full_speed_iad_audio10, sizeof(device_framework_full_speed_iad_audio10)); + UX_TEST_ASSERT(device_framework_modified[FRAMEWORK_POS_FULL_SPEED_AC10] == 0x0a); /* bLength */ + UX_TEST_ASSERT(device_framework_modified[FRAMEWORK_POS_FULL_SPEED_AC10 + 1] == 0x24); + UX_TEST_ASSERT(device_framework_modified[FRAMEWORK_POS_FULL_SPEED_AC10 + 7] == 0x02);/* bInCollection */ + + stepinfo(">>>>>>>>>> Fake descriptor tests - AC_Header::bInCollection = 0\n"); + device_framework_modified[FRAMEWORK_POS_FULL_SPEED_AC10 + 7] = 0; + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + /* Wait and break on error. */ + ux_test_breakable_sleep(100, sleep_break_on_error); + /* Check connection. */ + UX_TEST_ASSERT(host_audio_rx == UX_NULL && host_audio_tx == UX_NULL); + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + /* Check memory. */ + UX_TEST_ASSERT(mem_free == ux_test_regular_memory_free()); + + /* Set framework back. */ + _ux_system_slave -> ux_system_slave_device_framework_full_speed = device_framework_full_speed; +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +UCHAR test_tmp[32]; +ULONG temp; + + /* Test connect. */ + status = test_wait_until_not_null((void**)&host_audio_rx, 100); + status |= test_wait_until_not_null((void**)&host_audio_tx, 100); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(ux_host_class_audio_protocol_get(host_audio_rx) == UX_HOST_CLASS_AUDIO_PROTOCOL_IP_VERSION_02_00); + UX_TEST_ASSERT(ux_host_class_audio_type_get(host_audio_rx) == UX_HOST_CLASS_AUDIO_INPUT); + UX_TEST_ASSERT(ux_host_class_audio_speed_get(host_audio_rx) == UX_FULL_SPEED_DEVICE); + + _audio_desc_tests(); + _memory_tests(); + + /* Wait pending threads. */ + _ux_utility_thread_sleep(1); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + ux_device_stack_class_unregister(_ux_device_class_dummy_name, _ux_device_class_dummy_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + while(1) + { + +#if UX_DEMO_FEEDBACK + UINT status; + ULONG events; + status = tx_event_flags_get(&tx_test_events, 0x1u, TX_OR_CLEAR, &events, 10); + if (status == UX_SUCCESS) + { + /* Simulate ISO transfer done event. */ + feedback_transfer -> ux_transfer_request_completion_code = UX_SUCCESS; + if (feedback_transfer -> ux_transfer_request_completion_function) + feedback_transfer -> ux_transfer_request_completion_function(feedback_transfer); + _ux_host_semaphore_put(&feedback_transfer -> ux_transfer_request_semaphore); + ux_utility_delay_ms(1); + } +#else + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); +#endif + } +} diff --git a/test/regression/usbx_msrc_81206_81225_ecm_multiple_data_reject_test.c b/test/regression/usbx_msrc_81206_81225_ecm_multiple_data_reject_test.c new file mode 100644 index 00000000..f3642d78 --- /dev/null +++ b/test/regression/usbx_msrc_81206_81225_ecm_multiple_data_reject_test.c @@ -0,0 +1,426 @@ +/* Include necessary system files. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static UCHAR device_is_finished; + +#define CFG_DESC_POS (0x12) +static unsigned char local_device_framework[] = { + + /* Device Descriptor */ + 0x12, /* bLength */ + 0x01, /* bDescriptorType */ + 0x10, 0x01, /* bcdUSB */ + 0xef, /* bDeviceClass - Depends on bDeviceSubClass */ + 0x02, /* bDeviceSubClass - Depends on bDeviceProtocol */ + 0x01, /* bDeviceProtocol - There's an IAD */ + 0x40, /* bMaxPacketSize0 */ + 0x70, 0x07, /* idVendor */ + 0x42, 0x10, /* idProduct */ + 0x00, 0x01, /* bcdDevice */ + 0x01, /* iManufacturer */ + 0x02, /* iProduct */ + 0x03, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ + + /* Configuration Descriptor @ 18 */ + 0x09, /* bLength */ + 0x02, /* bDescriptorType */ + 0x79, 0x00, /* wTotalLength */ + 0x02, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xc0, /* bmAttributes - Self-powered */ + 0x00, /* bMaxPower */ + + /* Interface Association Descriptor @ 18+9=27 */ + 0x08, /* bLength */ + 0x0b, /* bDescriptorType */ + 0x00, /* bFirstInterface */ + 0x03, /* bInterfaceCount */ + 0x02, /* bFunctionClass - CDC - Communication */ + 0x06, /* bFunctionSubClass - ECM */ + 0x00, /* bFunctionProtocol - No class specific protocol required */ + 0x00, /* iFunction */ + + /* Interface Descriptor @ 27+8=35 */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x02, /* bInterfaceClass - CDC - Communication */ + 0x06, /* bInterfaceSubClass - ECM */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* CDC Header Functional Descriptor @ 35+9=44 */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x00, /* bDescriptorSubType */ + 0x10, 0x01, /* bcdCDC */ + + /* CDC ECM Functional Descriptor @ 44+5=49 */ + 0x0d, /* bLength */ + 0x24, /* bDescriptorType */ + 0x0f, /* bDescriptorSubType */ + 0x04, /* iMACAddress */ + 0x00, 0x00, 0x00, 0x00, /* bmEthernetStatistics */ + 0xea, 0x05, /* wMaxSegmentSize */ + 0x00, 0x00, /* wNumberMCFilters */ + 0x00, /* bNumberPowerFilters */ + + /* CDC Union Functional Descriptor @ 49+13=62 */ + 0x06, /* bLength */ + 0x24, /* bDescriptorType */ + 0x06, /* bDescriptorSubType */ + 0x00, /* bmMasterInterface */ + 0x01, /* bmSlaveInterface0 */ + 0x02, /* bmSlaveInterface1 */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x83, /* bEndpointAddress */ + 0x03, /* bmAttributes - Interrupt */ + 0x08, 0x00, /* wMaxPacketSize */ + 0x08, /* bInterval */ + + /* Data 0 (9+9+7+7=32) */ + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x01, /* bAlternateSetting */ + 0x02, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x02, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x81, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + + /* Data 1 (9+9+7+7=32) */ + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x02, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x02, /* bInterfaceNumber */ + 0x01, /* bAlternateSetting */ + 0x02, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x04, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x85, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ +}; + +static UX_TEST_SETUP _GetConfigDescriptor = UX_TEST_SETUP_GetCfgDescr; +static UX_TEST_HCD_SIM_ACTION replace_configuration_descriptor[] = { +{ .usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + .function = UX_HCD_TRANSFER_REQUEST, + .req_setup = &_GetConfigDescriptor, + .req_action = UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, + .req_ep_address = 0, + .req_data = (local_device_framework + CFG_DESC_POS), + .req_actual_len = 9, + .req_status = UX_SUCCESS, + .status = UX_SUCCESS, + .action_func = UX_NULL, + .no_return = UX_FALSE +}, +{ .usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + .function = UX_HCD_TRANSFER_REQUEST, + .req_setup = &_GetConfigDescriptor, + .req_action = UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, + .req_ep_address = 0, + .req_data = (local_device_framework + CFG_DESC_POS), + .req_actual_len = sizeof(local_device_framework) - CFG_DESC_POS, + .req_status = UX_SUCCESS, + .status = UX_SUCCESS, + .action_func = UX_NULL, + .no_return = UX_FALSE +}, +{ .usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + .function = UX_HCD_TRANSFER_REQUEST, + .req_setup = &_GetConfigDescriptor, + .req_action = UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, + .req_ep_address = 0, + .req_data = (local_device_framework + CFG_DESC_POS), + .req_actual_len = 9, + .req_status = UX_SUCCESS, + .status = UX_SUCCESS, + .action_func = UX_NULL, + .no_return = UX_FALSE +}, +{ .usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + .function = UX_HCD_TRANSFER_REQUEST, + .req_setup = &_GetConfigDescriptor, + .req_action = UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, + .req_ep_address = 0, + .req_data = (local_device_framework + CFG_DESC_POS), + .req_actual_len = sizeof(local_device_framework) - CFG_DESC_POS, + .req_status = UX_SUCCESS, + .status = UX_SUCCESS, + .action_func = UX_NULL, + .no_return = UX_FALSE +}, +{ .usbx_function = UX_TEST_OVERRIDE_ERROR_CALLBACK, + .system_level = UX_SYSTEM_LEVEL_THREAD, + .system_context = UX_SYSTEM_CONTEXT_CLASS, + .error_code = UX_DESCRIPTOR_CORRUPTED, + .no_return = 1, +}, +{ .usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + .function = UX_HCD_TRANSFER_REQUEST, + .req_setup = &_GetConfigDescriptor, + .req_action = UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, + .req_ep_address = 0, + .req_data = (local_device_framework + CFG_DESC_POS), + .req_actual_len = 9, + .req_status = UX_SUCCESS, + .status = UX_SUCCESS, + .action_func = UX_NULL, + .no_return = UX_FALSE +}, +{ .usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + .function = UX_HCD_TRANSFER_REQUEST, + .req_setup = &_GetConfigDescriptor, + .req_action = UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, + .req_ep_address = 0, + .req_data = (local_device_framework + CFG_DESC_POS), + .req_actual_len = sizeof(local_device_framework) - CFG_DESC_POS, + .req_status = UX_SUCCESS, + .status = UX_SUCCESS, + .action_func = UX_NULL, + .no_return = UX_FALSE +}, +{ .usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + .function = UX_HCD_TRANSFER_REQUEST, + .req_setup = &_GetConfigDescriptor, + .req_action = UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, + .req_ep_address = 0, + .req_data = (local_device_framework + CFG_DESC_POS), + .req_actual_len = 9, + .req_status = UX_SUCCESS, + .status = UX_SUCCESS, + .action_func = UX_NULL, + .no_return = UX_FALSE +}, +{ .usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + .function = UX_HCD_TRANSFER_REQUEST, + .req_setup = &_GetConfigDescriptor, + .req_action = UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, + .req_ep_address = 0, + .req_data = (local_device_framework + CFG_DESC_POS), + .req_actual_len = sizeof(local_device_framework) - CFG_DESC_POS, + .req_status = UX_SUCCESS, + .status = UX_SUCCESS, + .action_func = UX_NULL, + .no_return = UX_FALSE +}, +{ .usbx_function = UX_TEST_OVERRIDE_ERROR_CALLBACK, + .system_level = UX_SYSTEM_LEVEL_THREAD, + .system_context = UX_SYSTEM_CONTEXT_CLASS, + .error_code = UX_DESCRIPTOR_CORRUPTED, + .no_return = 1, +}, +{ .usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + .function = UX_HCD_TRANSFER_REQUEST, + .req_setup = &_GetConfigDescriptor, + .req_action = UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, + .req_ep_address = 0, + .req_data = (local_device_framework + CFG_DESC_POS), + .req_actual_len = 9, + .req_status = UX_SUCCESS, + .status = UX_SUCCESS, + .action_func = UX_NULL, + .no_return = UX_FALSE +}, +{ .usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + .function = UX_HCD_TRANSFER_REQUEST, + .req_setup = &_GetConfigDescriptor, + .req_action = UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, + .req_ep_address = 0, + .req_data = (local_device_framework + CFG_DESC_POS), + .req_actual_len = sizeof(local_device_framework) - CFG_DESC_POS, + .req_status = UX_SUCCESS, + .status = UX_SUCCESS, + .action_func = UX_NULL, + .no_return = UX_FALSE +}, +{ .usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + .function = UX_HCD_TRANSFER_REQUEST, + .req_setup = &_GetConfigDescriptor, + .req_action = UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, + .req_ep_address = 0, + .req_data = (local_device_framework + CFG_DESC_POS), + .req_actual_len = 9, + .req_status = UX_SUCCESS, + .status = UX_SUCCESS, + .action_func = UX_NULL, + .no_return = UX_FALSE +}, +{ .usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + .function = UX_HCD_TRANSFER_REQUEST, + .req_setup = &_GetConfigDescriptor, + .req_action = UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, + .req_ep_address = 0, + .req_data = (local_device_framework + CFG_DESC_POS), + .req_actual_len = sizeof(local_device_framework) - CFG_DESC_POS, + .req_status = UX_SUCCESS, + .status = UX_SUCCESS, + .action_func = UX_NULL, + .no_return = UX_FALSE +}, +{ .usbx_function = UX_TEST_OVERRIDE_ERROR_CALLBACK, + .system_level = UX_SYSTEM_LEVEL_THREAD, + .system_context = UX_SYSTEM_CONTEXT_CLASS, + .error_code = UX_DESCRIPTOR_CORRUPTED, + .no_return = 1, +}, +{ .usbx_function = UX_TEST_OVERRIDE_ERROR_CALLBACK, + .system_level = UX_SYSTEM_LEVEL_THREAD, + .system_context = UX_SYSTEM_CONTEXT_ROOT_HUB, + .error_code = UX_DEVICE_ENUMERATION_FAILURE, + .no_return = 1, +}, +{ 0 } +}; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_msrc_81206_81225_cdc_ecm_2_data_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running MSRC 81206 & 81225 - CDC ECM 2 Data IFC Test................ "); + + stepinfo("\n"); + + // ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED)); + // ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED)); + // ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED)); + // ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE)); + ux_test_cdc_ecm_initialize_use_framework(first_unused_memory, &default_device_init_data); +} + +static UINT _wait_host_inst_change_to(ULONG loop, UCHAR available) +{ + while(loop --) + { + _ux_utility_delay_ms(10); + if (available) + { + if (cdc_ecm_host_from_system_change_function != UX_NULL) + return UX_SUCCESS; + } + else + { + if (cdc_ecm_host_from_system_change_function == UX_NULL) + return UX_SUCCESS; + } + } + return UX_ERROR; +} + +static void post_init_host() +{ +ULONG mem_free; +UINT i; + + /* Wait connection. */ + UX_TEST_CHECK_SUCCESS(_wait_host_inst_change_to(100, 1)); + + /* Disconnect. */ + stepinfo(">>>>>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_disconnect_slave(); + ux_test_disconnect_host_wait_for_enum_completion(); + UX_TEST_CHECK_SUCCESS(_wait_host_inst_change_to(100, 0)); + + /* Save free memory usage. */ + mem_free = ux_test_regular_memory_free(); + + /* Connect. */ + stepinfo(">>>>>>>>>>>>>>>>>>> Test connect fake descriptor\n"); + ux_test_hcd_sim_host_set_actions(replace_configuration_descriptor); + ux_test_connect_slave_and_host_wait_for_enum_completion(); + UX_TEST_ASSERT(ux_test_check_actions_empty()); + + for (i = 0; i < 5; i ++) + { + + stepinfo(">>>>>>>>>>>>>>>>>>> Test connect fake descriptor memory %d\n", i); + + /* Disconnect. */ + ux_test_disconnect_slave(); + ux_test_disconnect_host_wait_for_enum_completion(); + + /* Check memory level. */ + UX_TEST_ASSERT(mem_free == ux_test_regular_memory_free()); + + /* Connect. */ + ux_test_hcd_sim_host_set_actions(replace_configuration_descriptor); + ux_test_connect_slave_and_host_wait_for_enum_completion(); + } + + /* We're done. */ +} + +static void post_init_device() +{ + device_is_finished = UX_TRUE; +} \ No newline at end of file diff --git a/test/regression/usbx_msrc_81230_host_asix_inst_free_tests.c b/test/regression/usbx_msrc_81230_host_asix_inst_free_tests.c new file mode 100644 index 00000000..97462a18 --- /dev/null +++ b/test/regression/usbx_msrc_81230_host_asix_inst_free_tests.c @@ -0,0 +1,524 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_device_class_dummy.h" +#include "ux_device_stack.h" +#include "ux_host_class_asix.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); + +static VOID ux_test_hcd_entry_should_not_be_called(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_disconnect(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 4)]; + +static UX_DEVICE *device = UX_NULL; +static UINT device_stall_count = 3; + +static UX_HOST_CLASS_ASIX *host_asix = UX_NULL; + +static ULONG host_device_insertion_counter = 0; +static ULONG host_device_removal_counter = 0; + +static ULONG enum_counter; + +static ULONG error_counter; +static ULONG error_callback_counter = 0; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_on_set_cfg; +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_enum_mem_alloc_count; + +static ULONG rsc_test_sem_usage; +static ULONG rsc_test_sem_get_count; +static ULONG rsc_test_mutex_usage; +static ULONG rsc_test_mem_alloc_count; + +static UX_DEVICE_CLASS_DUMMY *device_dummy = UX_NULL; +static UX_DEVICE_CLASS_DUMMY_PARAMETER device_dummy_parameter; + + +/* Define device framework. */ + +#define _W0(w) ( (w) & 0xFF) +#define _W1(w) (((w) >> 8) & 0xFF) + +#define _CONFIGURATION_DESCRIPTOR(total_len, n_ifc, cfg_val) \ + 0x09, 0x02, _W0(total_len), _W1(total_len), (n_ifc), (cfg_val), \ + 0x00, 0xc0, 0x32, + +#define _INTERFACE_DESCRIPTOR(ifc_n, alt, n_ep, cls, sub, protocol) \ + 0x09, 0x04, (ifc_n), (alt), (n_ep), (cls), (sub), (protocol), 0x00, + +#define _ENDPOINT_DESCRIPTOR(addr, attr, pktsize, interval) \ + 0x07, 0x05, (addr), (attr), _W0(pktsize), _W1(pktsize), (interval), + +#define _CFG_TOTAL_LEN (9+9+7+7+7+7) + +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0xEF bDeviceClass: Composite class code + 0x02 bDeviceSubclass: class sub code + 0x00 bDeviceProtocol: Device protocol + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + /* REF: + 12 01 10 02 00 00 00 40 95 0B 90 17 00 02 01 02 03 03 */ + 0x12, 0x01, 0x10, 0x02, + 0x00, 0x00, 0x00, + 0x40, + 0x95, 0x0B, + 0x2B, 0x77, + 0x00, 0x02, + 0x01, 0x02, 0x03, + 0x01, + + /* REF: + 09 02 2E 00 01 01 00 A0 32 + 09 04 00 00 04 FF FF 00 04 + 07 05 81 03 10 00 0B + 07 05 82 02 00 02 00 + 07 05 03 02 00 02 00 + 07 05 05 02 00 02 00 */ + + _CONFIGURATION_DESCRIPTOR(_CFG_TOTAL_LEN, 1, 1) + _INTERFACE_DESCRIPTOR(0, 0, 4, 0xFF, 0xFF, 0x00) + _ENDPOINT_DESCRIPTOR(0x81, 0x03, 16, 0x0B) + _ENDPOINT_DESCRIPTOR(0x82, 0x02, 64, 0x00) + _ENDPOINT_DESCRIPTOR(0x03, 0x02, 64, 0x00) + _ENDPOINT_DESCRIPTOR(0x05, 0x02, 64, 0x00) +}; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_full_speed) +#define device_framework_high_speed device_framework_full_speed + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "AzureRTOS" */ + 0x09, 0x04, 0x01, 9, + 'A','z','u','r','e','R','T','O','S', + + /* Product string descriptor : Index 2 - "Test device" */ + 0x09, 0x04, 0x02, 14, + 'T','e','s','t',' ',' ',' ',' ','d','e','v','i','c','e', + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +/* Test interactions */ + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT test_slave_change_function(ULONG change) +{ + return 0; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_ASIX *asix_inst = (UX_HOST_CLASS_ASIX *) inst; + // printf("test_host_change_function: event %lx, cls %p, inst %p\n", event, (void*)cls, (void*)inst); + switch(event) + { + + case UX_DEVICE_INSERTION: + host_device_insertion_counter ++; + host_asix = asix_inst; + break; + + case UX_DEVICE_REMOVAL: + host_device_removal_counter ++; + if (host_asix == asix_inst) + host_asix = UX_NULL; + break; + + case UX_DEVICE_CONNECTION: + device = (UX_DEVICE *)inst; + break; + + case UX_DEVICE_DISCONNECTION: + if ((VOID *)device == inst) + device = UX_NULL; + break; + +#if defined(UX_HOST_STANDALONE) + case UX_STANDALONE_WAIT_BACKGROUND_TASK: + tx_thread_relinquish(); + break; +#endif + + default: + break; + } + return 0; +} + +static VOID test_dummy_instance_activate(VOID *dummy_instance) +{ + if (device_dummy == UX_NULL) + device_dummy = (UX_DEVICE_CLASS_DUMMY *)dummy_instance; +} +static VOID test_dummy_instance_deactivate(VOID *dummy_instance) +{ + if ((VOID*)device_dummy == dummy_instance) + device_dummy = UX_NULL; +} +static VOID test_dummy_control_request(UX_DEVICE_CLASS_DUMMY *dummy_instance, UX_SLAVE_TRANSFER *transfer_request) +{ +UINT i; +ULONG cmd_type = transfer_request -> ux_slave_transfer_request_setup[0] | + (transfer_request -> ux_slave_transfer_request_setup[1] << 8); +UCHAR *cmd_buf = transfer_request -> ux_slave_transfer_request_data_pointer; + + if (device_dummy == dummy_instance) + { + + switch(cmd_type) + { + case 0x19c0: /* READ_PHY_ID: return 2 bytes */ + if (device_stall_count) + { + device_stall_count --; + ux_device_stack_endpoint_stall(transfer_request -> ux_slave_transfer_request_endpoint); + break; + } + cmd_buf[0] = 0x01; + cmd_buf[1] = 0x00; + ux_device_stack_transfer_request(transfer_request, 2, 2); + break; + + case 0x1f40: /* WRITE_GPIO_STATUS: */ + break; + + case 0x2240: /* WRITE_SW_PHY_SELECT_STATUS: */ + break; + + case 0x2040: /* SW_RESET: */ + break; + + case 0x1040: /* WRITE_RX_CTL: */ + break; + + case 0x13c0: /* READ_NODE_ID: return 6 bytes */ + cmd_buf[0] = 0x01; + cmd_buf[1] = 0x02; + cmd_buf[2] = 0x03; + cmd_buf[3] = 0x04; + cmd_buf[4] = 0x05; + cmd_buf[5] = 0x06; + ux_device_stack_transfer_request(transfer_request, 6, 6); + break; + + case 0x0640: /* OWN_SMI: */ + break; + + case 0x07c0: /* READ_PHY_REG: return 2 bytes */ + cmd_buf[0] = 0x01; + cmd_buf[1] = 0x00; + ux_device_stack_transfer_request(transfer_request, 2, 2); + break; + + case 0x0840: /* WRITE_PHY_REG: */ + break; + + case 0x1b40: /* WRITE_MEDIUM_MODE: */ + break; + + case 0x1240: /* WRITE_IPG012: */ + break; + + case 0x0a40: /* RELEASE_SMI: */ + break; + + default: + printf("_dummy_CREQ:"); + for (i = 0; i < 8; i ++) + printf(" %02x", transfer_request -> ux_slave_transfer_request_setup[i]); + printf("\n"); + break; + } + } +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + error_callback_counter ++; +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_enum_sem_get_count = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_msrc_81230_host_asix_inst_free_tests_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + printf("Running MSRC 81230 - Host ASIX inst free Test....................... "); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* Initialize the free memory pointer */ + stack_pointer = (CHAR *) usbx_memory; + memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 4); + + /* Initialize USBX Memory */ + status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL,0); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_system_initialize failed 0x%x\n", status); + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_host_stack_initialize failed 0x%x\n", status); + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_asix_name, _ux_host_class_asix_entry); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_host_stack_class_register failed 0x%x\n", status); + + /* 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, + test_slave_change_function); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_device_stack_initialize failed 0x%x\n", status); + + /* Set the parameters for callback when insertion/extraction of a dummy device. */ + _ux_utility_memory_set(&device_dummy_parameter, 0, sizeof(device_dummy_parameter)); + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_instance_activate = test_dummy_instance_activate; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_instance_deactivate = test_dummy_instance_deactivate; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_control_request = test_dummy_control_request; + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_device_class_dummy_name, + _ux_device_class_dummy_entry, + 1, 0, &device_dummy_parameter); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_device_stack_class_register failed 0x%x\n", status); + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "_ux_test_dcd_sim_slave_initialize failed 0x%x\n", status); + + /* 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); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_host_stack_hcd_register failed 0x%x\n", status); + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_thread_host_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_ASSERT_MESSAGE(status == TX_SUCCESS, "tx_thread_create failed 0x%x\n", status); + + /* Create the main slave simulation thread. */ + stack_pointer += UX_DEMO_STACK_SIZE; + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_ASSERT_MESSAGE(status == TX_SUCCESS, "tx_thread_create failed 0x%x\n", status); + +} + +static UINT _test_check_host_connection_error(VOID) +{ + if (device_dummy && host_asix) + return(UX_SUCCESS); + if (error_callback_counter >= 3) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_connection_success(VOID) +{ + if (device_dummy && host_asix) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_disconnection_success(VOID) +{ + if (device_dummy == UX_NULL && host_asix == UX_NULL) + return(UX_SUCCESS); + return(UX_ERROR); +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +ULONG mem_free; +ULONG loop; +ULONG parameter_u32[64/4]; +USHORT *parameter_u16 = (USHORT*)parameter_u32; +UCHAR *parameter_u8 = (UCHAR*)parameter_u32; +UX_INTERFACE *interface; + + + stepinfo("\n"); + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + status = ux_test_sleep_break_on_success(10000, _test_check_host_connection_error); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT_MESSAGE((host_device_insertion_counter == 0 && host_device_removal_counter == 0), + "Expect no INS(%ld)/RM(%ld) detection\n", host_device_insertion_counter, host_device_removal_counter); + UX_TEST_ASSERT_MESSAGE(device, "Expect device\n"); + UX_TEST_ASSERT_MESSAGE(device -> ux_device_class_instance == UX_NULL, "Expect no device class instance\n"); + interface = device -> ux_device_current_configuration -> ux_configuration_first_interface; + UX_TEST_ASSERT_MESSAGE(interface, "Expect interface\n"); + while(interface) + { + UX_TEST_ASSERT_MESSAGE(interface -> ux_interface_class_instance == UX_NULL, "Expect no interface class instance\n"); + interface = interface -> ux_interface_next_interface; + } + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_device_class_dummy_name, _ux_device_class_dummy_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); + tx_thread_relinquish(); +#else + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); +#endif + } +} diff --git a/test/regression/usbx_msrc_81231_host_prolific_inst_free_tests.c b/test/regression/usbx_msrc_81231_host_prolific_inst_free_tests.c new file mode 100644 index 00000000..202ea7f7 --- /dev/null +++ b/test/regression/usbx_msrc_81231_host_prolific_inst_free_tests.c @@ -0,0 +1,479 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_device_class_dummy.h" +#include "ux_device_stack.h" +#include "ux_host_class_prolific.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); + +static VOID ux_test_hcd_entry_should_not_be_called(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_disconnect(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 4)]; + +static UX_DEVICE *device = UX_NULL; +static UINT device_stall_count = 3; + +static UX_HOST_CLASS_PROLIFIC *host_prolific = UX_NULL; + +static ULONG host_device_insertion_counter = 0; +static ULONG host_device_removal_counter = 0; + +static ULONG enum_counter; + +static ULONG error_counter; +static ULONG error_callback_counter = 0; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_on_set_cfg; +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_enum_mem_alloc_count; + +static ULONG rsc_test_sem_usage; +static ULONG rsc_test_sem_get_count; +static ULONG rsc_test_mutex_usage; +static ULONG rsc_test_mem_alloc_count; + +static UX_DEVICE_CLASS_DUMMY *device_dummy = UX_NULL; +static UX_DEVICE_CLASS_DUMMY_PARAMETER device_dummy_parameter; + + +/* Define device framework. */ + +#define _W0(w) ( (w) & 0xFF) +#define _W1(w) (((w) >> 8) & 0xFF) + +#define _CONFIGURATION_DESCRIPTOR(total_len, n_ifc, cfg_val) \ + 0x09, 0x02, _W0(total_len), _W1(total_len), (n_ifc), (cfg_val), \ + 0x00, 0xc0, 0x32, + +#define _INTERFACE_DESCRIPTOR(ifc_n, alt, n_ep, cls, sub, protocol) \ + 0x09, 0x04, (ifc_n), (alt), (n_ep), (cls), (sub), (protocol), 0x00, + +#define _ENDPOINT_DESCRIPTOR(addr, attr, pktsize, interval) \ + 0x07, 0x05, (addr), (attr), _W0(pktsize), _W1(pktsize), (interval), + +#define _CFG_TOTAL_LEN (9+9+7+7+7) + +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0xEF bDeviceClass: Composite class code + 0x02 bDeviceSubclass: class sub code + 0x00 bDeviceProtocol: Device protocol + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + /* REF: 0x067b, 0x2303 */ + 0x12, 0x01, 0x10, 0x02, + 0x00, 0x00, 0x00, + 0x40, + 0x7B, 0x06, + 0x03, 0x23, + 0x00, 0x02, + 0x01, 0x02, 0x03, + 0x01, + + /* REF: CFG IFC BO BI II */ + _CONFIGURATION_DESCRIPTOR(_CFG_TOTAL_LEN, 1, 1) + _INTERFACE_DESCRIPTOR(0, 0, 3, 0xFF, 0xFF, 0x00) + _ENDPOINT_DESCRIPTOR(0x81, 0x03, 16, 0x0B) + _ENDPOINT_DESCRIPTOR(0x82, 0x02, 64, 0x00) + _ENDPOINT_DESCRIPTOR(0x03, 0x02, 64, 0x00) +}; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_full_speed) +#define device_framework_high_speed device_framework_full_speed + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "AzureRTOS" */ + 0x09, 0x04, 0x01, 9, + 'A','z','u','r','e','R','T','O','S', + + /* Product string descriptor : Index 2 - "Test device" */ + 0x09, 0x04, 0x02, 14, + 'T','e','s','t',' ',' ',' ',' ','d','e','v','i','c','e', + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +/* Test interactions */ + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT test_slave_change_function(ULONG change) +{ + return 0; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_PROLIFIC *prolific_inst = (UX_HOST_CLASS_PROLIFIC *) inst; + // printf("test_host_change_function: event %lx, cls %p, inst %p\n", event, (void*)cls, (void*)inst); + switch(event) + { + + case UX_DEVICE_INSERTION: + host_device_insertion_counter ++; + host_prolific = prolific_inst; + break; + + case UX_DEVICE_REMOVAL: + host_device_removal_counter ++; + if (host_prolific == prolific_inst) + host_prolific = UX_NULL; + break; + + case UX_DEVICE_CONNECTION: + device = (UX_DEVICE *)inst; + break; + + case UX_DEVICE_DISCONNECTION: + if ((VOID *)device == inst) + device = UX_NULL; + break; + +#if defined(UX_HOST_STANDALONE) + case UX_STANDALONE_WAIT_BACKGROUND_TASK: + tx_thread_relinquish(); + break; +#endif + + default: + break; + } + return 0; +} + +static VOID test_dummy_instance_activate(VOID *dummy_instance) +{ + if (device_dummy == UX_NULL) + device_dummy = (UX_DEVICE_CLASS_DUMMY *)dummy_instance; +} +static VOID test_dummy_instance_deactivate(VOID *dummy_instance) +{ + if ((VOID*)device_dummy == dummy_instance) + device_dummy = UX_NULL; +} +static VOID test_dummy_control_request(UX_DEVICE_CLASS_DUMMY *dummy_instance, UX_SLAVE_TRANSFER *transfer_request) +{ +UINT i; +ULONG cmd_type = transfer_request -> ux_slave_transfer_request_setup[0] | + (transfer_request -> ux_slave_transfer_request_setup[1] << 8); +UCHAR *cmd_buf = transfer_request -> ux_slave_transfer_request_data_pointer; + + if (device_dummy == dummy_instance) + { + if (device_stall_count) + { + device_stall_count --; + ux_device_stack_endpoint_stall(transfer_request -> ux_slave_transfer_request_endpoint); + return; + } + switch(cmd_type) + { + case 0x01c0: + cmd_buf[0] = 0x00; + ux_device_stack_transfer_request(transfer_request, 1, 1); + return; + + case 0x0140: + return; + + case 0x2021: + return; + + case 0x2221: + return; + + default: + printf("_dummy_CREQ:"); + for (i = 0; i < 8; i ++) + printf(" %02x", transfer_request -> ux_slave_transfer_request_setup[i]); + printf("\n"); + break; + } + } +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + error_callback_counter ++; +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_enum_sem_get_count = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_msrc_81231_host_prolific_inst_free_tests_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + printf("Running MSRC 81231 - Host PROLIFIC inst free Test................... "); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* Initialize the free memory pointer */ + stack_pointer = (CHAR *) usbx_memory; + memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 4); + + /* Initialize USBX Memory */ + status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL,0); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_system_initialize failed 0x%x\n", status); + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_host_stack_initialize failed 0x%x\n", status); + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_prolific_name, ux_host_class_prolific_entry); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_host_stack_class_register failed 0x%x\n", status); + + /* 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, + test_slave_change_function); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_device_stack_initialize failed 0x%x\n", status); + + /* Set the parameters for callback when insertion/extraction of a dummy device. */ + _ux_utility_memory_set(&device_dummy_parameter, 0, sizeof(device_dummy_parameter)); + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_instance_activate = test_dummy_instance_activate; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_instance_deactivate = test_dummy_instance_deactivate; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_control_request = test_dummy_control_request; + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_device_class_dummy_name, + _ux_device_class_dummy_entry, + 1, 0, &device_dummy_parameter); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_device_stack_class_register failed 0x%x\n", status); + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "_ux_test_dcd_sim_slave_initialize failed 0x%x\n", status); + + /* 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); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_host_stack_hcd_register failed 0x%x\n", status); + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_thread_host_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_ASSERT_MESSAGE(status == TX_SUCCESS, "tx_thread_create failed 0x%x\n", status); + + /* Create the main slave simulation thread. */ + stack_pointer += UX_DEMO_STACK_SIZE; + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_ASSERT_MESSAGE(status == TX_SUCCESS, "tx_thread_create failed 0x%x\n", status); + +} + +static UINT _test_check_host_connection_error(VOID) +{ + if (device_dummy && host_prolific) + return(UX_SUCCESS); + if (error_callback_counter >= 3) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_connection_success(VOID) +{ + if (device_dummy && host_prolific) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_disconnection_success(VOID) +{ + if (device_dummy == UX_NULL && host_prolific == UX_NULL) + return(UX_SUCCESS); + return(UX_ERROR); +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +ULONG mem_free; +ULONG loop; +ULONG parameter_u32[64/4]; +USHORT *parameter_u16 = (USHORT*)parameter_u32; +UCHAR *parameter_u8 = (UCHAR*)parameter_u32; +UX_INTERFACE *interface; + + + stepinfo("\n"); + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + status = ux_test_sleep_break_on_success(10000, _test_check_host_connection_error); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT_MESSAGE((host_device_insertion_counter == 0 && host_device_removal_counter == 0), + "Expect no INS(%ld)/RM(%ld) detection\n", host_device_insertion_counter, host_device_removal_counter); + UX_TEST_ASSERT_MESSAGE(device, "Expect device\n"); + UX_TEST_ASSERT_MESSAGE(device -> ux_device_class_instance == UX_NULL, "Expect no device class instance\n"); + interface = device -> ux_device_current_configuration -> ux_configuration_first_interface; + UX_TEST_ASSERT_MESSAGE(interface, "Expect interface\n"); + while(interface) + { + UX_TEST_ASSERT_MESSAGE(interface -> ux_interface_class_instance == UX_NULL, "Expect no interface class instance\n"); + interface = interface -> ux_interface_next_interface; + } + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_device_class_dummy_name, _ux_device_class_dummy_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); + tx_thread_relinquish(); +#else + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); +#endif + } +} diff --git a/test/regression/usbx_msrc_81232_host_gser_inst_free_tests.c b/test/regression/usbx_msrc_81232_host_gser_inst_free_tests.c new file mode 100644 index 00000000..9bbdf747 --- /dev/null +++ b/test/regression/usbx_msrc_81232_host_gser_inst_free_tests.c @@ -0,0 +1,471 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_device_class_dummy.h" +#include "ux_device_stack.h" +#include "ux_host_class_gser.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); + +static VOID ux_test_hcd_entry_should_not_be_called(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_disconnect(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 4)]; + +static UX_DEVICE *device = UX_NULL; +static UINT device_stall_count = 9; + +static UX_HOST_CLASS_GSER *host_gser = UX_NULL; + +static ULONG host_device_insertion_counter = 0; +static ULONG host_device_removal_counter = 0; + +static ULONG enum_counter; + +static ULONG error_counter; +static ULONG error_callback_counter = 0; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_on_set_cfg; +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_enum_mem_alloc_count; + +static ULONG rsc_test_sem_usage; +static ULONG rsc_test_sem_get_count; +static ULONG rsc_test_mutex_usage; +static ULONG rsc_test_mem_alloc_count; + +static UX_DEVICE_CLASS_DUMMY *device_dummy = UX_NULL; +static UX_DEVICE_CLASS_DUMMY_PARAMETER device_dummy_parameter; + + +/* Define device framework. */ + +#define _W0(w) ( (w) & 0xFF) +#define _W1(w) (((w) >> 8) & 0xFF) + +#define _CONFIGURATION_DESCRIPTOR(total_len, n_ifc, cfg_val) \ + 0x09, 0x02, _W0(total_len), _W1(total_len), (n_ifc), (cfg_val), \ + 0x00, 0xc0, 0x32, + +#define _INTERFACE_DESCRIPTOR(ifc_n, alt, n_ep, cls, sub, protocol) \ + 0x09, 0x04, (ifc_n), (alt), (n_ep), (cls), (sub), (protocol), 0x00, + +#define _ENDPOINT_DESCRIPTOR(addr, attr, pktsize, interval) \ + 0x07, 0x05, (addr), (attr), _W0(pktsize), _W1(pktsize), (interval), + +#define _CFG_TOTAL_LEN (9+(9+7+7)*2 + (9+7)) + +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0xEF bDeviceClass: Composite class code + 0x02 bDeviceSubclass: class sub code + 0x00 bDeviceProtocol: Device protocol + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + /* REF: 0x05c6 0x9002 */ + 0x12, 0x01, 0x10, 0x02, + 0x00, 0x00, 0x00, + 0x40, + 0xc6, 0x05, + 0x02, 0x90, + 0x00, 0x02, + 0x01, 0x02, 0x03, + 0x01, + + /* REF: CFG (IFC BO BI) * 3 */ + _CONFIGURATION_DESCRIPTOR(_CFG_TOTAL_LEN, 3, 1) + _INTERFACE_DESCRIPTOR(0, 0, 2, 0xFF, 0xFF, 0x00) + _ENDPOINT_DESCRIPTOR(0x81, 0x02, 64, 0x00) + _ENDPOINT_DESCRIPTOR(0x02, 0x02, 64, 0x00) + _INTERFACE_DESCRIPTOR(1, 0, 2, 0xFF, 0xFF, 0x00) + _ENDPOINT_DESCRIPTOR(0x83, 0x02, 64, 0x00) + _ENDPOINT_DESCRIPTOR(0x04, 0x02, 64, 0x00) + _INTERFACE_DESCRIPTOR(2, 0, 1, 0xFF, 0xFF, 0x00) + _ENDPOINT_DESCRIPTOR(0x85, 0x02, 64, 0x00) +}; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_full_speed) +#define device_framework_high_speed device_framework_full_speed + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "AzureRTOS" */ + 0x09, 0x04, 0x01, 9, + 'A','z','u','r','e','R','T','O','S', + + /* Product string descriptor : Index 2 - "Test device" */ + 0x09, 0x04, 0x02, 14, + 'T','e','s','t',' ',' ',' ',' ','d','e','v','i','c','e', + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +/* Test interactions */ + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT test_slave_change_function(ULONG change) +{ + return 0; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_GSER *gser_inst = (UX_HOST_CLASS_GSER *) inst; + // printf("test_host_change_function: event %lx, cls %p, inst %p\n", event, (void*)cls, (void*)inst); + switch(event) + { + + case UX_DEVICE_INSERTION: + host_device_insertion_counter ++; + host_gser = gser_inst; + break; + + case UX_DEVICE_REMOVAL: + host_device_removal_counter ++; + if (host_gser == gser_inst) + host_gser = UX_NULL; + break; + + case UX_DEVICE_CONNECTION: + device = (UX_DEVICE *)inst; + break; + + case UX_DEVICE_DISCONNECTION: + if ((VOID *)device == inst) + device = UX_NULL; + break; + +#if defined(UX_HOST_STANDALONE) + case UX_STANDALONE_WAIT_BACKGROUND_TASK: + tx_thread_relinquish(); + break; +#endif + + default: + break; + } + return 0; +} + +static VOID test_dummy_instance_activate(VOID *dummy_instance) +{ + if (device_dummy == UX_NULL) + device_dummy = (UX_DEVICE_CLASS_DUMMY *)dummy_instance; +} +static VOID test_dummy_instance_deactivate(VOID *dummy_instance) +{ + if ((VOID*)device_dummy == dummy_instance) + device_dummy = UX_NULL; +} +static VOID test_dummy_control_request(UX_DEVICE_CLASS_DUMMY *dummy_instance, UX_SLAVE_TRANSFER *transfer_request) +{ +UINT i; +ULONG cmd_type = transfer_request -> ux_slave_transfer_request_setup[0] | + (transfer_request -> ux_slave_transfer_request_setup[1] << 8); +UCHAR *cmd_buf = transfer_request -> ux_slave_transfer_request_data_pointer; + + if (device_dummy == dummy_instance) + { + + if (device_stall_count) + { + device_stall_count --; + ux_device_stack_endpoint_stall(transfer_request -> ux_slave_transfer_request_endpoint); + return; + } + switch(cmd_type) + { + + default: + printf("_dummy_CREQ:"); + for (i = 0; i < 8; i ++) + printf(" %02x", transfer_request -> ux_slave_transfer_request_setup[i]); + printf("\n"); + break; + } + } +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + error_callback_counter ++; +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_enum_sem_get_count = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_msrc_81232_host_gser_inst_free_tests_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + printf("Running MSRC 81232 - Host GSER inst free Test....................... "); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* Initialize the free memory pointer */ + stack_pointer = (CHAR *) usbx_memory; + memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 4); + + /* Initialize USBX Memory */ + status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL,0); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_system_initialize failed 0x%x\n", status); + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_host_stack_initialize failed 0x%x\n", status); + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_gser_name, _ux_host_class_gser_entry); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_host_stack_class_register failed 0x%x\n", status); + + /* 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, + test_slave_change_function); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_device_stack_initialize failed 0x%x\n", status); + + /* Set the parameters for callback when insertion/extraction of a dummy device. */ + _ux_utility_memory_set(&device_dummy_parameter, 0, sizeof(device_dummy_parameter)); + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_instance_activate = test_dummy_instance_activate; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_instance_deactivate = test_dummy_instance_deactivate; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_control_request = test_dummy_control_request; + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_device_class_dummy_name, + _ux_device_class_dummy_entry, + 1, 0, &device_dummy_parameter); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_device_stack_class_register failed 0x%x\n", status); + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "_ux_test_dcd_sim_slave_initialize failed 0x%x\n", status); + + /* 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); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_host_stack_hcd_register failed 0x%x\n", status); + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_thread_host_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_ASSERT_MESSAGE(status == TX_SUCCESS, "tx_thread_create failed 0x%x\n", status); + + /* Create the main slave simulation thread. */ + stack_pointer += UX_DEMO_STACK_SIZE; + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_ASSERT_MESSAGE(status == TX_SUCCESS, "tx_thread_create failed 0x%x\n", status); + +} + +static UINT _test_check_host_connection_error(VOID) +{ + if (device_dummy && host_gser) + return(UX_SUCCESS); + if (error_callback_counter >= 3) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_connection_success(VOID) +{ + if (device_dummy && host_gser) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_disconnection_success(VOID) +{ + if (device_dummy == UX_NULL && host_gser == UX_NULL) + return(UX_SUCCESS); + return(UX_ERROR); +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +ULONG mem_free; +ULONG loop; +ULONG parameter_u32[64/4]; +USHORT *parameter_u16 = (USHORT*)parameter_u32; +UCHAR *parameter_u8 = (UCHAR*)parameter_u32; +UX_INTERFACE *interface; + + + stepinfo("\n"); + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + status = ux_test_sleep_break_on_success(10000, _test_check_host_connection_error); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT_MESSAGE((host_device_insertion_counter == 0 && host_device_removal_counter == 0), + "Expect no INS(%ld)/RM(%ld) detection\n", host_device_insertion_counter, host_device_removal_counter); + UX_TEST_ASSERT_MESSAGE(device, "Expect device\n"); + UX_TEST_ASSERT_MESSAGE(device -> ux_device_class_instance == UX_NULL, "Expect no device class instance\n"); + interface = device -> ux_device_current_configuration -> ux_configuration_first_interface; + UX_TEST_ASSERT_MESSAGE(interface, "Expect interface\n"); + while(interface) + { + UX_TEST_ASSERT_MESSAGE(interface -> ux_interface_class_instance == UX_NULL, "Expect no interface class instance\n"); + interface = interface -> ux_interface_next_interface; + } + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_device_class_dummy_name, _ux_device_class_dummy_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); + tx_thread_relinquish(); +#else + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); +#endif + } +} diff --git a/test/regression/usbx_msrc_81233_host_swar_inst_free_tests.c b/test/regression/usbx_msrc_81233_host_swar_inst_free_tests.c new file mode 100644 index 00000000..3b19443b --- /dev/null +++ b/test/regression/usbx_msrc_81233_host_swar_inst_free_tests.c @@ -0,0 +1,465 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_device_class_dummy.h" +#include "ux_device_stack.h" +#include "ux_host_class_swar.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); + +static VOID ux_test_hcd_entry_should_not_be_called(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_disconnect(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 4)]; + +static UX_DEVICE *device = UX_NULL; +static UINT device_stall_count = 3; + +static UX_HOST_CLASS_SWAR *host_swar = UX_NULL; + +static ULONG host_device_insertion_counter = 0; +static ULONG host_device_removal_counter = 0; + +static ULONG enum_counter; + +static ULONG error_counter; +static ULONG error_callback_counter = 0; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_on_set_cfg; +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_enum_mem_alloc_count; + +static ULONG rsc_test_sem_usage; +static ULONG rsc_test_sem_get_count; +static ULONG rsc_test_mutex_usage; +static ULONG rsc_test_mem_alloc_count; + +static UX_DEVICE_CLASS_DUMMY *device_dummy = UX_NULL; +static UX_DEVICE_CLASS_DUMMY_PARAMETER device_dummy_parameter; + + +/* Define device framework. */ + +#define _W0(w) ( (w) & 0xFF) +#define _W1(w) (((w) >> 8) & 0xFF) + +#define _CONFIGURATION_DESCRIPTOR(total_len, n_ifc, cfg_val) \ + 0x09, 0x02, _W0(total_len), _W1(total_len), (n_ifc), (cfg_val), \ + 0x00, 0xc0, 0x32, + +#define _INTERFACE_DESCRIPTOR(ifc_n, alt, n_ep, cls, sub, protocol) \ + 0x09, 0x04, (ifc_n), (alt), (n_ep), (cls), (sub), (protocol), 0x00, + +#define _ENDPOINT_DESCRIPTOR(addr, attr, pktsize, interval) \ + 0x07, 0x05, (addr), (attr), _W0(pktsize), _W1(pktsize), (interval), + +#define _CFG_TOTAL_LEN (9+9+7) + +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0xEF bDeviceClass: Composite class code + 0x02 bDeviceSubclass: class sub code + 0x00 bDeviceProtocol: Device protocol + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + /* REF: VID 1199, PID 68A3 */ + 0x12, 0x01, 0x10, 0x02, + 0x00, 0x00, 0x00, + 0x40, + 0x99, 0x11, + 0xA3, 0x68, + 0x00, 0x02, + 0x01, 0x02, 0x03, + 0x01, + + /* REF: CFG IFC BO BI */ + _CONFIGURATION_DESCRIPTOR(_CFG_TOTAL_LEN, 1, 1) + _INTERFACE_DESCRIPTOR(0, 0, 1, 0xFF, 0xFF, 0x00) + _ENDPOINT_DESCRIPTOR(0x82, 0x02, 64, 0x00) +}; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_full_speed) +#define device_framework_high_speed device_framework_full_speed + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "AzureRTOS" */ + 0x09, 0x04, 0x01, 9, + 'A','z','u','r','e','R','T','O','S', + + /* Product string descriptor : Index 2 - "Test device" */ + 0x09, 0x04, 0x02, 14, + 'T','e','s','t',' ',' ',' ',' ','d','e','v','i','c','e', + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +/* Test interactions */ + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT test_slave_change_function(ULONG change) +{ + return 0; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_SWAR *swar_inst = (UX_HOST_CLASS_SWAR *) inst; + // printf("test_host_change_function: event %lx, cls %p, inst %p\n", event, (void*)cls, (void*)inst); + switch(event) + { + + case UX_DEVICE_INSERTION: + host_device_insertion_counter ++; + host_swar = swar_inst; + break; + + case UX_DEVICE_REMOVAL: + host_device_removal_counter ++; + if (host_swar == swar_inst) + host_swar = UX_NULL; + break; + + case UX_DEVICE_CONNECTION: + device = (UX_DEVICE *)inst; + break; + + case UX_DEVICE_DISCONNECTION: + if ((VOID *)device == inst) + device = UX_NULL; + break; + +#if defined(UX_HOST_STANDALONE) + case UX_STANDALONE_WAIT_BACKGROUND_TASK: + tx_thread_relinquish(); + break; +#endif + + default: + break; + } + return 0; +} + +static VOID test_dummy_instance_activate(VOID *dummy_instance) +{ + if (device_dummy == UX_NULL) + device_dummy = (UX_DEVICE_CLASS_DUMMY *)dummy_instance; +} +static VOID test_dummy_instance_deactivate(VOID *dummy_instance) +{ + if ((VOID*)device_dummy == dummy_instance) + device_dummy = UX_NULL; +} +static VOID test_dummy_control_request(UX_DEVICE_CLASS_DUMMY *dummy_instance, UX_SLAVE_TRANSFER *transfer_request) +{ +UINT i; +ULONG cmd_type = transfer_request -> ux_slave_transfer_request_setup[0] | + (transfer_request -> ux_slave_transfer_request_setup[1] << 8); +UCHAR *cmd_buf = transfer_request -> ux_slave_transfer_request_data_pointer; + + if (device_dummy == dummy_instance) + { + + if (device_stall_count) + { + device_stall_count --; + ux_device_stack_endpoint_stall(transfer_request -> ux_slave_transfer_request_endpoint); + return; + } + switch(cmd_type) + { + + default: + printf("_dummy_CREQ:"); + for (i = 0; i < 8; i ++) + printf(" %02x", transfer_request -> ux_slave_transfer_request_setup[i]); + printf("\n"); + break; + } + } +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + error_callback_counter ++; +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_enum_sem_get_count = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_msrc_81233_host_swar_inst_free_tests_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + printf("Running MSRC 81233 - Host SWAR inst free Test....................... "); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* Initialize the free memory pointer */ + stack_pointer = (CHAR *) usbx_memory; + memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 4); + + /* Initialize USBX Memory */ + status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL,0); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_system_initialize failed 0x%x\n", status); + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_host_stack_initialize failed 0x%x\n", status); + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_swar_name, _ux_host_class_swar_entry); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_host_stack_class_register failed 0x%x\n", status); + + /* 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, + test_slave_change_function); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_device_stack_initialize failed 0x%x\n", status); + + /* Set the parameters for callback when insertion/extraction of a dummy device. */ + _ux_utility_memory_set(&device_dummy_parameter, 0, sizeof(device_dummy_parameter)); + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_instance_activate = test_dummy_instance_activate; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_instance_deactivate = test_dummy_instance_deactivate; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_control_request = test_dummy_control_request; + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_device_class_dummy_name, + _ux_device_class_dummy_entry, + 1, 0, &device_dummy_parameter); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_device_stack_class_register failed 0x%x\n", status); + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "_ux_test_dcd_sim_slave_initialize failed 0x%x\n", status); + + /* 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); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ux_host_stack_hcd_register failed 0x%x\n", status); + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_thread_host_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_ASSERT_MESSAGE(status == TX_SUCCESS, "tx_thread_create failed 0x%x\n", status); + + /* Create the main slave simulation thread. */ + stack_pointer += UX_DEMO_STACK_SIZE; + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_ASSERT_MESSAGE(status == TX_SUCCESS, "tx_thread_create failed 0x%x\n", status); + +} + +static UINT _test_check_host_connection_error(VOID) +{ + if (device_dummy && host_swar) + return(UX_SUCCESS); + if (error_callback_counter >= 3) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_connection_success(VOID) +{ + if (device_dummy && host_swar) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_disconnection_success(VOID) +{ + if (device_dummy == UX_NULL && host_swar == UX_NULL) + return(UX_SUCCESS); + return(UX_ERROR); +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +ULONG mem_free; +ULONG loop; +ULONG parameter_u32[64/4]; +USHORT *parameter_u16 = (USHORT*)parameter_u32; +UCHAR *parameter_u8 = (UCHAR*)parameter_u32; +UX_INTERFACE *interface; + + + stepinfo("\n"); + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + status = ux_test_sleep_break_on_success(10000, _test_check_host_connection_error); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT_MESSAGE((host_device_insertion_counter == 0 && host_device_removal_counter == 0), + "Expect no INS(%ld)/RM(%ld) detection\n", host_device_insertion_counter, host_device_removal_counter); + UX_TEST_ASSERT_MESSAGE(device, "Expect device\n"); + UX_TEST_ASSERT_MESSAGE(device -> ux_device_class_instance == UX_NULL, "Expect no device class instance\n"); + interface = device -> ux_device_current_configuration -> ux_configuration_first_interface; + UX_TEST_ASSERT_MESSAGE(interface, "Expect interface\n"); + while(interface) + { + UX_TEST_ASSERT_MESSAGE(interface -> ux_interface_class_instance == UX_NULL, "Expect no interface class instance\n"); + interface = interface -> ux_interface_next_interface; + } + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_device_class_dummy_name, _ux_device_class_dummy_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); + tx_thread_relinquish(); +#else + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); +#endif + } +} diff --git a/test/regression/usbx_msrc_81251_host_hid_report_add_fail_mem_test.c b/test/regression/usbx_msrc_81251_host_hid_report_add_fail_mem_test.c new file mode 100644 index 00000000..2618a3cf --- /dev/null +++ b/test/regression/usbx_msrc_81251_host_hid_report_add_fail_mem_test.c @@ -0,0 +1,384 @@ +/* This file tests ux_host_class_hid_report_add() */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" +#include "ux_test_utility_sim.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0, // END_COLLECTION + + 0xa1, 0x01, // COLLECTION (Application) + 0x95, 0x00, // REPORT_COUNT (0) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION + +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_msrc81251__host_hid_report_add_fail_mem_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running MSRC 81251 ux_host_class_hid_report_add field fail 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_ITEM hid_item; +UINT report_id = 0xabcdef; +UX_MEMORY_BLOCK *dummy_memory_block_first = (UX_MEMORY_BLOCK *)dummy_usbx_memory; +UX_MEMORY_BLOCK *original_regular_memory_block = (UX_MEMORY_BLOCK*)_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start; +UX_MEMORY_BLOCK *original_cache_safe_memory_block = (UX_MEMORY_BLOCK*)_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_start; +UX_HOST_CLASS_HID_ITEM item; +ALIGN_TYPE tmp; +ALIGN_TYPE tmp2; +ALIGN_TYPE tmp3; +UX_HOST_CLASS_HID_PARSER *hid_parser; + +UX_HOST_CLASS_HID_REPORT *report; +UCHAR buffer[16] = {0}; + + + /* 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); + } + + hid_parser = &hid -> ux_host_class_hid_parser; + + /**************************************************/ + /** Test case: new_hid_field -> ux_host_class_hid_field_usages = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, hid_field_count*4); fails **/ + /**************************************************/ + + tmp2 = hid_parser->ux_host_class_hid_parser_global.ux_host_class_hid_global_item_report_count; + hid_parser->ux_host_class_hid_parser_global.ux_host_class_hid_global_item_report_count = 1; + + tmp3 = hid_parser->ux_host_class_hid_parser_local.ux_host_class_hid_local_item_number_usage; + hid_parser->ux_host_class_hid_parser_local.ux_host_class_hid_local_item_number_usage = 1; + + /* Ensure report_add() doesn't free the allocated memory for the new hid report. */ + tmp = (ALIGN_TYPE)hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_input_report; + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_input_report = UX_NULL; + + /* Set the necessary values to ensure we hit the case. */ + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_global.ux_host_class_hid_global_item_report_id = report_id++; // Don't free the newly allocated report. + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_global.ux_host_class_hid_global_item_report_count = 1; // Make sure we allocate a field. + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_local.ux_host_class_hid_local_item_number_usage = 1; // Make sure we allocate a field. + hid_item.ux_host_class_hid_item_report_tag = UX_HOST_CLASS_HID_MAIN_TAG_INPUT; // Make sure we pass a valid tag. + hid_item.ux_host_class_hid_item_report_length = 1; // Make sure we read in the INPUT's data. + buffer[0] = 0x02; // Set the input's data (Data,Var,Abs) + + /* Allocate level setup. */ + ux_test_utility_sim_mem_allocate_until( + sizeof(UX_HOST_CLASS_HID_REPORT) + + sizeof(UX_HOST_CLASS_HID_FIELD) + + 8 * 2); + + status = _ux_host_class_hid_report_add(hid, buffer, &hid_item); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + report = hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_input_report; + UX_TEST_ASSERT_MESSAGE(report != UX_NULL, "report should be added but null\n"); + UX_TEST_ASSERT_MESSAGE(report -> ux_host_class_hid_report_field == UX_NULL, "report_field should not be added but not null\n"); + + /* Restore state for next test. */ + ux_test_utility_sim_mem_free_all(); + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_input_report = (UX_HOST_CLASS_HID_REPORT *)tmp; + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_global.ux_host_class_hid_global_item_report_count = (ULONG)tmp2; + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_local.ux_host_class_hid_local_item_number_usage = (ULONG)tmp3; + + /* 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_msrc_81292_host_pima_deactivate_semaphore_test.c b/test/regression/usbx_msrc_81292_host_pima_deactivate_semaphore_test.c new file mode 100644 index 00000000..cbe72426 --- /dev/null +++ b/test/regression/usbx_msrc_81292_host_pima_deactivate_semaphore_test.c @@ -0,0 +1,3803 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#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_DEVICE *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_DEVICE *)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_msrc_81292_pima_deactivate_semaphore_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +ULONG test_n; + + /* Inform user. */ + printf("Running MSRC 81292 - PIMA Deactivate Semaphore 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 void test_call_pima_apis(void) +{ +UINT status; +ULONG actual_length; + + 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); + + 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); + + status = ux_host_class_pima_object_handles_get(pima_host, &pima_host_session, host_buffer32, 64, 0, UX_HOST_CLASS_PIMA_OFC_UNDEFINED, 0); + UX_TEST_CHECK_SUCCESS(status); + + status = ux_host_class_pima_object_info_get(pima_host, &pima_host_session, 0, &pima_host_object); + UX_TEST_CHECK_SUCCESS(status); + + status = ux_host_class_pima_object_open(pima_host, &pima_host_session, 0, &pima_host_object); + UX_TEST_CHECK_SUCCESS(status); + + status = ux_host_class_pima_object_close(pima_host, &pima_host_session, 0, &pima_host_object); + UX_TEST_CHECK_SUCCESS(status); + + status = ux_host_class_pima_session_close(pima_host, &pima_host_session); + UX_TEST_CHECK_SUCCESS(status); +} + +void test_disconnect(void) +{ +UINT test, i; +ULONG mem_free = 0xFFFFFFFF; + + for (test = 0; test < 3; test ++) + { + stepinfo(">>>>>>>>>>>> Disconnect.%d\n", test); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + UX_TEST_ASSERT_MESSAGE(pima_device == UX_NULL, "Expect device NULL but %p\n", (void*)pima_device); + UX_TEST_ASSERT_MESSAGE(pima_host == UX_NULL, "Expect host NULL but %p\n", (void*)pima_host); + + if (mem_free == 0xFFFFFFFF) + mem_free = ux_test_regular_memory_free(); + else + { + printf(" %ld <> %ld\n", mem_free, ux_test_regular_memory_free()); + // UX_TEST_ASSERT_MESSAGE(mem_free == ux_test_regular_memory_free(), "Memory leak %ld <> %ld\n", mem_free, ux_test_regular_memory_free()); + } + + stepinfo(">>>>>>>>>>>> Connect.%d\n", test); + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + for (i = 0; i < 100; i ++) + { + if (pima_host && pima_device) + break; + ux_utility_delay_ms(1); + } + + UX_TEST_ASSERT_MESSAGE(pima_device != UX_NULL, "Expect device but NULL\n"); + UX_TEST_ASSERT_MESSAGE(pima_host != UX_NULL, "Expect host NULL but NULL\n"); + } +} + +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_call_pima_apis(); + test_disconnect(); + + 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_msrc_81323_host_pima_deactivate_no_int_ep_test.c b/test/regression/usbx_msrc_81323_host_pima_deactivate_no_int_ep_test.c new file mode 100644 index 00000000..882f9616 --- /dev/null +++ b/test/regression/usbx_msrc_81323_host_pima_deactivate_no_int_ep_test.c @@ -0,0 +1,3797 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#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_DEVICE *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, 32, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 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, +}; +#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, 32, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 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, +}; +#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_DEVICE *)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_msrc_81323_pima_deactivate_no_int_ep_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +ULONG test_n; + + /* Inform user. */ + printf("Running MSRC 81323 - PIMA Deactivate No INT EP 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 void test_call_pima_apis(void) +{ +UINT status; +ULONG actual_length; + + 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); + + 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); + + status = ux_host_class_pima_object_handles_get(pima_host, &pima_host_session, host_buffer32, 64, 0, UX_HOST_CLASS_PIMA_OFC_UNDEFINED, 0); + UX_TEST_CHECK_SUCCESS(status); + + status = ux_host_class_pima_object_info_get(pima_host, &pima_host_session, 0, &pima_host_object); + UX_TEST_CHECK_SUCCESS(status); + + status = ux_host_class_pima_object_open(pima_host, &pima_host_session, 0, &pima_host_object); + UX_TEST_CHECK_SUCCESS(status); + + status = ux_host_class_pima_object_close(pima_host, &pima_host_session, 0, &pima_host_object); + UX_TEST_CHECK_SUCCESS(status); + + status = ux_host_class_pima_session_close(pima_host, &pima_host_session); + UX_TEST_CHECK_SUCCESS(status); +} + +void test_disconnect(void) +{ +UINT test, i; +ULONG mem_free = 0xFFFFFFFF; + + for (test = 0; test < 3; test ++) + { + stepinfo(">>>>>>>>>>>> Disconnect.%d\n", test); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + UX_TEST_ASSERT_MESSAGE(pima_device == UX_NULL, "Expect device NULL but %p\n", (void*)pima_device); + UX_TEST_ASSERT_MESSAGE(pima_host == UX_NULL, "Expect host NULL but %p\n", (void*)pima_host); + + if (mem_free == 0xFFFFFFFF) + mem_free = ux_test_regular_memory_free(); + else + { + // printf(" %ld <> %ld\n", mem_free, ux_test_regular_memory_free()); + UX_TEST_ASSERT_MESSAGE(mem_free == ux_test_regular_memory_free(), "Memory leak %ld <> %ld\n", mem_free, ux_test_regular_memory_free()); + } + + stepinfo(">>>>>>>>>>>> Connect.%d\n", test); + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + for (i = 0; i < 100; i ++) + { + if (pima_host && pima_device) + break; + ux_utility_delay_ms(1); + } + + UX_TEST_ASSERT_MESSAGE(pima_device != UX_NULL, "Expect device but NULL\n"); + UX_TEST_ASSERT_MESSAGE(pima_host != UX_NULL, "Expect host NULL but NULL\n"); + } +} + +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_call_pima_apis(); + test_disconnect(); + + 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_msrc_81325_host_hid_remote_control_free_callback_test.c b/test/regression/usbx_msrc_81325_host_hid_remote_control_free_callback_test.c new file mode 100644 index 00000000..42f898d6 --- /dev/null +++ b/test/regression/usbx_msrc_81325_host_hid_remote_control_free_callback_test.c @@ -0,0 +1,338 @@ +/* This file tests the ux_host_class_hid_mouse_wheel_get API. */ + +#include "usbx_test_common_hid.h" +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + +static UINT ux_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ +UX_HOST_CLASS_HID_CLIENT *client_inst = (UX_HOST_CLASS_HID_CLIENT*)inst; + + stepinfo("hChg:%lx, %p, %p\n", event, cls, inst); + switch(event) + { + case UX_HID_CLIENT_INSERTION: + break; + + case UX_HID_CLIENT_REMOVAL: + UX_TEST_ASSERT(!ux_test_memory_is_freed(client_inst -> ux_host_class_hid_client_local_instance)); + if (hid_client == client_inst) + { + hid_client = UX_NULL; + } + break; + + default: + break; + } + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_msrc_81325_host_hid_remote_control_free_callback_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running MSRC 81326 - Host HID RemoteControl Free and Callback 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Register the HID client(s). */ + status = ux_host_class_hid_client_register(_ux_system_host_class_hid_client_remote_control_name, ux_host_class_hid_remote_control_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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UINT i; + + /* 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); + } + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + for (i = 0; i < 100; i ++) + { + if (hid_client == UX_NULL) + break; + } + UX_TEST_ASSERT(hid_client == UX_NULL); + + /* 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_msrc_81326_host_hid_keyboard_free_callback_test.c b/test/regression/usbx_msrc_81326_host_hid_keyboard_free_callback_test.c new file mode 100644 index 00000000..f31a92de --- /dev/null +++ b/test/regression/usbx_msrc_81326_host_hid_keyboard_free_callback_test.c @@ -0,0 +1,338 @@ +/* This file tests the ux_host_class_hid_mouse_wheel_get API. */ + +#include "usbx_test_common_hid.h" +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + +static UINT ux_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ +UX_HOST_CLASS_HID_CLIENT *client_inst = (UX_HOST_CLASS_HID_CLIENT*)inst; + + stepinfo("hChg:%lx, %p, %p\n", event, cls, inst); + switch(event) + { + case UX_HID_CLIENT_INSERTION: + break; + + case UX_HID_CLIENT_REMOVAL: + UX_TEST_ASSERT(!ux_test_memory_is_freed(client_inst -> ux_host_class_hid_client_local_instance)); + if (hid_client == client_inst) + { + hid_client = UX_NULL; + } + break; + + default: + break; + } + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_msrc_81326_host_hid_keyboard_free_callback_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running MSRC 81326 - Host HID Keyboard Free and Callback 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UINT i; + + /* 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); + } + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + for (i = 0; i < 100; i ++) + { + if (hid_client == UX_NULL) + break; + } + UX_TEST_ASSERT(hid_client == UX_NULL); + + /* 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_msrc_81327_host_hid_mouse_free_callback_test.c b/test/regression/usbx_msrc_81327_host_hid_mouse_free_callback_test.c new file mode 100644 index 00000000..e58d147c --- /dev/null +++ b/test/regression/usbx_msrc_81327_host_hid_mouse_free_callback_test.c @@ -0,0 +1,338 @@ +/* This file tests the ux_host_class_hid_mouse_wheel_get API. */ + +#include "usbx_test_common_hid.h" +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + +static UINT ux_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ +UX_HOST_CLASS_HID_CLIENT *client_inst = (UX_HOST_CLASS_HID_CLIENT*)inst; + + stepinfo("hChg:%lx, %p, %p\n", event, cls, inst); + switch(event) + { + case UX_HID_CLIENT_INSERTION: + break; + + case UX_HID_CLIENT_REMOVAL: + UX_TEST_ASSERT(!ux_test_memory_is_freed(client_inst -> ux_host_class_hid_client_local_instance)); + if (hid_client == client_inst) + { + hid_client = UX_NULL; + } + break; + + default: + break; + } + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_msrc_81327_host_hid_mouse_free_callback_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running MSRC 81327 - Host HID Mouse Free and Callback 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Register the HID client(s). */ + status = ux_host_class_hid_client_register(_ux_system_host_class_hid_client_mouse_name, ux_host_class_hid_mouse_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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UINT i; + + /* 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); + } + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + for (i = 0; i < 100; i ++) + { + if (hid_client == UX_NULL) + break; + } + UX_TEST_ASSERT(hid_client == UX_NULL); + + /* 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_msrc_81426_host_audio_type_get_fail_ac_link_test.c b/test/regression/usbx_msrc_81426_host_audio_type_get_fail_ac_link_test.c new file mode 100644 index 00000000..582360a7 --- /dev/null +++ b/test/regression/usbx_msrc_81426_host_audio_type_get_fail_ac_link_test.c @@ -0,0 +1,1076 @@ +/* This test is designed to test the simple dpump host/device class operation. */ +/* Compile option requires: + -DUX_HOST_CLASS_AUDIO_2_SUPPORT + -DUX_HOST_CLASS_AUDIO_INTERRUPT_SUPPORT + -DUX_SLAVE_REQUEST_CONTROL_MAX_LENGTH=512 +*/ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" + +#include "fx_api.h" + +#include "ux_device_stack.h" +#include "ux_device_class_dummy.h" + +#include "ux_host_class_audio.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_DEMO_REQUEST_MAX_LENGTH \ + ((UX_HCD_SIM_HOST_MAX_PAYLOAD) > (UX_SLAVE_REQUEST_DATA_MAX_LENGTH) ? \ + (UX_HCD_SIM_HOST_MAX_PAYLOAD) : (UX_SLAVE_REQUEST_DATA_MAX_LENGTH)) + +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_DEMO_REQUEST_MAX_LENGTH + 1) +#define UX_DEMO_MEMORY_SIZE (128*1024) + +#define UX_TEST_LOG_SIZE (64) + + +/* Define local/extern function prototypes. */ +static void test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static void tx_test_thread_host_simulation_entry(ULONG); +static void tx_test_thread_slave_simulation_entry(ULONG); + +static TX_EVENT_FLAGS_GROUP tx_test_events; + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[64]; + +static UX_HOST_CLASS_AUDIO_AC *host_audio_ac = UX_NULL; +static UX_HOST_CLASS_AUDIO *host_audio_tx = UX_NULL; +static UX_HOST_CLASS_AUDIO *host_audio_rx = UX_NULL; + +static UX_HOST_CLASS_AUDIO *audio = UX_NULL; + +static UX_DEVICE_CLASS_DUMMY *dummy[3]; +static UX_DEVICE_CLASS_DUMMY_PARAMETER dummy_parameter; + +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_mem_alloc_cnt_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_enum_mem_alloc_count; + +static ULONG rsc_audio_sem_usage; +static ULONG rsc_audio_sem_get_count; +static ULONG rsc_audio_mutex_usage; +static ULONG rsc_audio_mem_usage; +static ULONG rsc_audio_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +/* Define device framework. */ + +#define D3(d) ((UCHAR)((d) >> 24)) +#define D2(d) ((UCHAR)((d) >> 16)) +#define D1(d) ((UCHAR)((d) >> 8)) +#define D0(d) ((UCHAR)((d) >> 0)) + +static unsigned char device_framework_full_speed[] = { + +/* --------------------------------------- Device Descriptor *//* @0 */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x02, 0x00, +/* 12 bcdDevice */ D0(0x200),D1(0x200), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* ----------------------------- Device Qualifier Descriptor *//* @18 */ +/* 0 bLength, bDescriptorType */ 10, 0x06, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 bNumConfigurations */ 1, +/* 9 bReserved */ 0, + +/* -------------------------------- Configuration Descriptor *//* 9+8+135+55+62=269 *//* @28 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(269),D1(269), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------ Interface Association Descriptor *//* @37 */ +/* 0 bLength, bDescriptorType */ 8, 0x0B, +/* 2 bFirstInterface, bInterfaceCount */ 0, 3, +/* 4 bFunctionClass, bFunctionSubClass, bFunctionProtocol */ 0x01, 0x00, 0x20, +/* 7 iFunction */ 0, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+126=135) *//* @45 */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x20, +/* 8 iInterface */ 0, +/* ---------------- Audio 2.0 AC Interface Header Descriptor *//* (9+8+8+7+17*2+18*2+12*2=126) *//* @54 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x01, +/* 3 bcdADC, bCategory */ D0(0x200),D1(0x200), 0x08, +/* 6 wTotalLength */ D0(126),D1(126), +/* 8 bmControls */ 0x00, +/* -------------------- Audio 2.0 AC Clock Source Descriptor (0x11) *//* @63 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x24, 0x0A, +/* 3 bClockID, bmAttributes, bmControls */ 0x11, 0x05, 0x01, +/* 6 bAssocTerminal, iClockSource */ 0x00, 0, +/* -------------------- Audio 2.0 AC Clock Selector Descriptor (1x1, 0x12) *//* @71 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x24, 0x0B, +/* 3 bClockID, bNrInPins, baCSourceID1 */ 0x12, 0x01, 0x11, +/* 6 bmControls, iClockSelector */ 0x01, 0, +/* -------------------- Audio 2.0 AC Clock Multiplier Descriptor (0x10) *//* @79 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x0C, +/* 3 bClockID, bCSourceID, bmControls */ 0x10, 0x12, 0x05, +/* 6 iClockMultiplier */ 0, +/* ------------------- Audio 2.0 AC Input Terminal Descriptor *//* @86 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 17, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, bCSourceID */ 0x00, 0x10, +/* 8 bNrChannels, bmChannelConfig */ 0x02, D0(0),D1(0),D2(0),D3(0), +/* 13 iChannelNames, bmControls, iTerminal */ 0, D0(0),D1(0), 0, +/* --------------------- Audio 2.0 AC Feature Unit Descriptor *//* @86+17=103 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 18, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bmaControls(0), bmaControls(...) ... */ D0(0xF),D1(0xF),D2(0xF),D3(0xF), D0(0),D1(0),D2(0),D3(0), D0(0),D1(0),D2(0),D3(0), +/* . iFeature */ 0, +/* ------------------ Audio 2.0 AC Output Terminal Descriptor *//* @103+18=121 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID, bCSourceID */ 0x00, 0x02, 0x10, +/* 9 bmControls, iTerminal */ D0(0),D1(0), 0, +/* ------------------- Audio 2.0 AC Input Terminal Descriptor *//* @121+12=133 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 17, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bCSourceID */ 0x00, 0x10, +/* 8 bNrChannels, bmChannelConfig */ 0x02, D0(0),D1(0),D2(0),D3(0), +/* 13 iChannelNames, bmControls, iTerminal */ 0, D0(0),D1(0), 0, +/* --------------------- Audio 2.0 AC Feature Unit Descriptor *//* @133+17=150 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 18, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bmaControls(0), bmaControls(...) ... */ D0(0xF),D1(0xF),D2(0xF),D3(0xF), D0(0),D1(0),D2(0),D3(0), D0(0),D1(0),D2(0),D3(0), +/* . iFeature */ 0, +/* ------------------ Audio 2.0 AC Output Terminal Descriptor *//* @150+18=168 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID, bCSourceID */ 0x00, 0x05, 0x10, +/* 9 bmControls, iTerminal */ D0(0),D1(0), 0, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+16+6+7+8=55) *//* @168+12=180 */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor *//* @180+9=189 */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------ Audio 2.0 AS Interface Descriptor *//* @189+9=198 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 16, 0x24, 0x01, +/* 3 bTerminalLink, bmControls */ 0x03,0x00, +/* 5 bFormatType, bmFormats */ 0x01,D0(1),D1(1),D2(1),D3(1), +/* 10 bNrChannels, bmChannelConfig */ 2, D0(0),D1(0),D2(0),D3(0), +/* 15 iChannelNames */ 0, +/* -------------------- Audio 2.0 AS Format Type I Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 6, 0x24, 0x02, +/* 3 bFormatType, bSubslotSize, bBitResolution */ 0x01, 2, 16, +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x0D, +/* 4 wMaxPacketSize, bInterval */ D0(256),D1(256), 1, +/* ---------- Audio 2.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x25, 0x01, +/* 3 bmAttributes, bmControls */ 0x00, 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+16+6+7+8+7=62) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 2, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------ Audio 2.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 16, 0x24, 0x01, +/* 3 bTerminalLink, bmControls */ 0x04,0x00, +/* 5 bFormatType, bmFormats */ 0x01,D0(1),D1(1),D2(1),D3(1), +/* 10 bNrChannels, bmChannelConfig */ 2, D0(0),D1(0),D2(0),D3(0), +/* 15 iChannelNames */ 0, +/* ---------------------- Audio 2.0 AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 6, 0x24, 0x02, +/* 3 bFormatType, bSubslotSize, bBitResolution */ 0x01, 2, 16, +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x0D, +/* 4 wMaxPacketSize, bInterval */ D0(256),D1(256), 1, +/* ---------- Audio 2.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x25, 0x01, +/* 3 bmAttributes, bmControls */ 0x00, 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x82, 0x11, +/* 4 wMaxPacketSize, bInterval */ D0(4),D1(4), 1, + +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +#define FRAMEWORK_POS_FULL_SPEED_IAD (37) +#define FRAMEWORK_POS_FULL_SPEED_ITD (84) +#define FRAMEWORK_POS_FULL_SPEED_OTD (119) +#define FRAMEWORK_POS_FULL_SPEED_ASD (198) /* IFD::bTerminalLink@4 */ + +static unsigned char device_framework_full_speed_iad_audio10[] = { + +/* --------------------------------------- Device Descriptor *//* @0 */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 0x08, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x01, 0x00, +/* 12 bcdDevice */ D0(0x100),D1(0x100), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* -------------------------------- Configuration Descriptor *//* 9+8+88+52*2=209 *//* @18 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(209),D1(209), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------ Interface Association Descriptor *//* @27 */ +/* 0 bLength, bDescriptorType */ 8, 0x0B, +/* 2 bFirstInterface, bInterfaceCount */ 0, 3, +/* 4 bFunctionClass, bFunctionSubClass, bFunctionProtocol */ 0x01, 0x01, 0x00, +/* 7 iFunction */ 0, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+72+7=88) *//* @35 */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x00, +/* 8 iInterface */ 0, +/* ---------------- Audio 1.0 AC Interface Header Descriptor *//* (10+12*2+10*2+9*2=72) *//* @44 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x01, +/* 3 bcdADC */ 0x00, 0x01, +/* 5 wTotalLength, bInCollection */ D0(72),D1(72), 2, +/* 8 baInterfaceNr(1) ... baInterfaceNr(n) */ 1, 2, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor *//* @54 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor *//* @54+12=66 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor *//* @66+10=76 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x02, +/* 8 iTerminal */ 0, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor *//* @76+9=85 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor *//* @85+12=97 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor *//* @97+10=107 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x05, +/* 8 iTerminal */ 0, +/* --------------------- Audio 1.0 AC INT Endpoint Descriptor *//* @107+9=116 */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x83, 0x03, +/* 4 wMaxPacketSize, bInterval */ D0(8),D1(8), 1, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+7+11+9+7=52) *//* @116+7=123 */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor *//* @123+9=132 */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor *//* @132+9=141 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x03, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 1, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x04, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 1, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +}; +#define FRAMEWORK_POS_FULL_SPEED_AC10 (44) +#define FRAMEWORK_POS_FULL_SPEED_ITD10 (54) +#define FRAMEWORK_POS_FULL_SPEED_OTD10 (76) +#define FRAMEWORK_POS_FULL_SPEED_ASD10 (141) /* bTerminalLink@4 */ +static UCHAR device_framework_modified[2048]; + +static unsigned char device_framework_high_speed[] = { +/* --------------------------------------- Device Descriptor */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 0x08, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x02, 0x00, +/* 12 bcdDevice */ D0(0x200),D1(0x200), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* ----------------------------- Device Qualifier Descriptor */ +/* 0 bLength, bDescriptorType */ 10, 0x06, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 bNumConfigurations */ 1, +/* 9 bReserved */ 0, + +/* -------------------------------- Configuration Descriptor *//* 9+8+135+55+62=269 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(269),D1(269), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------ Interface Association Descriptor */ +/* 0 bLength, bDescriptorType */ 8, 0x0B, +/* 2 bFirstInterface, bInterfaceCount */ 0, 3, +/* 4 bFunctionClass, bFunctionSubClass, bFunctionProtocol */ 0x01, 0x00, 0x20, +/* 7 iFunction */ 0, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+126=135) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x20, +/* 8 iInterface */ 0, +/* ---------------- Audio 2.0 AC Interface Header Descriptor *//* (9+8+8+7+17*2+18*2+12*2=126) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x01, +/* 3 bcdADC, bCategory */ D0(0x200),D1(0x200), 0x08, +/* 6 wTotalLength */ D0(126),D1(126), +/* 8 bmControls */ 0x00, +/* -------------------- Audio 2.0 AC Clock Source Descriptor (0x11) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x24, 0x0A, +/* 3 bClockID, bmAttributes, bmControls */ 0x11, 0x05, 0x01, +/* 6 bAssocTerminal, iClockSource */ 0x00, 0, +/* -------------------- Audio 2.0 AC Clock Selector Descriptor (1x1, 0x12) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x24, 0x0B, +/* 3 bClockID, bNrInPins, baCSourceID1 */ 0x12, 0x01, 0x11, +/* 6 bmControls, iClockSelector */ 0x01, 0, +/* -------------------- Audio 2.0 AC Clock Multiplier Descriptor (0x10) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x0C, +/* 3 bClockID, bCSourceID, bmControls */ 0x10, 0x12, 0x05, +/* 6 iClockMultiplier */ 0, +/* ------------------- Audio 2.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 17, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, bCSourceID */ 0x00, 0x10, +/* 8 bNrChannels, bmChannelConfig */ 0x02, D0(0),D1(0),D2(0),D3(0), +/* 13 iChannelNames, bmControls, iTerminal */ 0, D0(0),D1(0), 0, +/* --------------------- Audio 2.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 18, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bmaControls(0), bmaControls(...) ... */ D0(0xF),D1(0xF),D2(0xF),D3(0xF), D0(0),D1(0),D2(0),D3(0), D0(0),D1(0),D2(0),D3(0), +/* . iFeature */ 0, +/* ------------------ Audio 2.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID, bCSourceID */ 0x00, 0x02, 0x10, +/* 9 bmControls, iTerminal */ D0(0),D1(0), 0, +/* ------------------- Audio 2.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 17, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bCSourceID */ 0x00, 0x10, +/* 8 bNrChannels, bmChannelConfig */ 0x02, D0(0),D1(0),D2(0),D3(0), +/* 13 iChannelNames, bmControls, iTerminal */ 0, D0(0),D1(0), 0, +/* --------------------- Audio 2.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 18, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bmaControls(0), bmaControls(...) ... */ D0(0xF),D1(0xF),D2(0xF),D3(0xF), D0(0),D1(0),D2(0),D3(0), D0(0),D1(0),D2(0),D3(0), +/* . iFeature */ 0, +/* ------------------ Audio 2.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID, bCSourceID */ 0x00, 0x05, 0x10, +/* 9 bmControls, iTerminal */ D0(0),D1(0), 0, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+16+6+7+8=55) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------ Audio 2.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 16, 0x24, 0x01, +/* 3 bTerminalLink, bmControls */ 0x03,0x00, +/* 5 bFormatType, bmFormats */ 0x01,D0(1),D1(1),D2(1),D3(1), +/* 10 bNrChannels, bmChannelConfig */ 2, D0(0),D1(0),D2(0),D3(0), +/* 15 iChannelNames */ 0, +/* -------------------- Audio 2.0 AS Format Type I Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 6, 0x24, 0x02, +/* 3 bFormatType, bSubslotSize, bBitResolution */ 0x01, 2, 16, +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x0D, +/* 4 wMaxPacketSize, bInterval */ D0(256),D1(256), 4, +/* ---------- Audio 2.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x25, 0x01, +/* 3 bmAttributes, bmControls */ 0x00, 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+16+6+7+8+7=62) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 2, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------ Audio 2.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 16, 0x24, 0x01, +/* 3 bTerminalLink, bmControls */ 0x04,0x00, +/* 5 bFormatType, bmFormats */ 0x01,D0(1),D1(1),D2(1),D3(1), +/* 10 bNrChannels, bmChannelConfig */ 2, D0(0),D1(0),D2(0),D3(0), +/* 15 iChannelNames */ 0, +/* ---------------------- Audio 2.0 AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 6, 0x24, 0x02, +/* 3 bFormatType, bSubslotSize, bBitResolution */ 0x01, 2, 16, +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x0D, +/* 4 wMaxPacketSize, bInterval */ D0(256),D1(256), 4, +/* ---------- Audio 2.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x25, 0x01, +/* 3 bmAttributes, bmControls */ 0x00, 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x82, 0x11, +/* 4 wMaxPacketSize, bInterval */ D0(4),D1(4), 1, + +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + +/* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + +/* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + +/* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; +static UX_TEST_SETUP _GetCfgDescr = UX_TEST_SETUP_GetCfgDescr; +static UX_TEST_SETUP _SetAddress = UX_TEST_SETUP_SetAddress; +static UX_TEST_SETUP _GetDeviceDescriptor = UX_TEST_SETUP_GetDevDescr; +static UX_TEST_SETUP _GetConfigDescriptor = UX_TEST_SETUP_GetCfgDescr; + +/* Interaction define */ + +/* Hooks define */ + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* 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 ++; + printf("Error #%d, system_level: %d, system_context: %d, error_code: 0x%x\n", __LINE__, system_level, system_context, error_code); + + if (!error_callback_ignore) + { + { + /* Failed test. */ + 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_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_AUDIO *audio = (UX_HOST_CLASS_AUDIO *) inst; + + // printf("CHG:%lx,%p,%p\n", event, cls, inst); + switch(event) + { + + case UX_DEVICE_INSERTION: + + // printf("hINS:%p,%p:%lx\n", cls, inst, ux_host_class_audio_type_get(audio)); + if (ux_host_class_audio_subclass_get(audio) != UX_HOST_CLASS_AUDIO_CLASS) + { + if (ux_host_class_audio_type_get(audio) == UX_HOST_CLASS_AUDIO_INPUT) + host_audio_rx = audio; + else + host_audio_tx = audio; + } + else + host_audio_ac = (UX_HOST_CLASS_AUDIO_AC *)audio; + break; + + case UX_DEVICE_REMOVAL: + + // printf("hRMV:%p,%p:%lx\n", cls, inst, ux_host_class_audio_type_get(audio)); + if (ux_host_class_audio_subclass_get(audio) != UX_HOST_CLASS_AUDIO_CLASS) + { + if (audio == host_audio_rx) + host_audio_rx = UX_NULL; + if (audio == host_audio_tx) + host_audio_tx = UX_NULL; + } + else + if (audio == (UX_HOST_CLASS_AUDIO *)host_audio_ac) + host_audio_ac = UX_NULL; + break; + + default: + break; + } + return 0; +} + + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_mem_free_on_set_cfg = ux_test_regular_memory_free(); + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_msrc_81426_host_audio_type_get_fail_ac_link_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running MSRC 81426 - Audio Host Fail AC AS Link Test................ "); + +#if !UX_TEST_MULTI_IFC_ON || !UX_TEST_MULTI_ALT_ON || !UX_TEST_MULTI_CLS_ON || \ + !defined(UX_HOST_CLASS_AUDIO_2_SUPPORT) || \ + !defined(UX_HOST_CLASS_AUDIO_INTERRUPT_SUPPORT) || \ + (UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH < 260) + printf("SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + + stepinfo("\n"); + + /* 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(); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* 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_host_change_function); + UX_TEST_CHECK_SUCCESS(status); + + /* Register Audio class. */ + status = ux_host_stack_class_register(_ux_system_host_class_audio_name, ux_host_class_audio_entry); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Set the parameters for DUMMY. */ + ux_utility_memory_set(&dummy_parameter, 0, sizeof(UX_DEVICE_CLASS_DUMMY_PARAMETER)); + + /* Initialize the device DUMMY class. This class owns interfaces starting with 0, 1, 2. */ + status = ux_device_stack_class_register(_ux_device_class_dummy_name, _ux_device_class_dummy_entry, + 1, 0, &dummy_parameter); + UX_TEST_CHECK_SUCCESS(status); + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main event group. */ + status = tx_event_flags_create(&tx_test_events, "tx_test_events"); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx demo host simulation", tx_test_thread_host_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx demo slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_CHECK_SUCCESS(status); +} + +static UINT test_wait_until_expected(VOID **ptr, ULONG loop, VOID *expected) +{ + while(loop) + { + _ux_utility_delay_ms(10); + if (*ptr == expected) + return UX_SUCCESS; + } + return UX_ERROR; +} +static UINT test_wait_until_not_expected(VOID **ptr, ULONG loop, VOID *expected) +{ + while(loop) + { + _ux_utility_delay_ms(10); + if (*ptr != expected) + return UX_SUCCESS; + } + return UX_ERROR; +} +#define test_wait_until_not_null(ptr, loop) test_wait_until_not_expected(ptr, loop, UX_NULL) +#define test_wait_until_null(ptr, loop) test_wait_until_expected(ptr, loop, UX_NULL) + +static void _memory_tests(void) +{ +ULONG test_n; +ULONG mem_free; + + /* Test disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Reset testing counts. */ + ux_test_utility_sim_mutex_create_count_reset(); + ux_test_utility_sim_sem_create_count_reset(); + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + /* Save free memory usage. */ + mem_free = ux_test_regular_memory_free(); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + tx_thread_sleep(100); + /* Log create counts for further tests. */ + rsc_enum_mutex_usage = rsc_mutex_on_set_cfg; + rsc_enum_sem_usage = rsc_sem_on_set_cfg; + rsc_enum_mem_usage = mem_free - rsc_mem_free_on_set_cfg; + rsc_enum_mem_alloc_count = rsc_mem_alloc_cnt_on_set_cfg; + /* Log create counts when instances active for further tests. */ + rsc_audio_mutex_usage = ux_test_utility_sim_mutex_create_count() - rsc_enum_mutex_usage; + rsc_audio_sem_usage = ux_test_utility_sim_sem_create_count() - rsc_enum_sem_usage; + rsc_audio_mem_usage = rsc_mem_free_on_set_cfg - ux_test_regular_memory_free(); + rsc_audio_mem_alloc_count = ux_test_utility_sim_mem_alloc_count() - rsc_enum_mem_alloc_count; + stepinfo("mem free: %ld\n", ux_test_regular_memory_free()); + + /* Lock log base for tests. */ + ux_test_utility_sim_mem_alloc_log_lock(); + + stepinfo("enum mem: %ld\n", rsc_enum_mem_alloc_count); + stepinfo("cdc mem : %ld\n", rsc_audio_mem_alloc_count); + stepinfo("mem free: %ld, %ld\n", ux_test_regular_memory_free(), _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available); + + /* Simulate detach and attach for FS enumeration, + and check if there is memory error in normal enumeration. + */ + stepinfo(">>>>>>>>>>>> Enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < 3; test_n++) + { + stepinfo("%4ld / 2\n", test_n); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = ux_test_regular_memory_free(); + else if (mem_free != ux_test_regular_memory_free()) + { + + printf("ERROR #11.%ld: Memory level different after re-enumerations %ld <> %ld\n", test_n, mem_free, ux_test_regular_memory_free()); + test_control_return(1); + } + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on error. */ + ux_test_breakable_sleep(100, sleep_break_on_error); + + /* Check */ + if (!host_audio_tx || !host_audio_rx) + { + + printf("ERROR #12.%ld: Enumeration fail\n", test_n); + test_control_return(1); + } + } + + /* Simulate detach and attach for FS enumeration, + and test possible memory allocation error handlings. + */ + if (rsc_audio_mem_alloc_count) stepinfo(">>>>>>>>>>>> Memory errors enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_audio_mem_alloc_count; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_audio_mem_alloc_count - 1); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = ux_test_regular_memory_free(); + else if (mem_free != ux_test_regular_memory_free()) + { + + printf("ERROR #11.%ld: Memory level different after re-enumerations %ld <> %ld\n", test_n, mem_free, ux_test_regular_memory_free()); + test_control_return(1); + } + + /* Set memory error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n + rsc_enum_mem_alloc_count); + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on errors. */ + ux_test_breakable_sleep(100, sleep_break_on_error); + + /* Check error */ + if (host_audio_tx && host_audio_rx) + { + + printf("ERROR #12.%ld: device detected when there is memory error\n", test_n); + test_control_return(1); + } + stepinfo("mem free: %ld\n", ux_test_regular_memory_free()); + } + ux_test_utility_sim_mem_alloc_error_generation_stop(); + if (rsc_audio_mem_alloc_count) stepinfo("\n"); +} + +static void _audio_type_get_fail_ac_tests(void) +{ +ULONG mem_free; + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + UX_TEST_ASSERT(host_audio_ac == UX_NULL && host_audio_rx == UX_NULL && host_audio_tx == UX_NULL); + + /* Set framework. */ + _ux_system_slave -> ux_system_slave_device_framework_full_speed = device_framework_modified; + + /* Prepare descriptor ASD. */ + /* ------------------------ Audio 2.0 AS Interface Descriptor *//* @189+9=198 */ + /* 0 bLength, bDescriptorType, bDescriptorSubtype */// 16, 0x24, 0x01, + /* 3 bTerminalLink, bmControls */// 0x03,0x00, + _ux_utility_memory_copy(device_framework_modified, device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED); + UX_TEST_ASSERT(device_framework_modified[FRAMEWORK_POS_FULL_SPEED_ASD + 0] == 16); + UX_TEST_ASSERT(device_framework_modified[FRAMEWORK_POS_FULL_SPEED_ASD + 1] == 0x24); + UX_TEST_ASSERT(device_framework_modified[FRAMEWORK_POS_FULL_SPEED_ASD + 3] == 0x03);/* bTerminalLink */ + + /* Log memory. */ + mem_free = ux_test_regular_memory_free(); + + stepinfo(">>>>>>>>>> Fake descriptor _type_get fail - ASD::bTerminalLink=0\n"); + device_framework_modified[FRAMEWORK_POS_FULL_SPEED_ASD + 3] = 0; + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + /* Wait and break on error. */ + ux_test_breakable_sleep(100, sleep_break_on_error); + /* Check connection. */ + UX_TEST_ASSERT(host_audio_ac != UX_NULL); + UX_TEST_ASSERT(host_audio_rx == UX_NULL); + UX_TEST_ASSERT(host_audio_tx != UX_NULL); + UX_TEST_ASSERT(host_audio_ac->ux_host_class_audio_as_count == 2); + UX_TEST_ASSERT(host_audio_ac->ux_host_class_audio_as[0] == host_audio_tx); + UX_TEST_ASSERT(host_audio_ac->ux_host_class_audio_as[1] == UX_NULL); +#if defined(UX_HOST_CLASS_AUDIO_INTERRUPT_SUPPORT) + UX_TEST_ASSERT(host_audio_tx->ux_host_class_audio_ac == host_audio_ac); + UX_TEST_ASSERT(host_audio_tx->ux_host_class_audio_ac_as == 0); +#endif + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + /* Check memory. */ + UX_TEST_ASSERT(mem_free == ux_test_regular_memory_free()); + device_framework_modified[FRAMEWORK_POS_FULL_SPEED_ASD + 3] = 0x03; + + /* Set framework back. */ + _ux_system_slave -> ux_system_slave_device_framework_full_speed = device_framework_full_speed; +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +UCHAR test_tmp[32]; +ULONG temp; + + /* Test connect. */ + status = test_wait_until_not_null((void**)&host_audio_ac, 100); + status |= test_wait_until_not_null((void**)&host_audio_rx, 100); + status |= test_wait_until_not_null((void**)&host_audio_tx, 100); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(ux_host_class_audio_protocol_get(host_audio_rx) == UX_HOST_CLASS_AUDIO_PROTOCOL_IP_VERSION_02_00); + UX_TEST_ASSERT(ux_host_class_audio_type_get(host_audio_rx) == UX_HOST_CLASS_AUDIO_INPUT); + UX_TEST_ASSERT(ux_host_class_audio_speed_get(host_audio_rx) == UX_FULL_SPEED_DEVICE); + + _audio_type_get_fail_ac_tests(); + _memory_tests(); + + /* Wait pending threads. */ + _ux_utility_thread_sleep(1); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + ux_device_stack_class_unregister(_ux_device_class_dummy_name, _ux_device_class_dummy_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + while(1) + { + +#if UX_DEMO_FEEDBACK + UINT status; + ULONG events; + status = tx_event_flags_get(&tx_test_events, 0x1u, TX_OR_CLEAR, &events, 10); + if (status == UX_SUCCESS) + { + /* Simulate ISO transfer done event. */ + feedback_transfer -> ux_transfer_request_completion_code = UX_SUCCESS; + if (feedback_transfer -> ux_transfer_request_completion_function) + feedback_transfer -> ux_transfer_request_completion_function(feedback_transfer); + _ux_host_semaphore_put(&feedback_transfer -> ux_transfer_request_semaphore); + ux_utility_delay_ms(1); + } +#else + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); +#endif + } +} diff --git a/test/regression/usbx_msrc_81428_81429_host_audio_ac_search_test.c b/test/regression/usbx_msrc_81428_81429_host_audio_ac_search_test.c new file mode 100644 index 00000000..29a3fff3 --- /dev/null +++ b/test/regression/usbx_msrc_81428_81429_host_audio_ac_search_test.c @@ -0,0 +1,1152 @@ +/* This test is designed to test the simple dpump host/device class operation. */ +/* Compile option requires: + -DUX_HOST_CLASS_AUDIO_2_SUPPORT + -DUX_HOST_CLASS_AUDIO_INTERRUPT_SUPPORT + -DUX_SLAVE_REQUEST_CONTROL_MAX_LENGTH=512 +*/ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" + +#include "fx_api.h" + +#include "ux_device_stack.h" +#include "ux_device_class_dummy.h" + +#include "ux_host_class_audio.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_DEMO_REQUEST_MAX_LENGTH \ + ((UX_HCD_SIM_HOST_MAX_PAYLOAD) > (UX_SLAVE_REQUEST_DATA_MAX_LENGTH) ? \ + (UX_HCD_SIM_HOST_MAX_PAYLOAD) : (UX_SLAVE_REQUEST_DATA_MAX_LENGTH)) + +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_DEMO_REQUEST_MAX_LENGTH + 1) +#define UX_DEMO_MEMORY_SIZE (128*1024) + +#define UX_TEST_LOG_SIZE (64) + + +/* Define local/extern function prototypes. */ +static void test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static void tx_test_thread_host_simulation_entry(ULONG); +static void tx_test_thread_slave_simulation_entry(ULONG); + +static TX_EVENT_FLAGS_GROUP tx_test_events; + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[64]; + +static UX_HOST_CLASS_AUDIO_AC *host_audio_ac = UX_NULL; +static UX_HOST_CLASS_AUDIO *host_audio_tx = UX_NULL; +static UX_HOST_CLASS_AUDIO *host_audio_rx = UX_NULL; + +static UX_HOST_CLASS_AUDIO *audio = UX_NULL; + +static UX_DEVICE_CLASS_DUMMY *dummy[3]; +static UX_DEVICE_CLASS_DUMMY_PARAMETER dummy_parameter; + +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_mem_alloc_cnt_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_enum_mem_alloc_count; + +static ULONG rsc_audio_sem_usage; +static ULONG rsc_audio_sem_get_count; +static ULONG rsc_audio_mutex_usage; +static ULONG rsc_audio_mem_usage; +static ULONG rsc_audio_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +/* Define device framework. */ + +#define D3(d) ((UCHAR)((d) >> 24)) +#define D2(d) ((UCHAR)((d) >> 16)) +#define D1(d) ((UCHAR)((d) >> 8)) +#define D0(d) ((UCHAR)((d) >> 0)) + +static unsigned char device_framework_full_speed[] = { + +/* --------------------------------------- Device Descriptor *//* @0 */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x02, 0x00, +/* 12 bcdDevice */ D0(0x200),D1(0x200), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* ----------------------------- Device Qualifier Descriptor *//* @18 */ +/* 0 bLength, bDescriptorType */ 10, 0x06, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 bNumConfigurations */ 1, +/* 9 bReserved */ 0, + +/* -------------------------------- Configuration Descriptor *//* 9+8+135+55+62=269 *//* @28 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(269),D1(269), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------ Interface Association Descriptor *//* @37 */ +/* 0 bLength, bDescriptorType */ 8, 0x0B, +/* 2 bFirstInterface, bInterfaceCount */ 0, 3, +/* 4 bFunctionClass, bFunctionSubClass, bFunctionProtocol */ 0x01, 0x00, 0x20, +/* 7 iFunction */ 0, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+126=135) *//* @45 */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x20, +/* 8 iInterface */ 0, +/* ---------------- Audio 2.0 AC Interface Header Descriptor *//* (9+8+8+7+17*2+18*2+12*2=126) *//* @54 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x01, +/* 3 bcdADC, bCategory */ D0(0x200),D1(0x200), 0x08, +/* 6 wTotalLength */ D0(126),D1(126), +/* 8 bmControls */ 0x00, +/* -------------------- Audio 2.0 AC Clock Source Descriptor (0x11) *//* @63 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x24, 0x0A, +/* 3 bClockID, bmAttributes, bmControls */ 0x11, 0x05, 0x01, +/* 6 bAssocTerminal, iClockSource */ 0x00, 0, +/* -------------------- Audio 2.0 AC Clock Selector Descriptor (1x1, 0x12) *//* @71 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x24, 0x0B, +/* 3 bClockID, bNrInPins, baCSourceID1 */ 0x12, 0x01, 0x11, +/* 6 bmControls, iClockSelector */ 0x01, 0, +/* -------------------- Audio 2.0 AC Clock Multiplier Descriptor (0x10) *//* @79 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x0C, +/* 3 bClockID, bCSourceID, bmControls */ 0x10, 0x12, 0x05, +/* 6 iClockMultiplier */ 0, +/* ------------------- Audio 2.0 AC Input Terminal Descriptor *//* @86 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 17, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, bCSourceID */ 0x00, 0x10, +/* 8 bNrChannels, bmChannelConfig */ 0x02, D0(0),D1(0),D2(0),D3(0), +/* 13 iChannelNames, bmControls, iTerminal */ 0, D0(0),D1(0), 0, +/* --------------------- Audio 2.0 AC Feature Unit Descriptor *//* @86+17=103 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 18, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bmaControls(0), bmaControls(...) ... */ D0(0xF),D1(0xF),D2(0xF),D3(0xF), D0(0),D1(0),D2(0),D3(0), D0(0),D1(0),D2(0),D3(0), +/* . iFeature */ 0, +/* ------------------ Audio 2.0 AC Output Terminal Descriptor *//* @103+18=121 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID, bCSourceID */ 0x00, 0x02, 0x10, +/* 9 bmControls, iTerminal */ D0(0),D1(0), 0, +/* ------------------- Audio 2.0 AC Input Terminal Descriptor *//* @121+12=133 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 17, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bCSourceID */ 0x00, 0x10, +/* 8 bNrChannels, bmChannelConfig */ 0x02, D0(0),D1(0),D2(0),D3(0), +/* 13 iChannelNames, bmControls, iTerminal */ 0, D0(0),D1(0), 0, +/* --------------------- Audio 2.0 AC Feature Unit Descriptor *//* @133+17=150 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 18, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bmaControls(0), bmaControls(...) ... */ D0(0xF),D1(0xF),D2(0xF),D3(0xF), D0(0),D1(0),D2(0),D3(0), D0(0),D1(0),D2(0),D3(0), +/* . iFeature */ 0, +/* ------------------ Audio 2.0 AC Output Terminal Descriptor *//* @150+18=168 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID, bCSourceID */ 0x00, 0x05, 0x10, +/* 9 bmControls, iTerminal */ D0(0),D1(0), 0, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+16+6+7+8=55) *//* @168+12=180 */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor *//* @180+9=189 */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------ Audio 2.0 AS Interface Descriptor *//* @189+9=198 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 16, 0x24, 0x01, +/* 3 bTerminalLink, bmControls */ 0x03,0x00, +/* 5 bFormatType, bmFormats */ 0x01,D0(1),D1(1),D2(1),D3(1), +/* 10 bNrChannels, bmChannelConfig */ 2, D0(0),D1(0),D2(0),D3(0), +/* 15 iChannelNames */ 0, +/* -------------------- Audio 2.0 AS Format Type I Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 6, 0x24, 0x02, +/* 3 bFormatType, bSubslotSize, bBitResolution */ 0x01, 2, 16, +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x0D, +/* 4 wMaxPacketSize, bInterval */ D0(256),D1(256), 1, +/* ---------- Audio 2.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x25, 0x01, +/* 3 bmAttributes, bmControls */ 0x00, 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+16+6+7+8+7=62) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 2, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------ Audio 2.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 16, 0x24, 0x01, +/* 3 bTerminalLink, bmControls */ 0x04,0x00, +/* 5 bFormatType, bmFormats */ 0x01,D0(1),D1(1),D2(1),D3(1), +/* 10 bNrChannels, bmChannelConfig */ 2, D0(0),D1(0),D2(0),D3(0), +/* 15 iChannelNames */ 0, +/* ---------------------- Audio 2.0 AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 6, 0x24, 0x02, +/* 3 bFormatType, bSubslotSize, bBitResolution */ 0x01, 2, 16, +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x0D, +/* 4 wMaxPacketSize, bInterval */ D0(256),D1(256), 1, +/* ---------- Audio 2.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x25, 0x01, +/* 3 bmAttributes, bmControls */ 0x00, 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x82, 0x11, +/* 4 wMaxPacketSize, bInterval */ D0(4),D1(4), 1, + +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +#define FRAMEWORK_POS_FULL_SPEED_IAD (37) +#define FRAMEWORK_POS_FULL_SPEED_ITD (84) +#define FRAMEWORK_POS_FULL_SPEED_OTD (119) +#define FRAMEWORK_POS_FULL_SPEED_ASD (198) /* IFD::bTerminalLink@4 */ + +static unsigned char device_framework_full_speed_iad_audio10[] = { + +/* --------------------------------------- Device Descriptor *//* @0 */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 0x08, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x01, 0x00, +/* 12 bcdDevice */ D0(0x100),D1(0x100), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* -------------------------------- Configuration Descriptor *//* 9+8+88+52*2=209 *//* @18 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(209),D1(209), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------ Interface Association Descriptor *//* @27 */ +/* 0 bLength, bDescriptorType */ 8, 0x0B, +/* 2 bFirstInterface, bInterfaceCount */ 0, 3, +/* 4 bFunctionClass, bFunctionSubClass, bFunctionProtocol */ 0x01, 0x01, 0x00, +/* 7 iFunction */ 0, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+72+7=88) *//* @35 */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x00, +/* 8 iInterface */ 0, +/* ---------------- Audio 1.0 AC Interface Header Descriptor *//* (10+12*2+10*2+9*2=72) *//* @44 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x01, +/* 3 bcdADC */ 0x00, 0x01, +/* 5 wTotalLength, bInCollection */ D0(72),D1(72), 2, +/* 8 baInterfaceNr(1) ... baInterfaceNr(n) */ 1, 2, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor *//* @54 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor *//* @54+12=66 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor *//* @66+10=76 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x02, +/* 8 iTerminal */ 0, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor *//* @76+9=85 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor *//* @85+12=97 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor *//* @97+10=107 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x05, +/* 8 iTerminal */ 0, +/* --------------------- Audio 1.0 AC INT Endpoint Descriptor *//* @107+9=116 */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x83, 0x03, +/* 4 wMaxPacketSize, bInterval */ D0(8),D1(8), 1, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+7+11+9+7=52) *//* @116+7=123 */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor *//* @123+9=132 */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor *//* @132+9=141 */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x03, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 1, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x04, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 1, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +}; +#define FRAMEWORK_POS_FULL_SPEED_AC10 (44) +#define FRAMEWORK_POS_FULL_SPEED_ITD10 (54) +#define FRAMEWORK_POS_FULL_SPEED_OTD10 (76) +#define FRAMEWORK_POS_FULL_SPEED_ASD10 (141) /* bTerminalLink@4 */ +static UCHAR device_framework_modified[2048]; + +static unsigned char device_framework_high_speed[] = { +/* --------------------------------------- Device Descriptor */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 0x08, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x02, 0x00, +/* 12 bcdDevice */ D0(0x200),D1(0x200), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* ----------------------------- Device Qualifier Descriptor */ +/* 0 bLength, bDescriptorType */ 10, 0x06, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 bNumConfigurations */ 1, +/* 9 bReserved */ 0, + +/* -------------------------------- Configuration Descriptor *//* 9+8+135+55+62=269 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(269),D1(269), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------ Interface Association Descriptor */ +/* 0 bLength, bDescriptorType */ 8, 0x0B, +/* 2 bFirstInterface, bInterfaceCount */ 0, 3, +/* 4 bFunctionClass, bFunctionSubClass, bFunctionProtocol */ 0x01, 0x00, 0x20, +/* 7 iFunction */ 0, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+126=135) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x20, +/* 8 iInterface */ 0, +/* ---------------- Audio 2.0 AC Interface Header Descriptor *//* (9+8+8+7+17*2+18*2+12*2=126) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x01, +/* 3 bcdADC, bCategory */ D0(0x200),D1(0x200), 0x08, +/* 6 wTotalLength */ D0(126),D1(126), +/* 8 bmControls */ 0x00, +/* -------------------- Audio 2.0 AC Clock Source Descriptor (0x11) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x24, 0x0A, +/* 3 bClockID, bmAttributes, bmControls */ 0x11, 0x05, 0x01, +/* 6 bAssocTerminal, iClockSource */ 0x00, 0, +/* -------------------- Audio 2.0 AC Clock Selector Descriptor (1x1, 0x12) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x24, 0x0B, +/* 3 bClockID, bNrInPins, baCSourceID1 */ 0x12, 0x01, 0x11, +/* 6 bmControls, iClockSelector */ 0x01, 0, +/* -------------------- Audio 2.0 AC Clock Multiplier Descriptor (0x10) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x0C, +/* 3 bClockID, bCSourceID, bmControls */ 0x10, 0x12, 0x05, +/* 6 iClockMultiplier */ 0, +/* ------------------- Audio 2.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 17, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, bCSourceID */ 0x00, 0x10, +/* 8 bNrChannels, bmChannelConfig */ 0x02, D0(0),D1(0),D2(0),D3(0), +/* 13 iChannelNames, bmControls, iTerminal */ 0, D0(0),D1(0), 0, +/* --------------------- Audio 2.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 18, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bmaControls(0), bmaControls(...) ... */ D0(0xF),D1(0xF),D2(0xF),D3(0xF), D0(0),D1(0),D2(0),D3(0), D0(0),D1(0),D2(0),D3(0), +/* . iFeature */ 0, +/* ------------------ Audio 2.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID, bCSourceID */ 0x00, 0x02, 0x10, +/* 9 bmControls, iTerminal */ D0(0),D1(0), 0, +/* ------------------- Audio 2.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 17, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bCSourceID */ 0x00, 0x10, +/* 8 bNrChannels, bmChannelConfig */ 0x02, D0(0),D1(0),D2(0),D3(0), +/* 13 iChannelNames, bmControls, iTerminal */ 0, D0(0),D1(0), 0, +/* --------------------- Audio 2.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 18, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bmaControls(0), bmaControls(...) ... */ D0(0xF),D1(0xF),D2(0xF),D3(0xF), D0(0),D1(0),D2(0),D3(0), D0(0),D1(0),D2(0),D3(0), +/* . iFeature */ 0, +/* ------------------ Audio 2.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID, bCSourceID */ 0x00, 0x05, 0x10, +/* 9 bmControls, iTerminal */ D0(0),D1(0), 0, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+16+6+7+8=55) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------ Audio 2.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 16, 0x24, 0x01, +/* 3 bTerminalLink, bmControls */ 0x03,0x00, +/* 5 bFormatType, bmFormats */ 0x01,D0(1),D1(1),D2(1),D3(1), +/* 10 bNrChannels, bmChannelConfig */ 2, D0(0),D1(0),D2(0),D3(0), +/* 15 iChannelNames */ 0, +/* -------------------- Audio 2.0 AS Format Type I Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 6, 0x24, 0x02, +/* 3 bFormatType, bSubslotSize, bBitResolution */ 0x01, 2, 16, +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x0D, +/* 4 wMaxPacketSize, bInterval */ D0(256),D1(256), 4, +/* ---------- Audio 2.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x25, 0x01, +/* 3 bmAttributes, bmControls */ 0x00, 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+16+6+7+8+7=62) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 2, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x20, +/* 8 iInterface */ 0, +/* ------------------------ Audio 2.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 16, 0x24, 0x01, +/* 3 bTerminalLink, bmControls */ 0x04,0x00, +/* 5 bFormatType, bmFormats */ 0x01,D0(1),D1(1),D2(1),D3(1), +/* 10 bNrChannels, bmChannelConfig */ 2, D0(0),D1(0),D2(0),D3(0), +/* 15 iChannelNames */ 0, +/* ---------------------- Audio 2.0 AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 6, 0x24, 0x02, +/* 3 bFormatType, bSubslotSize, bBitResolution */ 0x01, 2, 16, +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x0D, +/* 4 wMaxPacketSize, bInterval */ D0(256),D1(256), 4, +/* ---------- Audio 2.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 8, 0x25, 0x01, +/* 3 bmAttributes, bmControls */ 0x00, 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +/* ------------------------------------- Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x82, 0x11, +/* 4 wMaxPacketSize, bInterval */ D0(4),D1(4), 1, + +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + +/* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + +/* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + +/* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; +static UX_TEST_SETUP _GetCfgDescr = UX_TEST_SETUP_GetCfgDescr; +static UX_TEST_SETUP _SetAddress = UX_TEST_SETUP_SetAddress; +static UX_TEST_SETUP _GetDeviceDescriptor = UX_TEST_SETUP_GetDevDescr; +static UX_TEST_SETUP _GetConfigDescriptor = UX_TEST_SETUP_GetCfgDescr; + +/* Interaction define */ + +/* Hooks define */ + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* 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 ++; + printf("Error #%d, system_level: %d, system_context: %d, error_code: 0x%x\n", __LINE__, system_level, system_context, error_code); + + if (!error_callback_ignore) + { + { + /* Failed test. */ + 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_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_AUDIO *audio = (UX_HOST_CLASS_AUDIO *) inst; + + // printf("CHG:%lx,%p,%p\n", event, cls, inst); + switch(event) + { + + case UX_DEVICE_INSERTION: + + // printf("hINS:%p,%p:%lx\n", cls, inst, ux_host_class_audio_type_get(audio)); + if (ux_host_class_audio_subclass_get(audio) != UX_HOST_CLASS_AUDIO_CLASS) + { + if (ux_host_class_audio_type_get(audio) == UX_HOST_CLASS_AUDIO_INPUT) + host_audio_rx = audio; + else + host_audio_tx = audio; + } + else + host_audio_ac = (UX_HOST_CLASS_AUDIO_AC *)audio; + break; + + case UX_DEVICE_REMOVAL: + + // printf("hRMV:%p,%p:%lx\n", cls, inst, ux_host_class_audio_type_get(audio)); + if (ux_host_class_audio_subclass_get(audio) != UX_HOST_CLASS_AUDIO_CLASS) + { + if (audio == host_audio_rx) + host_audio_rx = UX_NULL; + if (audio == host_audio_tx) + host_audio_tx = UX_NULL; + } + else + if (audio == (UX_HOST_CLASS_AUDIO *)host_audio_ac) + host_audio_ac = UX_NULL; + break; + + default: + break; + } + return 0; +} + + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_mem_free_on_set_cfg = ux_test_regular_memory_free(); + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_msrc_81428_81429_host_audio_ac_search_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running MSRC 81428/81429 - Audio Host AC Search Test................ "); + +#if !UX_TEST_MULTI_IFC_ON || !UX_TEST_MULTI_ALT_ON || !UX_TEST_MULTI_CLS_ON || \ + !defined(UX_HOST_CLASS_AUDIO_2_SUPPORT) || \ + !defined(UX_HOST_CLASS_AUDIO_INTERRUPT_SUPPORT) || \ + (UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH < 260) + printf("SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + + stepinfo("\n"); + + /* 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(); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* 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_host_change_function); + UX_TEST_CHECK_SUCCESS(status); + + /* Register Audio class. */ + status = ux_host_stack_class_register(_ux_system_host_class_audio_name, ux_host_class_audio_entry); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Set the parameters for DUMMY. */ + ux_utility_memory_set(&dummy_parameter, 0, sizeof(UX_DEVICE_CLASS_DUMMY_PARAMETER)); + + /* Initialize the device DUMMY class. This class owns interfaces starting with 0, 1, 2. */ + status = ux_device_stack_class_register(_ux_device_class_dummy_name, _ux_device_class_dummy_entry, + 1, 0, &dummy_parameter); + UX_TEST_CHECK_SUCCESS(status); + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main event group. */ + status = tx_event_flags_create(&tx_test_events, "tx_test_events"); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx demo host simulation", tx_test_thread_host_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx demo slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_CHECK_SUCCESS(status); +} + +static UINT test_wait_until_expected(VOID **ptr, ULONG loop, VOID *expected) +{ + while(loop) + { + _ux_utility_delay_ms(10); + if (*ptr == expected) + return UX_SUCCESS; + } + return UX_ERROR; +} +static UINT test_wait_until_not_expected(VOID **ptr, ULONG loop, VOID *expected) +{ + while(loop) + { + _ux_utility_delay_ms(10); + if (*ptr != expected) + return UX_SUCCESS; + } + return UX_ERROR; +} +#define test_wait_until_not_null(ptr, loop) test_wait_until_not_expected(ptr, loop, UX_NULL) +#define test_wait_until_null(ptr, loop) test_wait_until_expected(ptr, loop, UX_NULL) + +static void _memory_tests(void) +{ +ULONG test_n; +ULONG mem_free; + + /* Test disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Reset testing counts. */ + ux_test_utility_sim_mutex_create_count_reset(); + ux_test_utility_sim_sem_create_count_reset(); + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + /* Save free memory usage. */ + mem_free = ux_test_regular_memory_free(); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + tx_thread_sleep(100); + /* Log create counts for further tests. */ + rsc_enum_mutex_usage = rsc_mutex_on_set_cfg; + rsc_enum_sem_usage = rsc_sem_on_set_cfg; + rsc_enum_mem_usage = mem_free - rsc_mem_free_on_set_cfg; + rsc_enum_mem_alloc_count = rsc_mem_alloc_cnt_on_set_cfg; + /* Log create counts when instances active for further tests. */ + rsc_audio_mutex_usage = ux_test_utility_sim_mutex_create_count() - rsc_enum_mutex_usage; + rsc_audio_sem_usage = ux_test_utility_sim_sem_create_count() - rsc_enum_sem_usage; + rsc_audio_mem_usage = rsc_mem_free_on_set_cfg - ux_test_regular_memory_free(); + rsc_audio_mem_alloc_count = ux_test_utility_sim_mem_alloc_count() - rsc_enum_mem_alloc_count; + stepinfo("mem free: %ld\n", ux_test_regular_memory_free()); + + /* Lock log base for tests. */ + ux_test_utility_sim_mem_alloc_log_lock(); + + stepinfo("enum mem: %ld\n", rsc_enum_mem_alloc_count); + stepinfo("cdc mem : %ld\n", rsc_audio_mem_alloc_count); + stepinfo("mem free: %ld, %ld\n", ux_test_regular_memory_free(), _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available); + + /* Simulate detach and attach for FS enumeration, + and check if there is memory error in normal enumeration. + */ + stepinfo(">>>>>>>>>>>> Enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < 3; test_n++) + { + stepinfo("%4ld / 2\n", test_n); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = ux_test_regular_memory_free(); + else if (mem_free != ux_test_regular_memory_free()) + { + + printf("ERROR #11.%ld: Memory level different after re-enumerations %ld <> %ld\n", test_n, mem_free, ux_test_regular_memory_free()); + test_control_return(1); + } + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on error. */ + ux_test_breakable_sleep(100, sleep_break_on_error); + + /* Check */ + if (!host_audio_tx || !host_audio_rx) + { + + printf("ERROR #12.%ld: Enumeration fail\n", test_n); + test_control_return(1); + } + } + + /* Simulate detach and attach for FS enumeration, + and test possible memory allocation error handlings. + */ + if (rsc_audio_mem_alloc_count) stepinfo(">>>>>>>>>>>> Memory errors enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_audio_mem_alloc_count; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_audio_mem_alloc_count - 1); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = ux_test_regular_memory_free(); + else if (mem_free != ux_test_regular_memory_free()) + { + + printf("ERROR #11.%ld: Memory level different after re-enumerations %ld <> %ld\n", test_n, mem_free, ux_test_regular_memory_free()); + test_control_return(1); + } + + /* Set memory error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n + rsc_enum_mem_alloc_count); + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on errors. */ + ux_test_breakable_sleep(100, sleep_break_on_error); + + /* Check error */ + if (host_audio_tx && host_audio_rx) + { + + printf("ERROR #12.%ld: device detected when there is memory error\n", test_n); + test_control_return(1); + } + stepinfo("mem free: %ld\n", ux_test_regular_memory_free()); + } + ux_test_utility_sim_mem_alloc_error_generation_stop(); + if (rsc_audio_mem_alloc_count) stepinfo("\n"); +} + +static UX_HOST_CLASS_COMMAND class_command; +static UX_DEVICE fake_device; +static UX_CONFIGURATION fake_configuration; +static UX_INTERFACE fake_interface; +static UX_HOST_CLASS_AUDIO_AC fake_ac; +static UX_HOST_CLASS *good_cls; +static UX_CONFIGURATION *good_cfg; +static void _activate_interfaces(UX_INTERFACE *first_interface) +{ +UX_INTERFACE *interface_ptr = first_interface; + class_command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_ACTIVATE; + while(interface_ptr) + { + if (interface_ptr -> ux_interface_descriptor.bAlternateSetting == 0) + { + if (interface_ptr -> ux_interface_class) + { + class_command.ux_host_class_command_container = (VOID *) interface_ptr; + class_command.ux_host_class_command_class_ptr = interface_ptr -> ux_interface_class; + + interface_ptr -> ux_interface_class -> ux_host_class_entry_function(&class_command); + } + } + interface_ptr = interface_ptr -> ux_interface_next_interface; + } +} +static void _deactivate_interfaces(UX_INTERFACE *first_interface) +{ +UX_INTERFACE *interface_ptr = first_interface; + class_command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_DEACTIVATE; + while (interface_ptr) + { + if (interface_ptr -> ux_interface_class_instance) + { + class_command.ux_host_class_command_instance = interface_ptr -> ux_interface_class_instance; + + interface_ptr -> ux_interface_class -> ux_host_class_entry_function(&class_command); + } + interface_ptr = interface_ptr -> ux_interface_next_interface; + } + +} + +/* AC must not be linked if bInterfaceNumber equal but subclass not expected */ +static void _msrc_81428_audio_ac_type_tests(void) +{ + stepinfo(">>>>>>>>>>>> AC Search Test: ifc_n same but subclass mismatch\n"); + + stepinfo(">>>>>>>>>>>> AC Search Test: clear class instances\n"); + _deactivate_interfaces(good_cfg -> ux_configuration_first_interface); + UX_TEST_ASSERT(host_audio_ac == UX_NULL); + UX_TEST_ASSERT(host_audio_rx == UX_NULL); + UX_TEST_ASSERT(host_audio_tx == UX_NULL); + stepinfo(">>>>>>>>>>>> AC Search Test: insert fake class instance in head (IFC 0.1,CLS 2)\n"); + fake_ac.ux_host_class_audio_interface = &fake_interface; + fake_interface.ux_interface_configuration = good_cfg; + fake_configuration.ux_configuration_first_interface = &fake_interface; + fake_configuration.ux_configuration_device = &fake_device; + fake_interface.ux_interface_descriptor.bInterfaceNumber = 0; + fake_interface.ux_interface_descriptor.bAlternateSetting = 1; + fake_interface.ux_interface_descriptor.bInterfaceClass = UX_HOST_CLASS_AUDIO_CLASS; + fake_interface.ux_interface_descriptor.bInterfaceSubClass = UX_HOST_CLASS_AUDIO_SUBCLASS_STREAMING; + _ux_host_stack_class_instance_create(good_cls, (VOID *)&fake_ac); + stepinfo(">>>>>>>>>>>> AC Search Test: create class instance\n"); + _activate_interfaces(good_cfg -> ux_configuration_first_interface); + stepinfo(">>>>>>>>>>>> AC Search Test: Validate connections\n"); + UX_TEST_ASSERT(host_audio_ac != UX_NULL); + UX_TEST_ASSERT(host_audio_rx != UX_NULL); + UX_TEST_ASSERT(host_audio_tx != UX_NULL); + UX_TEST_ASSERT(host_audio_ac->ux_host_class_audio_as_count == 2); + UX_TEST_ASSERT(host_audio_ac->ux_host_class_audio_as[0] == host_audio_rx); + UX_TEST_ASSERT(host_audio_ac->ux_host_class_audio_as[1] == host_audio_tx); + UX_TEST_ASSERT(host_audio_rx -> ux_host_class_audio_ac == host_audio_ac); + UX_TEST_ASSERT(host_audio_tx -> ux_host_class_audio_ac == host_audio_ac); + stepinfo(">>>>>>>>>>>> AC Search Test: clear class instances\n"); + _deactivate_interfaces(good_cfg -> ux_configuration_first_interface); + UX_TEST_ASSERT(host_audio_ac == UX_NULL); + UX_TEST_ASSERT(host_audio_rx == UX_NULL); + UX_TEST_ASSERT(host_audio_tx == UX_NULL); + stepinfo(">>>>>>>>>>>> AC Search Test: destroy fake class instance\n"); + _ux_host_stack_class_instance_destroy(good_cls, (VOID *)&fake_ac); + stepinfo(">>>>>>>>>>>> AC Search Test: create class instances\n"); + _activate_interfaces(good_cfg -> ux_configuration_first_interface); +} + +/* AC must not be linked if device not the same. */ +static void _msrc_81429_audio_ac_device_tests(void) +{ + stepinfo(">>>>>>>>>>>> AC Search Test: ifc_n same but device/configuration mismatch\n"); + + stepinfo(">>>>>>>>>>>> AC Search Test: clear class instances\n"); + _deactivate_interfaces(good_cfg -> ux_configuration_first_interface); + UX_TEST_ASSERT(host_audio_ac == UX_NULL); + UX_TEST_ASSERT(host_audio_rx == UX_NULL); + UX_TEST_ASSERT(host_audio_tx == UX_NULL); + stepinfo(">>>>>>>>>>>> AC Search Test: insert fake class instance in head (DEV/CFG different)\n"); + fake_ac.ux_host_class_audio_interface = &fake_interface; + fake_interface.ux_interface_configuration = &fake_configuration; + fake_configuration.ux_configuration_first_interface = &fake_interface; + fake_configuration.ux_configuration_device = &fake_device; + fake_interface.ux_interface_descriptor.bInterfaceNumber = 0; + fake_interface.ux_interface_descriptor.bAlternateSetting = 0; + fake_interface.ux_interface_descriptor.bInterfaceClass = UX_HOST_CLASS_AUDIO_CLASS; + fake_interface.ux_interface_descriptor.bInterfaceSubClass = UX_HOST_CLASS_AUDIO_SUBCLASS_CONTROL; + _ux_host_stack_class_instance_create(good_cls, (VOID *)&fake_ac); + stepinfo(">>>>>>>>>>>> AC Search Test: create class instances\n"); + _activate_interfaces(good_cfg -> ux_configuration_first_interface); + stepinfo(">>>>>>>>>>>> AC Search Test: Validate connections\n"); + UX_TEST_ASSERT(host_audio_ac != UX_NULL); + UX_TEST_ASSERT(host_audio_rx != UX_NULL); + UX_TEST_ASSERT(host_audio_tx != UX_NULL); + UX_TEST_ASSERT(host_audio_ac->ux_host_class_audio_as_count == 2); + UX_TEST_ASSERT(host_audio_ac->ux_host_class_audio_as[0] == host_audio_rx); + UX_TEST_ASSERT(host_audio_ac->ux_host_class_audio_as[1] == host_audio_tx); + UX_TEST_ASSERT(host_audio_rx -> ux_host_class_audio_ac == host_audio_ac); + UX_TEST_ASSERT(host_audio_tx -> ux_host_class_audio_ac == host_audio_ac); + stepinfo(">>>>>>>>>>>> AC Search Test: clear class instances\n"); + _deactivate_interfaces(good_cfg -> ux_configuration_first_interface); + UX_TEST_ASSERT(host_audio_ac == UX_NULL); + UX_TEST_ASSERT(host_audio_rx == UX_NULL); + UX_TEST_ASSERT(host_audio_tx == UX_NULL); + stepinfo(">>>>>>>>>>>> AC Search Test: destroy fake class instance\n"); + _ux_host_stack_class_instance_destroy(good_cls, (VOID *)&fake_ac); + stepinfo(">>>>>>>>>>>> AC Search Test: create class instances\n"); + _activate_interfaces(good_cfg -> ux_configuration_first_interface); +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +UCHAR test_tmp[32]; +ULONG temp; + + /* Test connect. */ + status = test_wait_until_not_null((void**)&host_audio_ac, 100); + status |= test_wait_until_not_null((void**)&host_audio_rx, 100); + status |= test_wait_until_not_null((void**)&host_audio_tx, 100); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(ux_host_class_audio_protocol_get(host_audio_rx) == UX_HOST_CLASS_AUDIO_PROTOCOL_IP_VERSION_02_00); + UX_TEST_ASSERT(ux_host_class_audio_type_get(host_audio_rx) == UX_HOST_CLASS_AUDIO_INPUT); + UX_TEST_ASSERT(ux_host_class_audio_speed_get(host_audio_rx) == UX_FULL_SPEED_DEVICE); + + _memory_tests(); + good_cls = host_audio_ac -> ux_host_class_audio_class; + good_cfg = host_audio_ac -> ux_host_class_audio_interface -> ux_interface_configuration; + + _msrc_81428_audio_ac_type_tests(); + _msrc_81429_audio_ac_device_tests(); + + /* Wait pending threads. */ + _ux_utility_thread_sleep(1); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + ux_device_stack_class_unregister(_ux_device_class_dummy_name, _ux_device_class_dummy_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + while(1) + { + +#if UX_DEMO_FEEDBACK + UINT status; + ULONG events; + status = tx_event_flags_get(&tx_test_events, 0x1u, TX_OR_CLEAR, &events, 10); + if (status == UX_SUCCESS) + { + /* Simulate ISO transfer done event. */ + feedback_transfer -> ux_transfer_request_completion_code = UX_SUCCESS; + if (feedback_transfer -> ux_transfer_request_completion_function) + feedback_transfer -> ux_transfer_request_completion_function(feedback_transfer); + _ux_host_semaphore_put(&feedback_transfer -> ux_transfer_request_semaphore); + ux_utility_delay_ms(1); + } +#else + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); +#endif + } +} diff --git a/test/regression/usbx_msrc_81489_81570_host_cdc_acm_standalone_ac_search_test.c b/test/regression/usbx_msrc_81489_81570_host_cdc_acm_standalone_ac_search_test.c new file mode 100644 index 00000000..2e89e5a0 --- /dev/null +++ b/test/regression/usbx_msrc_81489_81570_host_cdc_acm_standalone_ac_search_test.c @@ -0,0 +1,611 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" +#include "ux_host_class_cdc_acm.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 + +#define UX_DEMO_MEMORY_SIZE (64*1024) + +/* Define local/extern function prototypes. */ +static TX_THREAD ux_test_thread_host_simulation; +static TX_THREAD ux_test_thread_device_simulation; +static void ux_test_thread_host_simulation_entry(ULONG); +static void ux_test_thread_device_simulation_entry(ULONG); + +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; +static UCHAR cdc_acm_slave_change; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_cdc_sem_usage; +static ULONG rsc_cdc_sem_get_count; +static ULONG rsc_cdc_mutex_usage; +static ULONG rsc_cdc_mem_alloc_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +/* Define device framework. */ + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 93 +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 103 +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Configuration 1 descriptor 9 bytes */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Endpoint 0x83 descriptor 7 bytes */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, /* @ 93 - 14 + 2 = 81 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, /* @ 93 - 7 + 2 = 88 */ + 0x02, + 0x40, 0x00, + 0x00, + +}; + +#define DEVICE_FRAMEWORK_EPA_POS_1_FS (DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 14 + 2) +#define DEVICE_FRAMEWORK_EPA_POS_2_FS (DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 7 + 2) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor */ + 0x05, 0x24, 0x06, + 0x00, + 0x01, + + /* Call Management Functional Descriptor */ + 0x05, 0x24, 0x01, + 0x00, + 0x01, + + /* Endpoint 0x83 descriptor */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor */ + 0x07, 0x05, 0x02, /* @ 103 - 14 + 2 = 91 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor */ + 0x07, 0x05, 0x81, /* @ 103 - 7 + 2 = 98 */ + 0x02, + 0x40, 0x00, + 0x00, + +}; + +#define DEVICE_FRAMEWORK_EPA_POS_1_HS (DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 14 + 2) +#define DEVICE_FRAMEWORK_EPA_POS_2_HS (DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 7 + 2) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 + }; + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +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; +} + +static UINT demo_class_cdc_acm_get(void) +{ + +UINT status; +UX_HOST_CLASS *class_inst; +UX_HOST_CLASS_CDC_ACM *cdc_acm_host; +ULONG n_loop = 1000 * 1000; + + /* Wait while background task preparing instances. */ + while(n_loop) + { + if (cdc_acm_host_control && cdc_acm_host_data) + return(UX_SUCCESS); + +#if defined(UX_HOST_STANDALONE) + ux_system_tasks_run(); +#endif + tx_thread_sleep(1); + n_loop -= 10; + } + + /* Return ERROR. */ + return(UX_ERROR); +} + +static UINT demo_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + { + /* Confirm link to control is cleared on control removal. */ + UX_TEST_ASSERT(cdc_acm_host_data -> ux_host_class_cdc_acm_control == cdc_acm_host_control); + cdc_acm_host_data = UX_NULL; + } + break; + +#if defined(UX_HOST_STANDALONE) + case UX_STANDALONE_WAIT_BACKGROUND_TASK: + tx_thread_relinquish(); + break; +#endif + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *_params) +{ + + set_cfg_counter ++; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_sem_get_on_set_cfg = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_msrc_81489_81570_standalone_cdc_acm_ac_search_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + /* Inform user. */ + printf("Running MSRC 81489/570 - STANDALONE CDC ACM AC Search Test.......... "); +#if !defined(UX_HOST_STANDALONE) + printf("SKIP\n"); + test_control_return(1); + return; +#endif + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* 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(demo_system_host_change_function); + UX_TEST_CHECK_SUCCESS(status); + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_entry); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + ux_utility_memory_set(¶meter, 0, sizeof(parameter)); + parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + UX_TEST_CHECK_SUCCESS(status); + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_host_simulation, "tx demo host simulation", ux_test_thread_host_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_ASSERT(status == TX_SUCCESS); + +#if 0 + /* Create the main slave simulation thread. */ + status = tx_thread_create(&ux_test_thread_device_simulation, "tx demo slave simulation", ux_test_thread_device_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_ASSERT(status == TX_SUCCESS); +#endif +} + +static UX_HOST_CLASS_COMMAND class_command; +static UX_DEVICE fake_device; +static UX_CONFIGURATION fake_configuration; +static UX_INTERFACE fake_interface[2]; +static UX_HOST_CLASS_CDC_ACM fake_cdc[2]; +static UX_HOST_CLASS *good_cls; +static UX_CONFIGURATION *good_cfg; + +/* Control must not be linked if not expected. */ +static void _msrc_81489_81570_cdc_activate_data_control_search_link_tests(void) +{ +UINT status; + + stepinfo(">>>>>>>>>>>> ACM Search Test: disconnect - clear class instances\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + UX_TEST_ASSERT(cdc_acm_host_control == UX_NULL); + UX_TEST_ASSERT(cdc_acm_host_data == UX_NULL); + + stepinfo(">>>>>>>>>>>> ACM Search Test: insert fake class instance in head (DEV/CFG different)\n"); + fake_interface[0].ux_interface_configuration = &fake_configuration; + fake_interface[0].ux_interface_next_interface = &fake_interface[0]; + fake_interface[1].ux_interface_configuration = &fake_configuration; + fake_configuration.ux_configuration_first_interface = &fake_interface[0]; + fake_configuration.ux_configuration_device = &fake_device; + + fake_cdc[0].ux_host_class_cdc_acm_interface = &fake_interface[0]; + fake_cdc[0].ux_host_class_cdc_acm_interfaces_bitmap = 0x3u; + fake_cdc[0].ux_host_class_cdc_acm_control = UX_NULL; + fake_interface[0].ux_interface_descriptor.bInterfaceNumber = 0; + fake_interface[0].ux_interface_descriptor.bAlternateSetting = 0; + fake_interface[0].ux_interface_descriptor.bInterfaceClass = UX_HOST_CLASS_CDC_CONTROL_CLASS; + fake_interface[0].ux_interface_descriptor.bInterfaceSubClass = UX_HOST_CLASS_CDC_ACM_SUBCLASS; + + fake_cdc[1].ux_host_class_cdc_acm_interface = &fake_interface[1]; + fake_cdc[1].ux_host_class_cdc_acm_control = UX_NULL; + fake_interface[1].ux_interface_descriptor.bInterfaceNumber = 0; + fake_interface[1].ux_interface_descriptor.bAlternateSetting = 0; + fake_interface[1].ux_interface_descriptor.bInterfaceClass = UX_HOST_CLASS_CDC_DATA_CLASS; + fake_interface[1].ux_interface_descriptor.bInterfaceSubClass = 0; + _ux_host_stack_class_instance_create(good_cls, (VOID *)&fake_cdc[0]); + _ux_host_stack_class_instance_create(good_cls, (VOID *)&fake_cdc[1]); + + stepinfo(">>>>>>>>>>>> ACM Search Test: connect - create class instances\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + status = demo_class_cdc_acm_get(); + UX_TEST_CHECK_SUCCESS(status); + + stepinfo(">>>>>>>>>>>> ACM Search Test: Validate connections\n"); + UX_TEST_ASSERT(cdc_acm_host_control != UX_NULL); + UX_TEST_ASSERT(cdc_acm_host_data != UX_NULL); + /* Fakes must not be linked (in normal). */ + UX_TEST_ASSERT(cdc_acm_host_control -> ux_host_class_cdc_acm_control == cdc_acm_host_control); + UX_TEST_ASSERT(cdc_acm_host_data -> ux_host_class_cdc_acm_control == cdc_acm_host_control); + /* Fakes must not be linked (update of fake). */ + UX_TEST_ASSERT(fake_cdc[0].ux_host_class_cdc_acm_control == UX_NULL); + UX_TEST_ASSERT(fake_cdc[1].ux_host_class_cdc_acm_control == UX_NULL); + + stepinfo(">>>>>>>>>>>> ACM Search Test: destroy fake class instance\n"); + _ux_host_stack_class_instance_destroy(good_cls, (VOID *)&fake_cdc[0]); + _ux_host_stack_class_instance_destroy(good_cls, (VOID *)&fake_cdc[1]); + + stepinfo(">>>>>>>>>>>> ACM Search Test: clear class instances\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + UX_TEST_ASSERT(cdc_acm_host_control == UX_NULL); + UX_TEST_ASSERT(cdc_acm_host_data == UX_NULL); +} + +static void ux_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; + + stepinfo("\n"); + + /* Find the cdc_acm class and wait for the link to be up. */ + status = demo_class_cdc_acm_get(); + UX_TEST_CHECK_SUCCESS(status); + + good_cls = cdc_acm_host_control -> ux_host_class_cdc_acm_class; + good_cfg = cdc_acm_host_control -> ux_host_class_cdc_acm_device -> ux_device_current_configuration; + + _msrc_81489_81570_cdc_activate_data_control_search_link_tests(); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_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); + +} diff --git a/test/regression/usbx_msrc_81572_standalone_host_printer_allocated_enum_free_test.c b/test/regression/usbx_msrc_81572_standalone_host_printer_allocated_enum_free_test.c new file mode 100644 index 00000000..d09156bd --- /dev/null +++ b/test/regression/usbx_msrc_81572_standalone_host_printer_allocated_enum_free_test.c @@ -0,0 +1,497 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_printer.h" +#include "ux_device_stack.h" +#include "ux_host_class_printer.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); + +static TX_THREAD tx_test_thread_printer_read; +static TX_THREAD tx_test_thread_printer_write; +static TX_SEMAPHORE tx_test_semaphore_printer_trigger; +static VOID tx_test_printer_read_entry(ULONG); +static VOID tx_test_printer_write_entry(ULONG); + +static VOID ux_test_hcd_entry_should_not_be_called(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_disconnect(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 4)]; + +static UX_DEVICE *device = UX_NULL; +static UX_HOST_CLASS_PRINTER *host_printer = UX_NULL; +static UCHAR host_buffer[UX_DEMO_BUFFER_SIZE * 8]; + +static ULONG enum_counter; + +static ULONG error_counter; +static ULONG error_callback_counter; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_on_set_cfg; +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_enum_mem_alloc_count; + +static ULONG rsc_test_sem_usage; +static ULONG rsc_test_sem_get_count; +static ULONG rsc_test_mutex_usage; +static ULONG rsc_test_mem_alloc_count; + +static UX_DEVICE_CLASS_PRINTER *device_printer = UX_NULL; +static UX_DEVICE_CLASS_PRINTER_PARAMETER device_printer_parameter; +static UCHAR device_buffer[UX_DEMO_BUFFER_SIZE * 8]; +static ULONG device_buffer_length = 0; +UCHAR _ux_device_class_printer_name[] = "_ux_device_class_printer"; + +/* Device printer device ID. */ +static UCHAR printer_device_id[] = + { + " " // Length (changed later) + "MFG:Generic;" // manufacturer (case sensitive) + "MDL:Generic_/_Text_Only;" // model (case sensitive) + "CMD:1284.4;" // PDL command set + "CLS:PRINTER;" // class + "DES:Generic text only printer;" // description + }; + +/* Define device framework. */ + +#define _W0(w) ( (w) & 0xFF) +#define _W1(w) (((w) >> 8) & 0xFF) + +#define _CONFIGURATION_DESCRIPTOR(total_len, n_ifc, cfg_val) \ + 0x09, 0x02, _W0(total_len), _W1(total_len), (n_ifc), (cfg_val), \ + 0x00, 0xc0, 0x32, + +#define _INTERFACE_DESCRIPTOR(ifc_n, alt, n_ep, cls, sub, protocol) \ + 0x09, 0x04, (ifc_n), (alt), (n_ep), (cls), (sub), (protocol), 0x00, + +#define _ENDPOINT_DESCRIPTOR(addr, attr, pktsize, interval) \ + 0x07, 0x05, (addr), (attr), _W0(pktsize), _W1(pktsize), (interval), + +#define _CFG_TOTAL_LEN (9+9+7+7) + +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0xEF bDeviceClass: Composite class code + 0x02 bDeviceSubclass: class sub code + 0x00 bDeviceProtocol: Device protocol + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0x00, 0x00, 0x00, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 0x03, + 0x01, + + _CONFIGURATION_DESCRIPTOR(_CFG_TOTAL_LEN, 1, 1) + _INTERFACE_DESCRIPTOR(0, 0, 2, 0x07, 0x01, 0x02) + _ENDPOINT_DESCRIPTOR(0x01, 0x02, 64, 0x00) + _ENDPOINT_DESCRIPTOR(0x82, 0x02, 64, 0x00) +}; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_full_speed) +#define device_framework_high_speed device_framework_full_speed + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "AzureRTOS" */ + 0x09, 0x04, 0x01, 9, + 'A','z','u','r','e','R','T','O','S', + + /* Product string descriptor : Index 2 - "Printer device" */ + 0x09, 0x04, 0x02, 14, + 'P','r','i','n','t','e','r',' ','d','e','v','i','c','e', + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; +static UX_TEST_SETUP _PrinterGetDeviceID = {0xA1,0x00,0x0000,0x0000}; + +/* Test interactions */ + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + + +static UINT _test_simulate_disconnect = 0; +static VOID ux_test_on_printer_get_device_id(UX_TEST_ACTION *action, VOID *params) +{ +/* Test is printer instance allocated. */ +UX_DEVICE *dev = &_ux_system_host->ux_system_host_device_array[0]; +UX_INTERFACE *ifc = dev->ux_device_first_configuration->ux_configuration_first_interface; +UX_HOST_CLASS_PRINTER *printer; + UX_TEST_ASSERT(ifc != UX_NULL); + printer = (UX_HOST_CLASS_PRINTER *)ifc->ux_interface_class_instance; + UX_TEST_ASSERT(printer != UX_NULL); + UX_TEST_ASSERT(printer->ux_host_class_printer_allocated != UX_NULL); + /* Memory allocated, disconnect device to see if memory is double freed. */ + _test_simulate_disconnect = 1; +} +static UX_TEST_HCD_SIM_ACTION call_on_PrinterGetDeviceID[] = { +/* 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, &_PrinterGetDeviceID, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_on_printer_get_device_id, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT test_slave_change_function(ULONG change) +{ + return 0; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_PRINTER *printer_inst = (UX_HOST_CLASS_PRINTER *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + host_printer = printer_inst; + break; + + case UX_DEVICE_REMOVAL: + if (host_printer == printer_inst) + host_printer = UX_NULL; + break; + + case UX_DEVICE_CONNECTION: + device = (UX_DEVICE *)inst; + break; + + case UX_DEVICE_DISCONNECTION: + if ((VOID *)device == inst) + device = UX_NULL; + break; + +#if defined(UX_HOST_STANDALONE) + case UX_STANDALONE_WAIT_BACKGROUND_TASK: + tx_thread_relinquish(); + if(_test_simulate_disconnect) + { + _test_simulate_disconnect = 0; + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + } + break; +#endif + + default: + break; + } + return 0; +} + +static VOID test_printer_instance_activate(VOID *dummy_instance) +{ + if (device_printer == UX_NULL) + device_printer = (UX_DEVICE_CLASS_PRINTER *)dummy_instance; +} +static VOID test_printer_instance_deactivate(VOID *dummy_instance) +{ + if ((VOID*)device_printer == dummy_instance) + device_printer = UX_NULL; +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + printf("ERROR #%d: 0x%x, 0x%x, 0x%x\n", __LINE__, system_level, system_context, error_code); + UX_TEST_ASSERT(!( + (system_context == UX_SYSTEM_CONTEXT_UTILITY) && + (error_code == UX_MEMORY_CORRUPTED))); /* fail on UX_MEMORY_CORRUPTED */ + error_callback_counter ++; +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = ux_test_regular_memory_free(); + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_enum_sem_get_count = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_msrc_81572_standalone_host_printer_allocated_enum_free_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + printf("Running MSRC 81572 - Standalone Host Printer Alloc Enum Free Test... "); +#if !defined(UX_HOST_STANDALONE) + printf("Skip\n"); + test_control_return(0); + return; +#endif + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* Initialize the free memory pointer */ + stack_pointer = (CHAR *) usbx_memory; + memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 4); + + /* Initialize USBX Memory */ + status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL,0); + UX_TEST_CHECK_SUCCESS(status); + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + UX_TEST_CHECK_SUCCESS(status); + + /* Register PRINTER class. */ + status = ux_host_stack_class_register(_ux_system_host_class_printer_name, ux_host_class_printer_entry); + UX_TEST_CHECK_SUCCESS(status); + + /* 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, + test_slave_change_function); + UX_TEST_CHECK_SUCCESS(status); + + /* Set the parameters for callback when insertion/extraction of a printer device. */ + _ux_utility_memory_set(&device_printer_parameter, 0, sizeof(device_printer_parameter)); + device_printer_parameter.ux_device_class_printer_device_id = printer_device_id; + ux_utility_short_put_big_endian(printer_device_id, sizeof(printer_device_id)); + device_printer_parameter.ux_device_class_printer_instance_activate = test_printer_instance_activate; + device_printer_parameter.ux_device_class_printer_instance_deactivate = test_printer_instance_deactivate; + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_device_class_printer_name, + _ux_device_class_printer_entry, + 1, 0, &device_printer_parameter); + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Setup a hook for GET_DEVICE_ID request, to test disconnect (memory allocated by class at that time) */ + ux_test_hcd_sim_host_set_actions(call_on_PrinterGetDeviceID); + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_thread_host_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_ASSERT(status == TX_SUCCESS); + + /* Create the main slave simulation thread. */ + stack_pointer += UX_DEMO_STACK_SIZE; + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_ASSERT(status == TX_SUCCESS); +} + +static UINT _test_check_host_connection_error(VOID) +{ + if (device_printer && host_printer) + return(UX_SUCCESS); + if (error_callback_counter >= 3) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_connection_success(VOID) +{ + if (device_printer && host_printer) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_disconnection_success(VOID) +{ + if (device_printer == UX_NULL && host_printer == UX_NULL) + return(UX_SUCCESS); + return(UX_ERROR); +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +ULONG mem_free; +ULONG loop; +ULONG parameter_u32[64/4]; +USHORT *parameter_u16 = (USHORT*)parameter_u32; +UCHAR *parameter_u8 = (UCHAR*)parameter_u32; + + + stepinfo("\n"); + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + status = ux_test_sleep_break_on_error(100, _test_check_host_connection_success); + UX_TEST_ASSERT(status == UX_SUCCESS); + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + if (host_printer != UX_NULL) + { + + printf("ERROR #13: instance not removed when disconnect"); + test_control_return(1); + } + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_device_class_printer_name, _ux_device_class_printer_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); + tx_thread_relinquish(); +#else + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); +#endif + } +} diff --git a/test/regression/usbx_msrc_81573_standalone_host_hub_allocated_enum_free_test.c b/test/regression/usbx_msrc_81573_standalone_host_hub_allocated_enum_free_test.c new file mode 100644 index 00000000..8000eab5 --- /dev/null +++ b/test/regression/usbx_msrc_81573_standalone_host_hub_allocated_enum_free_test.c @@ -0,0 +1,499 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_dummy.h" +#include "ux_device_stack.h" +#include "ux_host_class_hub.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); + +static TX_THREAD tx_test_thread_hub_read; +static TX_THREAD tx_test_thread_hub_write; +static TX_SEMAPHORE tx_test_semaphore_hub_trigger; +static VOID tx_test_dummy_read_entry(ULONG); +static VOID tx_test_dummy_write_entry(ULONG); + +static VOID ux_test_hcd_entry_should_not_be_called(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_disconnect(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 4)]; + +static UX_DEVICE *device = UX_NULL; +static UX_HOST_CLASS_HUB *host_hub = UX_NULL; + +static ULONG enum_counter; + +static ULONG error_counter; +static ULONG error_callback_counter; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_on_set_cfg; +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_enum_mem_alloc_count; + +static ULONG rsc_test_sem_usage; +static ULONG rsc_test_sem_get_count; +static ULONG rsc_test_mutex_usage; +static ULONG rsc_test_mem_alloc_count; + +static UX_DEVICE_CLASS_DUMMY *device_dummy = UX_NULL; +static UX_DEVICE_CLASS_DUMMY_PARAMETER device_dummy_parameter; + +/* Define device framework. */ + +#define _W0(w) ( (w) & 0xFF) +#define _W1(w) (((w) >> 8) & 0xFF) + +#define _CONFIGURATION_DESCRIPTOR(total_len, n_ifc, cfg_val) \ + 0x09, 0x02, _W0(total_len), _W1(total_len), (n_ifc), (cfg_val), \ + 0x00, 0xc0, 0x32, + +#define _INTERFACE_DESCRIPTOR(ifc_n, alt, n_ep, cls, sub, protocol) \ + 0x09, 0x04, (ifc_n), (alt), (n_ep), (cls), (sub), (protocol), 0x00, + +#define _ENDPOINT_DESCRIPTOR(addr, attr, pktsize, interval) \ + 0x07, 0x05, (addr), (attr), _W0(pktsize), _W1(pktsize), (interval), + +#define _CFG_TOTAL_LEN (9+9+7) + +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0xEF bDeviceClass: Composite class code + 0x02 bDeviceSubclass: class sub code + 0x00 bDeviceProtocol: Device protocol + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0x09, 0x00, 0x01, + 0x08, + 0x24, 0x04, + 0x12, 0x24, + 0x00, 0x01, + 0x01, 0x02, 0x03, + 0x01, + + _CONFIGURATION_DESCRIPTOR(_CFG_TOTAL_LEN, 1, 1) + _INTERFACE_DESCRIPTOR(0, 0, 1, 0x09, 0x00, 0x00) + _ENDPOINT_DESCRIPTOR(0x81, 0x03, 2, 0x0c) +}; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_full_speed) +#define device_framework_high_speed device_framework_full_speed + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "AzureRTOS" */ + 0x09, 0x04, 0x01, 9, + 'A','z','u','r','e','R','T','O','S', + + /* Product string descriptor : Index 2 - "Printer device" */ + 0x09, 0x04, 0x02, 14, + 'P','r','i','n','t','e','r',' ','d','e','v','i','c','e', + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; + +static unsigned char default_hub_descriptor[] = { + + /* Hub Descriptor */ + 0x09, /* bLength */ + 0x29, /* bDescriptorType */ + 0x02, /* bNbrPorts */ + 0x09, 0x00, /* wHubCharacteristics */ + 0x32, /* bPwrOn2PwrGood */ + 0x01, /* bHubContrCurrent */ + 0x00, /* DeviceRemovable */ + 0xff, /* PortPwrCtrlMask */ + +}; + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; +static UX_TEST_SETUP _HubGetDescriptor = {0xA0,0x06,0x2900,0x0000}; + +/* Test interactions */ + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +static UINT _test_simulate_disconnect = 0; +static VOID ux_test_on_hub_get_descriptor(UX_TEST_ACTION *action, VOID *params) +{ +/* Test is hub instance allocated. */ +UX_DEVICE *dev = &_ux_system_host->ux_system_host_device_array[0]; +UX_INTERFACE *ifc = dev->ux_device_first_configuration->ux_configuration_first_interface; +UX_HOST_CLASS_HUB *hub; + UX_TEST_ASSERT(ifc != UX_NULL); + hub = (UX_HOST_CLASS_HUB *)dev->ux_device_class_instance; + UX_TEST_ASSERT(hub != UX_NULL); + UX_TEST_ASSERT(hub->ux_host_class_hub_allocated != UX_NULL); + /* Memory allocated, disconnect device to see if memory is double freed. */ + _test_simulate_disconnect = 1; +} +static UX_TEST_HCD_SIM_ACTION call_on_HubGetDescriptor[] = { +/* 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, &_HubGetDescriptor, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_on_hub_get_descriptor, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT test_slave_change_function(ULONG change) +{ + return 0; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_HUB *hub_inst = (UX_HOST_CLASS_HUB *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + host_hub = hub_inst; + break; + + case UX_DEVICE_REMOVAL: + if (host_hub == hub_inst) + host_hub = UX_NULL; + break; + + case UX_DEVICE_CONNECTION: + device = (UX_DEVICE *)inst; + break; + + case UX_DEVICE_DISCONNECTION: + if ((VOID *)device == inst) + device = UX_NULL; + break; + +#if defined(UX_HOST_STANDALONE) + case UX_STANDALONE_WAIT_BACKGROUND_TASK: + tx_thread_relinquish(); + if (_test_simulate_disconnect) + { + _test_simulate_disconnect = 0; + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + } + break; +#endif + + default: + break; + } + return 0; +} + +static VOID test_dummy_instance_activate(VOID *dummy_instance) +{ + if (device_dummy == UX_NULL) + device_dummy = (UX_DEVICE_CLASS_DUMMY *)dummy_instance; +} +static VOID test_dummy_instance_deactivate(VOID *dummy_instance) +{ + if ((VOID*)device_dummy == dummy_instance) + device_dummy = UX_NULL; +} +static VOID test_dummy_control_request(struct UX_DEVICE_CLASS_DUMMY_STRUCT *dummy, UX_SLAVE_TRANSFER *transfer) +{ +UCHAR *req = transfer -> ux_slave_transfer_request_setup; +UCHAR *req_buf = transfer -> ux_slave_transfer_request_data_pointer; +UINT req_type = req[0]; +UINT req_request = req[1]; +UINT req_value = ux_utility_short_get(req + 2); +UINT req_index = ux_utility_short_get(req + 4); +UINT req_length = ux_utility_short_get(req + 6); + /* HubDescriptorGet */ + if (req_type == 0xa0 && req_request == 0x06 && req_value == 0x2900) + { + ux_utility_memory_copy(req_buf, default_hub_descriptor, sizeof(default_hub_descriptor)); + UX_TEST_CHECK_SUCCESS(_ux_device_stack_transfer_request(transfer, sizeof(default_hub_descriptor), req_length)); + } +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + printf("ERROR #%d: 0x%x, 0x%x, 0x%x\n", __LINE__, system_level, system_context, error_code); + UX_TEST_ASSERT(!( + (system_context == UX_SYSTEM_CONTEXT_UTILITY) && + (error_code == UX_MEMORY_CORRUPTED))); /* fail on UX_MEMORY_CORRUPTED */ + error_callback_counter ++; +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = ux_test_regular_memory_free(); + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_enum_sem_get_count = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_msrc_81573_standalone_host_hub_allocated_enum_free_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + printf("Running MSRC 81573 - Standalone Host Hub Alloc Enum Free Test....... "); +#if !defined(UX_HOST_STANDALONE) + printf("Skip\n"); + test_control_return(0); + return; +#endif + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* Initialize the free memory pointer */ + stack_pointer = (CHAR *) usbx_memory; + memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 4); + + /* Initialize USBX Memory */ + status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL,0); + UX_TEST_CHECK_SUCCESS(status); + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + UX_TEST_CHECK_SUCCESS(status); + + /* Register DUMMY class. */ + status = ux_host_stack_class_register(_ux_system_host_class_hub_name, ux_host_class_hub_entry); + UX_TEST_CHECK_SUCCESS(status); + + /* 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, + test_slave_change_function); + UX_TEST_CHECK_SUCCESS(status); + + /* Set the parameters for callback when insertion/extraction of a hub device. */ + _ux_utility_memory_set(&device_dummy_parameter, 0, sizeof(device_dummy_parameter)); + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_instance_activate = test_dummy_instance_activate; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_instance_deactivate = test_dummy_instance_deactivate; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_control_request = test_dummy_control_request; + /* Initialize the device dummy class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_device_class_dummy_name, + _ux_device_class_dummy_entry, + 1, 0, &device_dummy_parameter); + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Setup a hook for GET_DEVICE_ID request, to test disconnect (memory allocated by class at that time) */ + ux_test_hcd_sim_host_set_actions(call_on_HubGetDescriptor); + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_thread_host_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_ASSERT(status == TX_SUCCESS); + + /* Create the main slave simulation thread. */ + stack_pointer += UX_DEMO_STACK_SIZE; + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_ASSERT(status == TX_SUCCESS); +} + +static UINT _test_check_host_connection_error(VOID) +{ + if (device_dummy && host_hub) + return(UX_SUCCESS); + if (error_callback_counter >= 3) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_connection_success(VOID) +{ + if (device_dummy && host_hub) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_disconnection_success(VOID) +{ + if (device_dummy == UX_NULL && host_hub == UX_NULL) + return(UX_SUCCESS); + return(UX_ERROR); +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +ULONG mem_free; +ULONG loop; +ULONG parameter_u32[64/4]; +USHORT *parameter_u16 = (USHORT*)parameter_u32; +UCHAR *parameter_u8 = (UCHAR*)parameter_u32; + + + stepinfo("\n"); + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + status = ux_test_sleep_break_on_error(100, _test_check_host_connection_success); + UX_TEST_ASSERT(status == UX_SUCCESS); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_device_class_dummy_name, _ux_device_class_dummy_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); + tx_thread_relinquish(); +#else + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); +#endif + } +} diff --git a/test/regression/usbx_msrc_81574_standalone_host_hid_allocated_enum_free_test.c b/test/regression/usbx_msrc_81574_standalone_host_hid_allocated_enum_free_test.c new file mode 100644 index 00000000..65a9cfbd --- /dev/null +++ b/test/regression/usbx_msrc_81574_standalone_host_hid_allocated_enum_free_test.c @@ -0,0 +1,514 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_hid.h" +#include "ux_device_stack.h" +#include "ux_host_class_hid.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); + +static TX_THREAD tx_test_thread_hid_read; +static TX_THREAD tx_test_thread_hid_write; +static TX_SEMAPHORE tx_test_semaphore_hid_trigger; +static VOID tx_test_hid_read_entry(ULONG); +static VOID tx_test_hid_write_entry(ULONG); + +static VOID ux_test_hcd_entry_should_not_be_called(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_disconnect(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 4)]; + +static UX_DEVICE *device = UX_NULL; +static UX_HOST_CLASS_HID *host_hid = UX_NULL; + +static ULONG enum_counter; + +static ULONG error_counter; +static ULONG error_callback_counter; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_on_set_cfg; +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_enum_mem_alloc_count; + +static ULONG rsc_test_sem_usage; +static ULONG rsc_test_sem_get_count; +static ULONG rsc_test_mutex_usage; +static ULONG rsc_test_mem_alloc_count; + +static UX_SLAVE_CLASS_HID *device_hid = UX_NULL; +static UX_SLAVE_CLASS_HID_PARAMETER device_hid_parameter; + +static UCHAR hid_keyboard_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + + 0xc0 // END_COLLECTION +}; +#define HID_KEYBOARD_REPORT_LENGTH sizeof(hid_keyboard_report)/sizeof(hid_keyboard_report[0]) + +/* Define device framework. */ + +#define _W0(w) ( (w) & 0xFF) +#define _W1(w) (((w) >> 8) & 0xFF) + +#define _CONFIGURATION_DESCRIPTOR(total_len, n_ifc, cfg_val) \ + 0x09, 0x02, _W0(total_len), _W1(total_len), (n_ifc), (cfg_val), \ + 0x00, 0xc0, 0x32, + +#define _INTERFACE_DESCRIPTOR(ifc_n, alt, n_ep, cls, sub, protocol) \ + 0x09, 0x04, (ifc_n), (alt), (n_ep), (cls), (sub), (protocol), 0x00, + +#define _ENDPOINT_DESCRIPTOR(addr, attr, pktsize, interval) \ + 0x07, 0x05, (addr), (attr), _W0(pktsize), _W1(pktsize), (interval), + +#define _CFG_TOTAL_LEN (9+9+9+7) + +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0xEF bDeviceClass: Composite class code + 0x02 bDeviceSubclass: class sub code + 0x00 bDeviceProtocol: Device protocol + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0x00, 0x00, 0x00, + 0x08, + 0x81, 0x0A, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 0x03, + 0x01, + + _CONFIGURATION_DESCRIPTOR(_CFG_TOTAL_LEN, 1, 1) + _INTERFACE_DESCRIPTOR(0, 0, 1, 0x03, 0x00, 0x00) + /* HID descriptor */ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, _W0(HID_KEYBOARD_REPORT_LENGTH), _W1(HID_KEYBOARD_REPORT_LENGTH), + _ENDPOINT_DESCRIPTOR(0x81, 0x03, 8, 0x0A) +}; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_full_speed) +#define device_framework_high_speed device_framework_full_speed + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "AzureRTOS" */ + 0x09, 0x04, 0x01, 9, + 'A','z','u','r','e','R','T','O','S', + + /* Product string descriptor : Index 2 - "Printer device" */ + 0x09, 0x04, 0x02, 14, + 'P','r','i','n','t','e','r',' ','d','e','v','i','c','e', + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; +static UX_TEST_SETUP _HidReportDescriptorGet = {0x81,0x06,0x2200,0x0000}; + +/* Test interactions */ + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +static UINT _test_simulate_disconnect = 0; +static VOID ux_test_on_hid_get_report_descriptor(UX_TEST_ACTION *action, VOID *params) +{ +/* Test is hid instance allocated. */ +UX_DEVICE *dev = &_ux_system_host->ux_system_host_device_array[0]; +UX_INTERFACE *ifc = dev->ux_device_first_configuration->ux_configuration_first_interface; +UX_HOST_CLASS_HID *hid; + UX_TEST_ASSERT(ifc != UX_NULL); + hid = (UX_HOST_CLASS_HID *)ifc->ux_interface_class_instance; + UX_TEST_ASSERT(hid != UX_NULL); + UX_TEST_ASSERT(hid->ux_host_class_hid_allocated != UX_NULL); + /* Memory allocated, disconnect device to see if memory is double freed. */ + _test_simulate_disconnect = 1; +} +static UX_TEST_HCD_SIM_ACTION call_on_HidReportDescriptorGet[] = { +/* 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, &_HidReportDescriptorGet, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_on_hid_get_report_descriptor, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT test_slave_change_function(ULONG change) +{ + return 0; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_HID *hid_inst = (UX_HOST_CLASS_HID *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + host_hid = hid_inst; + break; + + case UX_DEVICE_REMOVAL: + if (host_hid == hid_inst) + host_hid = UX_NULL; + break; + + case UX_DEVICE_CONNECTION: + device = (UX_DEVICE *)inst; + break; + + case UX_DEVICE_DISCONNECTION: + if ((VOID *)device == inst) + device = UX_NULL; + break; + +#if defined(UX_HOST_STANDALONE) + case UX_STANDALONE_WAIT_BACKGROUND_TASK: + tx_thread_relinquish(); + if(_test_simulate_disconnect) + { + _test_simulate_disconnect = 0; + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + } + break; +#endif + + default: + break; + } + return 0; +} + +static VOID test_hid_instance_activate(VOID *dummy_instance) +{ + if (device_hid == UX_NULL) + device_hid = (UX_SLAVE_CLASS_HID *)dummy_instance; +} +static VOID test_hid_instance_deactivate(VOID *dummy_instance) +{ + if ((VOID*)device_hid == dummy_instance) + device_hid = UX_NULL; +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + printf("ERROR #%d: 0x%x, 0x%x, 0x%x\n", __LINE__, system_level, system_context, error_code); + UX_TEST_ASSERT(!( + (system_context == UX_SYSTEM_CONTEXT_UTILITY) && + (error_code == UX_MEMORY_CORRUPTED))); /* fail on UX_MEMORY_CORRUPTED */ + error_callback_counter ++; +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = ux_test_regular_memory_free(); + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_enum_sem_get_count = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_msrc_81572_standalone_host_hid_allocated_enum_free_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + printf("Running MSRC 81574 - Standalone Host HID Alloc Enum Free Test....... "); +#if !defined(UX_HOST_STANDALONE) + printf("Skip\n"); + test_control_return(0); + return; +#endif + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* Initialize the free memory pointer */ + stack_pointer = (CHAR *) usbx_memory; + memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 4); + + /* Initialize USBX Memory */ + status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL,0); + UX_TEST_CHECK_SUCCESS(status); + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + UX_TEST_CHECK_SUCCESS(status); + + /* Register HID class. */ + status = ux_host_stack_class_register(_ux_system_host_class_hid_name, ux_host_class_hid_entry); + UX_TEST_CHECK_SUCCESS(status); + + /* 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, + test_slave_change_function); + UX_TEST_CHECK_SUCCESS(status); + + /* Set the parameters for callback when insertion/extraction of a hid device. */ + _ux_utility_memory_set(&device_hid_parameter, 0, sizeof(device_hid_parameter)); + device_hid_parameter.ux_device_class_hid_parameter_report_address = hid_keyboard_report; + device_hid_parameter.ux_device_class_hid_parameter_report_length = HID_KEYBOARD_REPORT_LENGTH; + device_hid_parameter.ux_slave_class_hid_instance_activate = test_hid_instance_activate; + device_hid_parameter.ux_slave_class_hid_instance_deactivate = test_hid_instance_deactivate; + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_hid_name, + ux_device_class_hid_entry, + 1, 0, &device_hid_parameter); + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Setup a hook for GET_DEVICE_ID request, to test disconnect (memory allocated by class at that time) */ + ux_test_hcd_sim_host_set_actions(call_on_HidReportDescriptorGet); + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_thread_host_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_ASSERT(status == TX_SUCCESS); + + /* Create the main slave simulation thread. */ + stack_pointer += UX_DEMO_STACK_SIZE; + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_ASSERT(status == TX_SUCCESS); +} + +static UINT _test_check_host_connection_error(VOID) +{ + if (device_hid && host_hid) + return(UX_SUCCESS); + if (error_callback_counter >= 3) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_connection_success(VOID) +{ + if (device_hid && host_hid) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_disconnection_success(VOID) +{ + if (device_hid == UX_NULL && host_hid == UX_NULL) + return(UX_SUCCESS); + return(UX_ERROR); +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +ULONG mem_free; +ULONG loop; +ULONG parameter_u32[64/4]; +USHORT *parameter_u16 = (USHORT*)parameter_u32; +UCHAR *parameter_u8 = (UCHAR*)parameter_u32; + + + stepinfo("\n"); + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + status = ux_test_sleep_break_on_error(100, _test_check_host_connection_success); + UX_TEST_ASSERT(status == UX_SUCCESS); + + /* Finally 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); + +} + +void tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); + tx_thread_relinquish(); +#else + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); +#endif + } +} diff --git a/test/regression/usbx_msrc_81575_standalone_host_cdc_acm_allocated_enum_free_test.c b/test/regression/usbx_msrc_81575_standalone_host_cdc_acm_allocated_enum_free_test.c new file mode 100644 index 00000000..4052d95c --- /dev/null +++ b/test/regression/usbx_msrc_81575_standalone_host_cdc_acm_allocated_enum_free_test.c @@ -0,0 +1,491 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" +#include "ux_host_class_cdc_acm.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); + +static VOID ux_test_hcd_entry_should_not_be_called(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_disconnect(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 4)]; + +static UX_DEVICE *device = UX_NULL; +static UX_HOST_CLASS_CDC_ACM *host_cdc_acm = UX_NULL; + +static ULONG enum_counter; + +static ULONG error_counter; +static ULONG error_callback_counter; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_on_set_cfg; +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_enum_mem_alloc_count; + +static ULONG rsc_test_sem_usage; +static ULONG rsc_test_sem_get_count; +static ULONG rsc_test_mutex_usage; +static ULONG rsc_test_mem_alloc_count; + +static UX_SLAVE_CLASS_CDC_ACM *device_cdc_acm = UX_NULL; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER device_cdc_acm_parameter; + +/* Define device framework. */ + +#define _W0(w) ( (w) & 0xFF) +#define _W1(w) (((w) >> 8) & 0xFF) + +#define _CONFIGURATION_DESCRIPTOR(total_len, n_ifc, cfg_val) \ + 0x09, 0x02, _W0(total_len), _W1(total_len), (n_ifc), (cfg_val), \ + 0x00, 0xc0, 0x32, + +#define _INTERFACE_DESCRIPTOR(ifc_n, alt, n_ep, cls, sub, protocol) \ + 0x09, 0x04, (ifc_n), (alt), (n_ep), (cls), (sub), (protocol), 0x00, + +#define _ENDPOINT_DESCRIPTOR(addr, attr, pktsize, interval) \ + 0x07, 0x05, (addr), (attr), _W0(pktsize), _W1(pktsize), (interval), + +#define _CFG_TOTAL_LEN (9 +8 +9 +5+4+5+5 +7 +9 +7+7) + +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0xEF bDeviceClass: Composite class code + 0x02 bDeviceSubclass: class sub code + 0x00 bDeviceProtocol: Device protocol + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0x00, 0x00, 0x00, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 0x03, + 0x01, + + _CONFIGURATION_DESCRIPTOR(_CFG_TOTAL_LEN, 2, 1) + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + _INTERFACE_DESCRIPTOR(0, 0, 1, 0x02, 0x02, 0x01) + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, 0x10, 0x01, + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, 0x0f, + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + _ENDPOINT_DESCRIPTOR(0x83, 0x03, 8, 0x0a) + _INTERFACE_DESCRIPTOR(1, 0, 2, 0x0a, 0x00, 0x00) + _ENDPOINT_DESCRIPTOR(0x01, 0x02, 64, 0x00) + _ENDPOINT_DESCRIPTOR(0x82, 0x02, 64, 0x00) +}; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_full_speed) +#define device_framework_high_speed device_framework_full_speed + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "AzureRTOS" */ + 0x09, 0x04, 0x01, 9, + 'A','z','u','r','e','R','T','O','S', + + /* Product string descriptor : Index 2 - "Printer device" */ + 0x09, 0x04, 0x02, 14, + 'P','r','i','n','t','e','r',' ','d','e','v','i','c','e', + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; +static UX_TEST_SETUP _CDCACMLineCodingSet = {0x21,0x20,0x0000,0x0001}; + +/* Test interactions */ + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +static UINT _test_simulate_disconnect = 0; +static VOID ux_test_on_cdc_acm_set_line_coding(UX_TEST_ACTION *action, VOID *params) +{ +/* Test is cdc_acm instance allocated. */ +UX_DEVICE *dev = &_ux_system_host->ux_system_host_device_array[0]; +UX_INTERFACE *ifc = dev->ux_device_first_configuration->ux_configuration_first_interface; +UX_INTERFACE *ifc1; +UX_HOST_CLASS_CDC_ACM *cdc_acm; + UX_TEST_ASSERT(ifc != UX_NULL); + ifc1 = ifc->ux_interface_next_interface; + cdc_acm = (UX_HOST_CLASS_CDC_ACM *)ifc1->ux_interface_class_instance; + UX_TEST_ASSERT(cdc_acm != UX_NULL); + UX_TEST_ASSERT(cdc_acm->ux_host_class_cdc_acm_allocated != UX_NULL); + /* Memory allocated, disconnect device to see if memory is double freed. */ + _test_simulate_disconnect = 1; +} +static UX_TEST_HCD_SIM_ACTION call_on_CDCACMLineCodingSet[] = { +/* 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, &_CDCACMLineCodingSet, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_on_cdc_acm_set_line_coding, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT test_slave_change_function(ULONG change) +{ + return 0; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm_inst = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + host_cdc_acm = cdc_acm_inst; + break; + + case UX_DEVICE_REMOVAL: + if (host_cdc_acm == cdc_acm_inst) + host_cdc_acm = UX_NULL; + break; + + case UX_DEVICE_CONNECTION: + device = (UX_DEVICE *)inst; + break; + + case UX_DEVICE_DISCONNECTION: + if ((VOID *)device == inst) + device = UX_NULL; + break; + +#if defined(UX_HOST_STANDALONE) + case UX_STANDALONE_WAIT_BACKGROUND_TASK: + tx_thread_relinquish(); + if(_test_simulate_disconnect) + { + _test_simulate_disconnect = 0; + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + } + break; +#endif + + default: + break; + } + return 0; +} + +static VOID test_cdc_acm_instance_activate(VOID *dummy_instance) +{ + if (device_cdc_acm == UX_NULL) + device_cdc_acm = (UX_SLAVE_CLASS_CDC_ACM *)dummy_instance; +} +static VOID test_cdc_acm_instance_deactivate(VOID *dummy_instance) +{ + if ((VOID*)device_cdc_acm == dummy_instance) + device_cdc_acm = UX_NULL; +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + printf("ERROR #%d: 0x%x, 0x%x, 0x%x\n", __LINE__, system_level, system_context, error_code); + UX_TEST_ASSERT(!( + (system_context == UX_SYSTEM_CONTEXT_UTILITY) && + (error_code == UX_MEMORY_CORRUPTED))); /* fail on UX_MEMORY_CORRUPTED */ + error_callback_counter ++; +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = ux_test_regular_memory_free(); + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_enum_sem_get_count = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_msrc_81572_standalone_host_cdc_acm_allocated_enum_free_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + printf("Running MSRC 81575 - Standalone Host CDC ACM Alloc Enum Free Test... "); +#if !defined(UX_HOST_STANDALONE) + printf("Skip\n"); + test_control_return(0); + return; +#endif + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* Initialize the free memory pointer */ + stack_pointer = (CHAR *) usbx_memory; + memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 4); + + /* Initialize USBX Memory */ + status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL,0); + UX_TEST_CHECK_SUCCESS(status); + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + UX_TEST_CHECK_SUCCESS(status); + + /* Register CDC_ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_entry); + UX_TEST_CHECK_SUCCESS(status); + + /* 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, + test_slave_change_function); + UX_TEST_CHECK_SUCCESS(status); + + /* Set the parameters for callback when insertion/extraction of a cdc_acm device. */ + _ux_utility_memory_set(&device_cdc_acm_parameter, 0, sizeof(device_cdc_acm_parameter)); + device_cdc_acm_parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_acm_instance_activate; + device_cdc_acm_parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_acm_instance_deactivate; + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, + ux_device_class_cdc_acm_entry, + 1, 0, &device_cdc_acm_parameter); + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Setup a hook for GET_DEVICE_ID request, to test disconnect (memory allocated by class at that time) */ + ux_test_hcd_sim_host_set_actions(call_on_CDCACMLineCodingSet); + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_thread_host_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_ASSERT(status == TX_SUCCESS); + + /* Create the main slave simulation thread. */ + stack_pointer += UX_DEMO_STACK_SIZE; + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_ASSERT(status == TX_SUCCESS); +} + +static UINT _test_check_host_connection_error(VOID) +{ + if (device_cdc_acm && host_cdc_acm) + return(UX_SUCCESS); + if (error_callback_counter >= 3) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_connection_success(VOID) +{ + if (device_cdc_acm && host_cdc_acm) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_disconnection_success(VOID) +{ + if (device_cdc_acm == UX_NULL && host_cdc_acm == UX_NULL) + return(UX_SUCCESS); + return(UX_ERROR); +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +ULONG mem_free; +ULONG loop; +ULONG parameter_u32[64/4]; +USHORT *parameter_u16 = (USHORT*)parameter_u32; +UCHAR *parameter_u8 = (UCHAR*)parameter_u32; + + + stepinfo("\n"); + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + status = ux_test_sleep_break_on_error(100, _test_check_host_connection_success); + UX_TEST_ASSERT(status == UX_SUCCESS); + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + if (host_cdc_acm != UX_NULL) + { + + printf("ERROR #13: instance not removed when disconnect"); + test_control_return(1); + } + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, _ux_device_class_cdc_acm_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); + tx_thread_relinquish(); +#else + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); +#endif + } +} diff --git a/test/regression/usbx_msrc_81691_standalone_host_stack_enum_double_free_test.c b/test/regression/usbx_msrc_81691_standalone_host_stack_enum_double_free_test.c new file mode 100644 index 00000000..0cb8e78c --- /dev/null +++ b/test/regression/usbx_msrc_81691_standalone_host_stack_enum_double_free_test.c @@ -0,0 +1,475 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" +#include "ux_host_class_cdc_acm.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); + +static VOID ux_test_hcd_entry_should_not_be_called(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_disconnect(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 4)]; + +static UX_DEVICE *device = UX_NULL; +static UX_HOST_CLASS_CDC_ACM *host_cdc_acm = UX_NULL; + +static ULONG enum_counter; + +static ULONG error_counter; +static ULONG error_callback_counter; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_on_set_cfg; +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_enum_mem_alloc_count; + +static ULONG rsc_test_sem_usage; +static ULONG rsc_test_sem_get_count; +static ULONG rsc_test_mutex_usage; +static ULONG rsc_test_mem_alloc_count; + +static UX_SLAVE_CLASS_CDC_ACM *device_cdc_acm = UX_NULL; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER device_cdc_acm_parameter; + +/* Define device framework. */ + +#define _W0(w) ( (w) & 0xFF) +#define _W1(w) (((w) >> 8) & 0xFF) + +#define _CONFIGURATION_DESCRIPTOR(total_len, n_ifc, cfg_val) \ + 0x09, 0x02, _W0(total_len), _W1(total_len), (n_ifc), (cfg_val), \ + 0x00, 0xc0, 0x32, + +#define _INTERFACE_DESCRIPTOR(ifc_n, alt, n_ep, cls, sub, protocol) \ + 0x09, 0x04, (ifc_n), (alt), (n_ep), (cls), (sub), (protocol), 0x00, + +#define _ENDPOINT_DESCRIPTOR(addr, attr, pktsize, interval) \ + 0x07, 0x05, (addr), (attr), _W0(pktsize), _W1(pktsize), (interval), + +#define _CFG_TOTAL_LEN (9 +8 +9 +5+4+5+5 +7 +9 +7+7) + +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0xEF bDeviceClass: Composite class code + 0x02 bDeviceSubclass: class sub code + 0x00 bDeviceProtocol: Device protocol + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0x00, 0x00, 0x00, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 0x03, + 0x01, + + _CONFIGURATION_DESCRIPTOR(_CFG_TOTAL_LEN, 2, 1) + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + _INTERFACE_DESCRIPTOR(0, 0, 1, 0x02, 0x02, 0x01) + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, 0x10, 0x01, + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, 0x0f, + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + _ENDPOINT_DESCRIPTOR(0x83, 0x03, 8, 0x0a) + _INTERFACE_DESCRIPTOR(1, 0, 2, 0x0a, 0x00, 0x00) + _ENDPOINT_DESCRIPTOR(0x01, 0x02, 64, 0x00) + _ENDPOINT_DESCRIPTOR(0x82, 0x02, 64, 0x00) +}; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_full_speed) +#define device_framework_high_speed device_framework_full_speed + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "AzureRTOS" */ + 0x09, 0x04, 0x01, 9, + 'A','z','u','r','e','R','T','O','S', + + /* Product string descriptor : Index 2 - "Printer device" */ + 0x09, 0x04, 0x02, 14, + 'P','r','i','n','t','e','r',' ','d','e','v','i','c','e', + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +/* Test interactions */ + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT test_slave_change_function(ULONG change) +{ + return 0; +} + +#include "ux_host_stack.h" +static UINT _test_state_to_disconnect = UX_HOST_STACK_ENUM_WAIT; +static VOID _test_standalone_dev_retry_with_buffer(VOID) +{ +UX_DEVICE *dev; +UX_TRANSFER *trans; + /* Check device state and allocated buffer. */ + if (!_ux_system_host) + return; + dev = &_ux_system_host->ux_system_host_device_array[0]; + trans = dev->ux_device_enum_trans; + if ((dev->ux_device_enum_state == _test_state_to_disconnect) && + (trans) && (trans->ux_transfer_request_data_pointer)) + { + /* Memory allocated, disconnect device to see if memory is double freed. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + } +} +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm_inst = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + host_cdc_acm = cdc_acm_inst; + break; + + case UX_DEVICE_REMOVAL: + if (host_cdc_acm == cdc_acm_inst) + host_cdc_acm = UX_NULL; + break; + + case UX_DEVICE_CONNECTION: + device = (UX_DEVICE *)inst; + break; + + case UX_DEVICE_DISCONNECTION: + if ((VOID *)device == inst) + device = UX_NULL; + break; + +#if defined(UX_HOST_STANDALONE) + case UX_STANDALONE_WAIT_BACKGROUND_TASK: + tx_thread_relinquish(); + _test_standalone_dev_retry_with_buffer(); + break; +#endif + + default: + break; + } + return 0; +} + +static VOID test_cdc_acm_instance_activate(VOID *dummy_instance) +{ + if (device_cdc_acm == UX_NULL) + device_cdc_acm = (UX_SLAVE_CLASS_CDC_ACM *)dummy_instance; +} +static VOID test_cdc_acm_instance_deactivate(VOID *dummy_instance) +{ + if ((VOID*)device_cdc_acm == dummy_instance) + device_cdc_acm = UX_NULL; +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + printf("ERROR #%d: 0x%x, 0x%x, 0x%x\n", __LINE__, system_level, system_context, error_code); + UX_TEST_ASSERT(!( + (system_context == UX_SYSTEM_CONTEXT_UTILITY) && + (error_code == UX_MEMORY_CORRUPTED))); /* fail on UX_MEMORY_CORRUPTED */ + error_callback_counter ++; +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = ux_test_regular_memory_free(); + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_enum_sem_get_count = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_msrc_81691_standalone_host_stack_enum_double_free_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + printf("Running MSRC 81691 - Standalone Host Stack Enum Double Free Test.... "); +#if !defined(UX_HOST_STANDALONE) + printf("Skip\n"); + test_control_return(0); + return; +#endif + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* Initialize the free memory pointer */ + stack_pointer = (CHAR *) usbx_memory; + memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 4); + + /* Initialize USBX Memory */ + status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL,0); + UX_TEST_CHECK_SUCCESS(status); + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + UX_TEST_CHECK_SUCCESS(status); + + /* Register CDC_ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_entry); + UX_TEST_CHECK_SUCCESS(status); + + /* 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, + test_slave_change_function); + UX_TEST_CHECK_SUCCESS(status); + + /* Set the parameters for callback when insertion/extraction of a cdc_acm device. */ + _ux_utility_memory_set(&device_cdc_acm_parameter, 0, sizeof(device_cdc_acm_parameter)); + device_cdc_acm_parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_acm_instance_activate; + device_cdc_acm_parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_acm_instance_deactivate; + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, + ux_device_class_cdc_acm_entry, + 1, 0, &device_cdc_acm_parameter); + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Modify bMaxPacketSize0 to generate retrying. */ + device_framework_full_speed[7] = 0x00; + _test_state_to_disconnect = UX_HOST_STACK_ENUM_WAIT; + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_thread_host_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_ASSERT(status == TX_SUCCESS); + + /* Create the main slave simulation thread. */ + stack_pointer += UX_DEMO_STACK_SIZE; + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_ASSERT(status == TX_SUCCESS); +} + +static UINT _test_check_host_connection_error(VOID) +{ + if (device_cdc_acm && host_cdc_acm) + return(UX_SUCCESS); + if (error_callback_counter >= 3) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_connection_success(VOID) +{ + if (device_cdc_acm && host_cdc_acm) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_disconnection_success(VOID) +{ + if (device_cdc_acm == UX_NULL && host_cdc_acm == UX_NULL) + return(UX_SUCCESS); + return(UX_ERROR); +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +ULONG mem_free; +ULONG loop; +ULONG parameter_u32[64/4]; +USHORT *parameter_u16 = (USHORT*)parameter_u32; +UCHAR *parameter_u8 = (UCHAR*)parameter_u32; + + + stepinfo("\n"); + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + status = ux_test_sleep_break_on_error(10000, _test_check_host_connection_success); + UX_TEST_ASSERT(status == UX_SUCCESS); + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + if (host_cdc_acm != UX_NULL) + { + + printf("ERROR #13: instance not removed when disconnect"); + test_control_return(1); + } + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, _ux_device_class_cdc_acm_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); + tx_thread_relinquish(); +#else + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); +#endif + } +} diff --git a/test/regression/usbx_pictbridge_basic_test.c b/test/regression/usbx_pictbridge_basic_test.c new file mode 100644 index 00000000..5f07e9a5 --- /dev/null +++ b/test/regression/usbx_pictbridge_basic_test.c @@ -0,0 +1,747 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#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_pictbridge.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" + +#include "ux_test_jpeg_image.h" + +/* Define constants. */ +#define UX_TEST_STACK_SIZE (2*1024) +#define UX_TEST_MEMORY_SIZE (512*1024) + +/* Define local/extern function prototypes. */ + +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_pima_instance_activate(VOID *pima_instance); +static VOID test_pima_instance_deactivate(VOID *pima_instance); + + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_TEST_MEMORY_SIZE + (UX_TEST_STACK_SIZE * 2)]; + +static UX_SLAVE_CLASS_PIMA_DEVICE *pima_device; +static UX_PICTBRIDGE pictbridge_device; +static UX_PICTBRIDGE_PRINTINFO printinfo; +static UX_PICTBRIDGE_JOBINFO *jobinfo; +static UX_SLAVE_CLASS_PIMA_OBJECT *object; +static TX_SEMAPHORE print_semaphore; +static ULONG pictbridge_device_copy_count = 0; + +static UX_HOST_CLASS_PIMA *pima_host; +static UX_PICTBRIDGE pictbridge_host; +static ULONG pictbridge_host_copy_count = 0; +static TX_SEMAPHORE wait_semaphore; + +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; + +/* 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, + +}; +#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) + +/* Pima device info manufacture string (Unicode). */ +UCHAR string_pima_manufacturer[] = +{ + 0x0C, + 0x45, 0x00, 0x78, 0x00, 0x70, 0x00, 0x72, 0x00, + 0x65, 0x00, 0x73, 0x00, 0x20, 0x00, 0x4c, 0x00, + 0x6f, 0x00, 0x67, 0x00, 0x69, 0x00, 0x63, 0x00 +}; + +/* Pima device info Model string (Unicode). */ +UCHAR string_pima_model[] = +{ + 0x0C, + 0x50, 0x00, 0x69, 0x00, 0x6D, 0x00, 0x61, 0x00, + 0x20, 0x00, 0x43, 0x00, 0x61, 0x00, 0x6D, 0x00, + 0x65, 0x00, 0x72, 0x00, 0x61, 0x00, 0x20, 0x00 +}; + +/* Pima device info Device version (Unicode). */ +UCHAR string_pima_device_version[] = +{ + 0x04, + 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x31, 0x00 +}; + +/* Pima device info Device serial number (Unicode). */ +UCHAR string_pima_serial_number[] = +{ + 0x04, + 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00 +}; + +UCHAR string_pima_storage_description[] = +{ + 0x0b, + 0x56, 0x00, 0x69, 0x00, 0x72, 0x00, 0x74, 0x00, + 0x75, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x20, 0x00, + 0x44, 0x00, 0x69, 0x00, 0x73, 0x00, 0x6b, 0x00 +}; + +UCHAR string_pima_storage_volume_label[] = +{ + 0x09, + 0x4d, 0x00, 0x79, 0x00, 0x20, 0x00, 0x56, 0x00, + 0x6f, 0x00, 0x6c, 0x00, 0x75, 0x00, 0x6d, 0x00, + 0x65, 0x00 +}; + +/* 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_DEVICE *)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_pictbridge_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +ULONG test_n; + + /* Inform user. */ + printf("Running Pictbridge Basic Functionality 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(); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Register PIMA class. */ + status = ux_host_stack_class_register(_ux_system_host_class_pima_name, ux_host_class_pima_entry); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Initialize the Pictbridge string components. */ + ux_utility_memory_copy(pictbridge_device.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_vendor_name, "ExpressLogic",13); + ux_utility_memory_copy(pictbridge_device.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_product_name, "EL_Pictbridge_Camera",21); + ux_utility_memory_copy(pictbridge_device.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_serial_no, "ABC_123",7); + ux_utility_memory_copy(pictbridge_device.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dpsversions, "1.0 1.1",7); + pictbridge_device.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_vendor_specific_version = 0x0100; + + pictbridge_device.ux_pictbridge_pima_parameter.ux_device_class_pima_instance_activate = test_pima_instance_activate; + pictbridge_device.ux_pictbridge_pima_parameter.ux_device_class_pima_instance_deactivate = test_pima_instance_deactivate; + + pictbridge_device.ux_pictbridge_pima_parameter.ux_device_class_pima_parameter_device_version = "0.0"; + + /* Start the Pictbridge client. */ + status = ux_pictbridge_dpsclient_start(&pictbridge_device); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Create a semaphore for the demo. */ + status = tx_semaphore_create(&wait_semaphore,"Wait Semaphore", 0); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); +} + +/* Copy the object data. */ +static UINT test_pictbridge_host_object_data_write(UX_PICTBRIDGE *pictbridge,UCHAR *object_buffer, ULONG offset, ULONG total_length, ULONG length) +{ + pictbridge_host_copy_count ++; + + /* We have copied the requested data. Return OK. */ + return(UX_SUCCESS); + +} + +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); + } + + /* Initialize the dpshost structure with the printer vendor info. */ + ux_utility_memory_copy(pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_vendor_name, "ExpressLogic",13); + ux_utility_memory_copy(pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_product_name, "EL_Pictbridge_Printer",21); + ux_utility_memory_copy(pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_serial_no, "ABC_123",7); + + /* Set supported versions. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dpsversions[0] = 0x00010000; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dpsversions[1] = 0x00010001; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dpsversions[2] = 0; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_vendor_specific_version = 0x00010000; + + /* Set print services to TRUE. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_print_service_available = 0x30010000; + + /* Set Qualities. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_qualities[0] = UX_PICTBRIDGE_QUALITIES_DEFAULT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_qualities[1] = UX_PICTBRIDGE_QUALITIES_NORMAL; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_qualities[2] = UX_PICTBRIDGE_QUALITIES_DRAFT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_qualities[3] = UX_PICTBRIDGE_QUALITIES_FINE; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_qualities[4] = 0; + + /* Set Paper Sizes. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_papersizes[0] = UX_PICTBRIDGE_PAPER_SIZES_DEFAULT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_papersizes[1] = UX_PICTBRIDGE_PAPER_SIZES_4IX6I; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_papersizes[2] = UX_PICTBRIDGE_PAPER_SIZES_L; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_papersizes[3] = UX_PICTBRIDGE_PAPER_SIZES_2L; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_papersizes[4] = UX_PICTBRIDGE_PAPER_SIZES_LETTER; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_papersizes[5] = 0; + + /* Set Paper Types. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_papertypes[0] = UX_PICTBRIDGE_PAPER_TYPES_DEFAULT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_papertypes[1] = UX_PICTBRIDGE_PAPER_TYPES_PLAIN; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_papertypes[2] = UX_PICTBRIDGE_PAPER_TYPES_PHOTO; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_papertypes[3] = 0; + + /* Set File Types. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_filetypes[0] = UX_PICTBRIDGE_FILE_TYPES_DEFAULT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_filetypes[1] = UX_PICTBRIDGE_FILE_TYPES_EXIF_JPEG; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_filetypes[2] = UX_PICTBRIDGE_FILE_TYPES_JFIF; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_filetypes[3] = UX_PICTBRIDGE_FILE_TYPES_DPOF; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_filetypes[4] = 0; + + /* Set Date Prints. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dateprints[0] = UX_PICTBRIDGE_DATE_PRINTS_DEFAULT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dateprints[1] = UX_PICTBRIDGE_DATE_PRINTS_OFF; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dateprints[2] = UX_PICTBRIDGE_DATE_PRINTS_ON; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dateprints[3] = 0; + + /* Set File Name Prints. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_filenameprints[0] = UX_PICTBRIDGE_FILE_NAME_PRINTS_DEFAULT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_filenameprints[1] = UX_PICTBRIDGE_FILE_NAME_PRINTS_OFF; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_filenameprints[2] = UX_PICTBRIDGE_FILE_NAME_PRINTS_ON; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_filenameprints[3] = 0; + + /* Set Image optimizes. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_imageoptimizes[0] = UX_PICTBRIDGE_IMAGE_OPTIMIZES_DEFAULT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_imageoptimizes[1] = UX_PICTBRIDGE_IMAGE_OPTIMIZES_OFF; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_imageoptimizes[2] = UX_PICTBRIDGE_IMAGE_OPTIMIZES_ON; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_imageoptimizes[3] = 0; + + /* Set Layouts. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_layouts[0] = UX_PICTBRIDGE_LAYOUTS_DEFAULT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_layouts[1] = UX_PICTBRIDGE_LAYOUTS_1_UP_BORDER; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_layouts[2] = UX_PICTBRIDGE_LAYOUTS_INDEX_PRINT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_layouts[3] = UX_PICTBRIDGE_LAYOUTS_1_UP_BORDERLESS; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_layouts[4] = 0; + + /* Set Fixed Sizes. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_fixedsizes[0] = UX_PICTBRIDGE_FIXED_SIZE_DEFAULT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_fixedsizes[1] = UX_PICTBRIDGE_FIXED_SIZE_35IX5I; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_fixedsizes[2] = UX_PICTBRIDGE_FIXED_SIZE_4IX6I; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_fixedsizes[3] = UX_PICTBRIDGE_FIXED_SIZE_5IX7I; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_fixedsizes[4] = UX_PICTBRIDGE_FIXED_SIZE_7CMX10CM; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_fixedsizes[5] = UX_PICTBRIDGE_FIXED_SIZE_LETTER; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_fixedsizes[6] = UX_PICTBRIDGE_FIXED_SIZE_A4; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_fixedsizes[7] = 0; + + /* Set croppings. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_croppings[0] = UX_PICTBRIDGE_CROPPINGS_DEFAULT; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_croppings[1] = UX_PICTBRIDGE_CROPPINGS_OFF; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_croppings[2] = UX_PICTBRIDGE_CROPPINGS_ON; + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_croppings[3] = 0; + + /* Set Print Service Status to idle. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_dpsprintservicestatus = UX_PICTBRIDGE_DPS_PRINTSERVICE_STATUS_IDLE; + + /* Set Job End Reason. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_jobendreason = UX_PICTBRIDGE_JOB_END_REASON_NOT_ENDED; + + /* Set Error Status. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_errorstatus = UX_PICTBRIDGE_ERROR_STATUS_NO_ERROR; + + /* Set Error Reason. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_errorreason = UX_PICTBRIDGE_ERROR_REASON_NO_REASON; + + /* Set Disconnection Enable. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_disconnectenable = UX_PICTBRIDGE_DISCONNECT_ENABLE_TRUE; + + /* Set Capability Changed. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_capabilitychanged = UX_PICTBRIDGE_CAPABILITY_CHANGED_FALSE; + + /* Set New Job OK. */ + pictbridge_host.ux_pictbridge_dpslocal.ux_pictbridge_devinfo_newjobok = UX_PICTBRIDGE_NEW_JOB_TRUE; + + /* Set a callback when an object is being received. */ + pictbridge_host.ux_pictbridge_application_object_data_write = test_pictbridge_host_object_data_write; + + /* Activate the pictbridge dpshost. */ + status = _ux_pictbridge_dpshost_start(&pictbridge_host, pima_host); + UX_TEST_CHECK_SUCCESS(status); + + status = tx_semaphore_get(&wait_semaphore, 30000); + UX_TEST_CHECK_SUCCESS(status); + tx_thread_sleep(5); + + 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); + +} + +static UINT test_pictbridge_device_object_data_copy(UX_PICTBRIDGE *pictbridge, ULONG object_handle, UCHAR *object_buffer, ULONG object_offset, ULONG object_length, ULONG *actual_length) +{ + pictbridge_device_copy_count ++; + + /* Copy the demanded object data portion. */ + ux_utility_memory_copy(object_buffer, ux_test_jpeg_image + object_offset, object_length); + + /* Update the actual length. */ + *actual_length = object_length; + + /* We have copied the requested data. Return OK. */ + return(UX_SUCCESS); + +} + + +UINT test_pictbridge_device_event_callback(struct UX_PICTBRIDGE_STRUCT *pictbridge, UINT event_flag) +{ + + /* Check if we received NotifyDeviceStatus event. */ + if (event_flag & UX_PICTBRIDGE_EVENT_FLAG_NOTIFY_DEVICE_STATUS) + { + + /* Check if the printer can accept new job. */ + if (pictbridge -> ux_pictbridge_dpsclient.ux_pictbridge_devinfo_newjobok == UX_PICTBRIDGE_NEW_JOB_TRUE) + { + + /* Let the demo thread to send a new job. */ + tx_semaphore_put(&print_semaphore); + } + } + + return UX_SUCCESS; +} + + +void test_thread_device_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG actual_flags; + + /* Create a semaphore for the demo. */ + status = tx_semaphore_create(&print_semaphore,"Print Semaphore", 0); + UX_TEST_CHECK_SUCCESS(status); + + while(1) + { + + /* We should wait for the host and the client to discover one another. */ + status = ux_utility_event_flags_get(&pictbridge_device.ux_pictbridge_event_flags_group, UX_PICTBRIDGE_EVENT_FLAG_DISCOVERY, + TX_AND_CLEAR, &actual_flags, UX_PICTBRIDGE_EVENT_TIMEOUT); + + /* Check status. */ + if (status == UX_SUCCESS) + { + + /* Check if the pictbridge state machine has changed to discovery complete. */ + if (pictbridge_device.ux_pictbridge_discovery_state == UX_PICTBRIDGE_DPSCLIENT_DISCOVERY_COMPLETE) + { + + /* We can now communicate using XML scripts with the printer. First get information on capabilities. */ + status = ux_pictbridge_dpsclient_api_configure_print_service(&pictbridge_device); + UX_TEST_CHECK_SUCCESS(status); + + /* Check status. */ + if (status == UX_SUCCESS) + { + + /* Get the printer capabilities : Qualities. */ + status = ux_pictbridge_dpsclient_api_capability(&pictbridge_device, UX_PICTBRIDGE_API_QUALITIES, 0); + UX_TEST_CHECK_SUCCESS(status); + + /* Get the printer capabilities : PaperSizes. */ + status = ux_pictbridge_dpsclient_api_capability(&pictbridge_device, UX_PICTBRIDGE_API_PAPER_SIZES, 0); + UX_TEST_CHECK_SUCCESS(status); + + /* Get the printer capabilities : FileTypes. */ + status = ux_pictbridge_dpsclient_api_capability(&pictbridge_device, UX_PICTBRIDGE_API_FILE_TYPES, 0); + UX_TEST_CHECK_SUCCESS(status); + + /* Get the printer capabilities : DatePrints. */ + status = ux_pictbridge_dpsclient_api_capability(&pictbridge_device, UX_PICTBRIDGE_API_DATE_PRINTS, 0); + UX_TEST_CHECK_SUCCESS(status); + + /* Get the printer capabilities : FileNamePrints. */ + status = ux_pictbridge_dpsclient_api_capability(&pictbridge_device, UX_PICTBRIDGE_API_FILE_NAME_PRINTS, 0); + UX_TEST_CHECK_SUCCESS(status); + + /* Get the printer capabilities : ImageOptimizes. */ + status = ux_pictbridge_dpsclient_api_capability(&pictbridge_device, UX_PICTBRIDGE_API_IMAGE_OPTIMIZES, 0); + UX_TEST_CHECK_SUCCESS(status); + + /* Get the printer capabilities : Layouts. */ + status = ux_pictbridge_dpsclient_api_capability(&pictbridge_device, UX_PICTBRIDGE_API_LAYOUTS, 0); + UX_TEST_CHECK_SUCCESS(status); + + /* Get the printer capabilities : FixedSizes. */ + status = ux_pictbridge_dpsclient_api_capability(&pictbridge_device, UX_PICTBRIDGE_API_FIXED_SIZES, 0); + UX_TEST_CHECK_SUCCESS(status); + + /* Get the printer capabilities : Croppings. */ + status = ux_pictbridge_dpsclient_api_capability(&pictbridge_device, UX_PICTBRIDGE_API_CROPPINGS, 0); + UX_TEST_CHECK_SUCCESS(status); + + /* We have all the printer capabilities, get the device status. */ + status = ux_pictbridge_dpsclient_api_device_status(&pictbridge_device); + UX_TEST_CHECK_SUCCESS(status); + + /* Check status. */ + if (status == UX_SUCCESS) + { + + /* Check if the printer is ready for a pring job. */ + if (pictbridge_device.ux_pictbridge_dpsclient.ux_pictbridge_devinfo_newjobok == UX_PICTBRIDGE_NEW_JOB_TRUE) + { + + /* We can start a new job. Fill in the JobConfig and PrintInfo structures. */ + jobinfo = &pictbridge_device.ux_pictbridge_jobinfo; + + /* Attach a printinfo structure to the job. */ + jobinfo -> ux_pictbridge_jobinfo_printinfo_start = &printinfo; + + + /* Set the default values for print job. */ + jobinfo -> ux_pictbridge_jobinfo_quality = UX_PICTBRIDGE_QUALITIES_DEFAULT; + jobinfo -> ux_pictbridge_jobinfo_papersize = UX_PICTBRIDGE_PAPER_SIZES_DEFAULT; + jobinfo -> ux_pictbridge_jobinfo_papertype = UX_PICTBRIDGE_PAPER_TYPES_DEFAULT; + jobinfo -> ux_pictbridge_jobinfo_filetype = UX_PICTBRIDGE_FILE_TYPES_DEFAULT; + jobinfo -> ux_pictbridge_jobinfo_dateprint = UX_PICTBRIDGE_DATE_PRINTS_DEFAULT; + jobinfo -> ux_pictbridge_jobinfo_filenameprint = UX_PICTBRIDGE_FILE_NAME_PRINTS_DEFAULT; + jobinfo -> ux_pictbridge_jobinfo_imageoptimize = UX_PICTBRIDGE_IMAGE_OPTIMIZES_OFF; + jobinfo -> ux_pictbridge_jobinfo_layout = UX_PICTBRIDGE_LAYOUTS_DEFAULT; + jobinfo -> ux_pictbridge_jobinfo_fixedsize = UX_PICTBRIDGE_FIXED_SIZE_DEFAULT; + jobinfo -> ux_pictbridge_jobinfo_cropping = UX_PICTBRIDGE_CROPPINGS_DEFAULT; + + /* Program the callback function for reading the object data. */ + jobinfo -> ux_pictbridge_jobinfo_object_data_read = test_pictbridge_device_object_data_copy; + + /* This is a demo, the fileID is hardwired (1 and 2 for scripts, 3 for photo to be printed. */ + printinfo.ux_pictbridge_printinfo_fileid = UX_PICTBRIDGE_OBJECT_HANDLE_PRINT; + ux_utility_memory_copy(printinfo.ux_pictbridge_printinfo_filename, "Pictbridge demo file", 20); + ux_utility_memory_copy(printinfo.ux_pictbridge_printinfo_date, "01/01/2008", 10); + + /* Fill in the object info to be printed. First get the pointer to the object container in the job info structure. */ + object = (UX_SLAVE_CLASS_PIMA_OBJECT *) jobinfo -> ux_pictbridge_jobinfo_object; + + /* Store the object format : JPEG picture. */ + object -> ux_device_class_pima_object_format = UX_DEVICE_CLASS_PIMA_OFC_EXIF_JPEG; + object -> ux_device_class_pima_object_compressed_size = UX_TEST_JPEG_IMAGE_LENGTH; + object -> ux_device_class_pima_object_offset = 0; + object -> ux_device_class_pima_object_handle_id = UX_PICTBRIDGE_OBJECT_HANDLE_PRINT; + object -> ux_device_class_pima_object_length = UX_TEST_JPEG_IMAGE_LENGTH; + + /* File name is in Unicode. */ + ux_utility_string_to_unicode("JPEG Image", object -> ux_device_class_pima_object_filename); + + /* And start the job. */ + status = ux_pictbridge_dpsclient_api_start_job(&pictbridge_device); + UX_TEST_CHECK_SUCCESS(status); + + /* Register the callback function to receive events from the printer. */ + ux_pictbridge_dpsclient_register_event_callback_function(&pictbridge_device, test_pictbridge_device_event_callback); + + /* Wait for the job to complete. */ + status = tx_semaphore_get(&print_semaphore, 30000); + UX_TEST_CHECK_SUCCESS(status); + + if (status == TX_SUCCESS) + { + + /* Print the job again to demo the use of callback function. */ + status = ux_pictbridge_dpsclient_api_start_job(&pictbridge_device); + UX_TEST_CHECK_SUCCESS(status); + + /* Let host thread run to end. */ + tx_semaphore_put(&wait_semaphore); + } + + /* Unregister the callback function by passing a Null pointer. */ + ux_pictbridge_dpsclient_register_event_callback_function(&pictbridge_device, UX_NULL); + } + } + } + } + } + } +} diff --git a/test/regression/usbx_pima_basic_test.c b/test/regression/usbx_pima_basic_test.c new file mode 100644 index 00000000..8932004e --- /dev/null +++ b/test/regression/usbx_pima_basic_test.c @@ -0,0 +1,3759 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#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_DEVICE *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_DEVICE *)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_pima_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +ULONG test_n; + + /* Inform user. */ + printf("Running PIMA Basic Functionality 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 void test_call_pima_apis(void) +{ +UINT status; +ULONG actual_length; + + 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); + + 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); + + status = ux_host_class_pima_object_handles_get(pima_host, &pima_host_session, host_buffer32, 64, 0, UX_HOST_CLASS_PIMA_OFC_UNDEFINED, 0); + UX_TEST_CHECK_SUCCESS(status); + + status = ux_host_class_pima_object_info_get(pima_host, &pima_host_session, 0, &pima_host_object); + UX_TEST_CHECK_SUCCESS(status); + + status = ux_host_class_pima_object_open(pima_host, &pima_host_session, 0, &pima_host_object); + UX_TEST_CHECK_SUCCESS(status); + + status = ux_host_class_pima_object_close(pima_host, &pima_host_session, 0, &pima_host_object); + 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_call_pima_apis(); + + 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_rndis_basic_test.c b/test/regression/usbx_rndis_basic_test.c new file mode 100644 index 00000000..c81bbaea --- /dev/null +++ b/test/regression/usbx_rndis_basic_test.c @@ -0,0 +1,663 @@ +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_network_driver.h" +#include "ux_host_class_cdc_ecm.h" +#include "ux_device_class_rndis.h" +#include "ux_device_class_cdc_ecm.h" +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" +#include "ux_test.h" +#include "ux_hcd_sim_host.h" +#include "ux_dcd_sim_slave.h" + +#define DEMO_IP_THREAD_STACK_SIZE (8*1024) +#define HOST_IP_ADDRESS IP_ADDRESS(192,168,1,176) +#define HOST_SOCKET_PORT_UDP 45054 +#define DEVICE_IP_ADDRESS IP_ADDRESS(192,168,1,175) +#define DEVICE_SOCKET_PORT_UDP 45055 + +#define PACKET_PAYLOAD 1400 +#define PACKET_POOL_SIZE (PACKET_PAYLOAD*10000) +#define ARP_MEMORY_SIZE 1024 + +/* Define local constants. */ + +#define UX_DEMO_STACK_SIZE (4*1024) +#define UX_USBX_MEMORY_SIZE (128*1024) + +/* Host */ + +static UX_HOST_CLASS *class_driver_host; +static UX_HOST_CLASS_CDC_ECM *cdc_ecm_host; +static UX_HOST_CLASS_CDC_ECM **cdc_ecm_host_ptr; +static TX_THREAD thread_host; +static UCHAR thread_stack_host[UX_DEMO_STACK_SIZE]; +static NX_IP nx_ip_host; +static NX_PACKET_POOL packet_pool_host; +static NX_UDP_SOCKET udp_socket_host; +static CHAR *packet_pool_memory_host; +static CHAR ip_thread_stack_host[DEMO_IP_THREAD_STACK_SIZE]; +static CHAR arp_memory_host[ARP_MEMORY_SIZE]; + +/* Device */ + +static TX_THREAD thread_device; +static UX_HOST_CLASS *class_driver_device; +static UX_SLAVE_CLASS_RNDIS *rndis_device; +static UX_SLAVE_CLASS_RNDIS_PARAMETER rndis_parameter; +static UCHAR thread_stack_device[UX_DEMO_STACK_SIZE]; +static NX_IP nx_ip_device; +static NX_PACKET_POOL packet_pool_device; +static NX_UDP_SOCKET udp_socket_device; +static CHAR *packet_pool_memory_device; +static CHAR ip_thread_stack_device[DEMO_IP_THREAD_STACK_SIZE]; +static CHAR arp_memory_device[ARP_MEMORY_SIZE]; + +static UCHAR global_is_device_initialized; + +static ULONG global_basic_test_num_writes_host; +static ULONG global_basic_test_num_reads_host; + +static ULONG global_basic_test_num_writes_device; +static ULONG global_basic_test_num_reads_device; + +/* Define local prototypes and definitions. */ +static void thread_entry_host(ULONG arg); +static void thread_entry_device(ULONG arg); + +//#define USE_ZERO_ENDPOINT_SETTING + +static unsigned char device_framework_high_speed[] = { + + /* Device Descriptor */ + 0x12, /* bLength */ + 0x01, /* bDescriptorType */ + 0x10, 0x01, /* bcdUSB */ + 0xef, /* bDeviceClass - Depends on bDeviceSubClass */ + 0x02, /* bDeviceSubClass - Depends on bDeviceProtocol */ + 0x01, /* bDeviceProtocol - There's an IAD */ + 0x40, /* bMaxPacketSize0 */ + 0x70, 0x07, /* idVendor */ + 0x42, 0x10, /* idProduct */ + 0x00, 0x01, /* bcdDevice */ + 0x01, /* iManufacturer */ + 0x02, /* iProduct */ + 0x03, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ + + /* Configuration Descriptor */ + 0x09, /* bLength */ + 0x02, /* bDescriptorType */ + +#ifdef USE_ZERO_ENDPOINT_SETTING + 0x58, 0x00, /* wTotalLength */ +#else + 0x4f, 0x00, /* wTotalLength */ +#endif + 0x02, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xc0, /* bmAttributes - Self-powered */ + 0x00, /* bMaxPower */ + + /* Interface Association Descriptor */ + 0x08, /* bLength */ + 0x0b, /* bDescriptorType */ + 0x00, /* bFirstInterface */ + 0x02, /* bInterfaceCount */ + 0x02, /* bFunctionClass - CDC - Communication */ + 0x06, /* bFunctionSubClass - ECM */ + 0x00, /* bFunctionProtocol - No class specific protocol required */ + 0x00, /* iFunction */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x02, /* bInterfaceClass - CDC - Communication */ + 0x06, /* bInterfaceSubClass - ECM */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* CDC Header Functional Descriptor */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x00, /* bDescriptorSubType */ + 0x10, 0x01, /* bcdCDC */ + + /* CDC ECM Functional Descriptor */ + 0x0d, /* bLength */ + 0x24, /* bDescriptorType */ + 0x0f, /* bDescriptorSubType */ + 0x04, /* iMACAddress */ + 0x00, 0x00, 0x00, 0x00, /* bmEthernetStatistics */ + 0xea, 0x05, /* wMaxSegmentSize */ + 0x00, 0x00, /* wNumberMCFilters */ + 0x00, /* bNumberPowerFilters */ + + /* CDC Union Functional Descriptor */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x06, /* bDescriptorSubType */ + 0x00, /* bmMasterInterface */ + 0x01, /* bmSlaveInterface0 */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x83, /* bEndpointAddress */ + 0x03, /* bmAttributes - Interrupt */ + 0x08, 0x00, /* wMaxPacketSize */ + 0x08, /* bInterval */ + +#ifdef USE_ZERO_ENDPOINT_SETTING + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x01, /* bAlternateSetting */ + 0x02, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ +#else + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x02, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ +#endif + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x02, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x81, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + +}; + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL CDCECM Device" */ + 0x09, 0x04, 0x02, 0x10, + 0x45, 0x4c, 0x20, 0x43, 0x44, 0x43, 0x45, 0x43, + 0x4d, 0x20, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31, + + /* MAC Address string descriptor : Index 4 - "001E5841B879" */ + 0x09, 0x04, 0x04, 0x0C, + 0x30, 0x30, 0x31, 0x45, 0x35, 0x38, + 0x34, 0x31, 0x42, 0x38, 0x37, 0x39, + +}; + +static unsigned char *device_framework_full_speed = device_framework_high_speed; +#define FRAMEWORK_LENGTH sizeof(device_framework_high_speed) + + /* 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 + }; + +/* Define local variables. */ + +static UINT class_cdc_ecm_get_host(void) +{ + +UX_HOST_CLASS *class; +UINT status; + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_cdc_ecm_name, &class); + if (status != UX_SUCCESS) + test_control_return(0); + + /* We get the first instance of the storage device */ + do + { + status = ux_host_stack_class_instance_get(class, 0, (void **) &cdc_ecm_host); + tx_thread_sleep(10); + } while (status != UX_SUCCESS); + + /* We still need to wait for the cdc-ecm status to be live */ + while (cdc_ecm_host -> ux_host_class_cdc_ecm_state != UX_HOST_CLASS_INSTANCE_LIVE) + tx_thread_sleep(10); + + return(UX_SUCCESS); +} + +static VOID demo_rndis_instance_activate(VOID *rndis_instance) +{ + + /* Save the CDC instance. */ + rndis_device = (UX_SLAVE_CLASS_RNDIS *) rndis_instance; +} + +static VOID demo_rndis_instance_deactivate(VOID *rndis_instance) +{ + + /* Reset the CDC instance. */ + rndis_device = UX_NULL; +} + +static void read_packet_udp(NX_UDP_SOCKET *udp_socket, ULONG num_reads, CHAR *name) +{ + +NX_PACKET *rcv_packet; +ULONG num_writes_from_peer; + +#ifndef LOCAL_MACHINE + if (num_reads % 100 == 0) +#endif + stepinfo("%s reading packet# %lu\n", name, num_reads); + + UX_TEST_CHECK_SUCCESS(nx_udp_socket_receive(udp_socket, &rcv_packet, NX_WAIT_FOREVER)); + + num_writes_from_peer = *(ULONG *)rcv_packet->nx_packet_prepend_ptr; + if (num_writes_from_peer != num_reads) + test_control_return(0); + + UX_TEST_CHECK_SUCCESS(nx_packet_release(rcv_packet)); +} + +static void write_packet_udp(NX_UDP_SOCKET *udp_socket, NX_PACKET_POOL *packet_pool, ULONG ip_address, ULONG port, ULONG num_writes, CHAR *name) +{ + +NX_PACKET *out_packet; + + UX_TEST_CHECK_SUCCESS(nx_packet_allocate(packet_pool, &out_packet, NX_UDP_PACKET, MS_TO_TICK(1000))); + + *(ULONG *)out_packet->nx_packet_prepend_ptr = num_writes; + out_packet->nx_packet_length = sizeof(ULONG); + out_packet->nx_packet_append_ptr = out_packet->nx_packet_prepend_ptr + out_packet->nx_packet_length; + +#ifndef LOCAL_MACHINE + if (num_writes % 100 == 0) +#endif + stepinfo("%s writing packet# %lu\n", name, num_writes); + + UX_TEST_CHECK_SUCCESS(nx_udp_socket_send(udp_socket, out_packet, ip_address, port)); +} + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_rndis_basic_test_application_define(void *first_unused_memory) +#endif +{ + +CHAR *memory_pointer = first_unused_memory; + + /* Inform user. */ + printf("Running RNDIS Basic Functionality Test.............................. "); + + stepinfo("\n"); + + /* Initialize USBX Memory. */ + UX_TEST_CHECK_SUCCESS(ux_system_initialize(memory_pointer, UX_USBX_MEMORY_SIZE, UX_NULL, 0)); + memory_pointer += UX_USBX_MEMORY_SIZE; + + /* It looks weird if this doesn't have a comment! */ + ux_utility_error_callback_register(ux_test_error_callback); + + /* Perform the initialization of the network driver. */ + UX_TEST_CHECK_SUCCESS(ux_network_driver_init()); + + /* Initialize the NetX system. */ + nx_system_initialize(); + + /* Now allocate memory for the packet pools. Note that using the memory passed + to us by ThreadX is mucho bettero than putting it in global memory because + we can reuse the memory for each test. So no more having to worry about + running out of memory! */ + packet_pool_memory_host = memory_pointer; + memory_pointer += PACKET_POOL_SIZE; + packet_pool_memory_device = memory_pointer; + memory_pointer += PACKET_POOL_SIZE; + + /* Create the host thread. */ + UX_TEST_CHECK_SUCCESS(tx_thread_create(&thread_host, "host thread", thread_entry_host, 0, + thread_stack_host, UX_DEMO_STACK_SIZE, + 30, 30, 1, TX_AUTO_START)); + + /* Create the slave thread. */ + UX_TEST_CHECK_SUCCESS(tx_thread_create(&thread_device, "device thread", thread_entry_device, 0, + thread_stack_device, UX_DEMO_STACK_SIZE, + 30, 30, 1, TX_AUTO_START)); +} + +/* Needs to be large enough to hold NetX packet data and RNDIS header. */ +static UCHAR host_bulk_endpoint_transfer_data[16*1024]; + +static UINT my_ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UX_TRANSFER *transfer_request; +UX_ENDPOINT *endpoint; + + + if (function == UX_HCD_TRANSFER_REQUEST) + { + + transfer_request = parameter; + endpoint = transfer_request->ux_transfer_request_endpoint; + + /* Bulk out? */ + if ((endpoint->ux_endpoint_descriptor.bmAttributes == 0x02) && + (endpoint->ux_endpoint_descriptor.bEndpointAddress & 0x80) == 0) + { + + UX_TEST_ASSERT(transfer_request->ux_transfer_request_requested_length + UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH <= sizeof(host_bulk_endpoint_transfer_data)); + + /* Fix it, now! - we need to add the RNDIS header. */ + + /* Copy that packet payload. */ + memcpy(host_bulk_endpoint_transfer_data + UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH, + transfer_request->ux_transfer_request_data_pointer, + transfer_request->ux_transfer_request_requested_length); + + /* Add the RNDIS header to this packet. */ + + _ux_utility_long_put(host_bulk_endpoint_transfer_data + UX_DEVICE_CLASS_RNDIS_PACKET_MESSAGE_TYPE, UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_MSG); + + _ux_utility_long_put(host_bulk_endpoint_transfer_data + UX_DEVICE_CLASS_RNDIS_PACKET_MESSAGE_LENGTH, + transfer_request->ux_transfer_request_requested_length + UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH); + + _ux_utility_long_put(host_bulk_endpoint_transfer_data + UX_DEVICE_CLASS_RNDIS_PACKET_DATA_OFFSET, + UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH - UX_DEVICE_CLASS_RNDIS_PACKET_DATA_OFFSET); + + _ux_utility_long_put(host_bulk_endpoint_transfer_data + UX_DEVICE_CLASS_RNDIS_PACKET_DATA_LENGTH, + transfer_request->ux_transfer_request_requested_length); + + /* The original data pointer points to the packet, so no leak. We also + only allow one transfer at a time, so no worries with overriding data. */ + transfer_request->ux_transfer_request_data_pointer = host_bulk_endpoint_transfer_data; + transfer_request->ux_transfer_request_requested_length += UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH; + } + } + + return _ux_hcd_sim_host_entry(hcd, function, parameter); +} + +static UINT my_ux_dcd_sim_slave_function(UX_SLAVE_DCD *dcd, UINT function, VOID *parameter) +{ + +UX_SLAVE_TRANSFER *transfer_request; +UX_SLAVE_ENDPOINT *endpoint; +UINT netx_packet_length; +UINT i; + + + if (function == UX_HCD_TRANSFER_REQUEST) + { + + transfer_request = parameter; + endpoint = transfer_request->ux_slave_transfer_request_endpoint; + + /* Bulk in? */ + if ((endpoint->ux_slave_endpoint_descriptor.bmAttributes == 0x02) && + (endpoint->ux_slave_endpoint_descriptor.bEndpointAddress & 0x80) != 0) + { + + /* Fix it, now! - we need to remove the RNDIS header. */ + + netx_packet_length = transfer_request->ux_slave_transfer_request_requested_length - UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH; + + /* Just shift the packet over the RNDIS header. */ + for (i = 0; i < netx_packet_length; i++) + { + + transfer_request->ux_slave_transfer_request_data_pointer[i] = transfer_request->ux_slave_transfer_request_data_pointer[i + UX_DEVICE_CLASS_RNDIS_PACKET_HEADER_LENGTH]; + } + + transfer_request->ux_slave_transfer_request_requested_length = netx_packet_length; + } + } + + return _ux_dcd_sim_slave_function(dcd, function, parameter); +} + +static void thread_entry_host(ULONG input) +{ + +UINT i; +UINT num_iters; + + /* Wait for device to initialize before starting the HCD thread; also, there + seems to be some race condition with simultaneous NetX initialization: + somehow, device was calling the host CDC-ECM write. */ + while (!global_is_device_initialized) + tx_thread_sleep(10); + + /* Wait for device to initialize. */ + while (!global_is_device_initialized) + tx_thread_sleep(10); + + /* Create the IP instance. */ + + UX_TEST_CHECK_SUCCESS(nx_packet_pool_create(&packet_pool_host, "NetX Host Packet Pool", PACKET_PAYLOAD, packet_pool_memory_host, PACKET_POOL_SIZE)); + UX_TEST_CHECK_SUCCESS(nx_ip_create(&nx_ip_host, "NetX Host Thread", HOST_IP_ADDRESS, 0xFF000000UL, + &packet_pool_host, _ux_network_driver_entry, ip_thread_stack_host, DEMO_IP_THREAD_STACK_SIZE, 1)); + + /* Setup ARP. */ + + UX_TEST_CHECK_SUCCESS(nx_arp_enable(&nx_ip_host, (void *)arp_memory_host, ARP_MEMORY_SIZE)); + UX_TEST_CHECK_SUCCESS(nx_arp_static_entry_create(&nx_ip_host, DEVICE_IP_ADDRESS, 0x0000001E, 0x80032CD8)); + + /* Setup UDP. */ + + UX_TEST_CHECK_SUCCESS(nx_udp_enable(&nx_ip_host)); + UX_TEST_CHECK_SUCCESS(nx_udp_socket_create(&nx_ip_host, &udp_socket_host, "USB HOST UDP SOCKET", NX_IP_NORMAL, NX_DONT_FRAGMENT, 20, 20)); + UX_TEST_CHECK_SUCCESS(nx_udp_socket_bind(&udp_socket_host, HOST_SOCKET_PORT_UDP, NX_NO_WAIT)); + + /* The code below is required for installing the host portion of USBX. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_initialize(UX_NULL)); + + /* Register cdc_ecm class. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_class_register(_ux_system_host_class_cdc_ecm_name, ux_host_class_cdc_ecm_entry)); + + ux_test_ignore_all_errors(); + + /* Register all the USB host controllers available in this system. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + + /* Change entry function. */ + _ux_system_host->ux_system_host_hcd_array[0].ux_hcd_entry_function = my_ux_hcd_sim_host_entry; + + /* Find the storage class. */ + class_cdc_ecm_get_host(); + + /* Now wait for the link to be up. */ + while (cdc_ecm_host -> ux_host_class_cdc_ecm_link_state != UX_HOST_CLASS_CDC_ECM_LINK_STATE_UP) + tx_thread_sleep(10); + + for (num_iters = 0; num_iters < 100; num_iters++) + { + + for (i = 0; i < 10; i++) + write_packet_udp(&udp_socket_host, &packet_pool_host, DEVICE_IP_ADDRESS, DEVICE_SOCKET_PORT_UDP, global_basic_test_num_writes_host++, "host"); + + for (i = 0; i < 10; i++) + read_packet_udp(&udp_socket_host, global_basic_test_num_reads_host++, "host"); + } + + /* Wait for all transfers to complete. */ + while (global_basic_test_num_reads_host != 1000 || global_basic_test_num_reads_device != 1000) + tx_thread_sleep(10); + + /* And finally the usbx system resources. */ + _ux_system_uninitialize(); + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + +static void thread_entry_device(ULONG input) +{ + +UINT i; +UINT status; +UINT num_iters; +UCHAR *notification_buffer; +UX_SLAVE_TRANSFER *interrupt_transfer; + + /* Create the IP instance. */ + + UX_TEST_CHECK_SUCCESS(nx_packet_pool_create(&packet_pool_device, "NetX Device Packet Pool", PACKET_PAYLOAD, packet_pool_memory_device, PACKET_POOL_SIZE)); + + UX_TEST_CHECK_SUCCESS(nx_ip_create(&nx_ip_device, "NetX Device Thread", DEVICE_IP_ADDRESS, 0xFF000000L, &packet_pool_device, + _ux_network_driver_entry, ip_thread_stack_device, DEMO_IP_THREAD_STACK_SIZE, 1)); + + /* Setup ARP. */ + + UX_TEST_CHECK_SUCCESS(nx_arp_enable(&nx_ip_device, (void *)arp_memory_device, ARP_MEMORY_SIZE)); + UX_TEST_CHECK_SUCCESS(nx_arp_static_entry_create(&nx_ip_device, HOST_IP_ADDRESS, 0x0000001E, 0x5841B878)); + + /* Setup UDP. */ + + UX_TEST_CHECK_SUCCESS(nx_udp_enable(&nx_ip_device)); + UX_TEST_CHECK_SUCCESS(nx_udp_socket_create(&nx_ip_device, &udp_socket_device, "USB DEVICE UDP SOCKET", NX_IP_NORMAL, NX_DONT_FRAGMENT, 20, 20)); + UX_TEST_CHECK_SUCCESS(nx_udp_socket_bind(&udp_socket_device, DEVICE_SOCKET_PORT_UDP, NX_NO_WAIT)); + + /* The code below is required for installing the device portion of USBX. */ + status = ux_device_stack_initialize(device_framework_high_speed, FRAMEWORK_LENGTH, + device_framework_full_speed, FRAMEWORK_LENGTH, + string_framework, sizeof(string_framework), + language_id_framework, sizeof(language_id_framework), + UX_NULL); + if (status) + test_control_return(0); + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + rndis_parameter.ux_slave_class_rndis_instance_activate = demo_rndis_instance_activate; + rndis_parameter.ux_slave_class_rndis_instance_deactivate = demo_rndis_instance_deactivate; + + /* Define a local NODE ID. */ + rndis_parameter.ux_slave_class_rndis_parameter_local_node_id[0] = 0x00; + rndis_parameter.ux_slave_class_rndis_parameter_local_node_id[1] = 0x1e; + rndis_parameter.ux_slave_class_rndis_parameter_local_node_id[2] = 0x58; + rndis_parameter.ux_slave_class_rndis_parameter_local_node_id[3] = 0x41; + rndis_parameter.ux_slave_class_rndis_parameter_local_node_id[4] = 0xb8; + rndis_parameter.ux_slave_class_rndis_parameter_local_node_id[5] = 0x78; + + /* Define a remote NODE ID. */ + rndis_parameter.ux_slave_class_rndis_parameter_remote_node_id[0] = 0x00; + rndis_parameter.ux_slave_class_rndis_parameter_remote_node_id[1] = 0x1e; + rndis_parameter.ux_slave_class_rndis_parameter_remote_node_id[2] = 0x58; + rndis_parameter.ux_slave_class_rndis_parameter_remote_node_id[3] = 0x41; + rndis_parameter.ux_slave_class_rndis_parameter_remote_node_id[4] = 0xb8; + rndis_parameter.ux_slave_class_rndis_parameter_remote_node_id[5] = 0x79; + + /* Set extra parameters used by the RNDIS query command with certain OIDs. */ + rndis_parameter.ux_slave_class_rndis_parameter_vendor_id = 0x04b4 ; + rndis_parameter.ux_slave_class_rndis_parameter_driver_version = 0x1127; + ux_utility_memory_copy(rndis_parameter.ux_slave_class_rndis_parameter_vendor_description, "ELOGIC RNDIS", 12); + + /* Initialize the device rndis class. This class owns both interfaces. */ + status = ux_device_stack_class_register(_ux_system_slave_class_rndis_name, ux_device_class_rndis_entry, 1, 0, &rndis_parameter); + if (status) + test_control_return(0); + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + if (status) + test_control_return(0); + + _ux_system_slave->ux_system_slave_dcd.ux_slave_dcd_function = my_ux_dcd_sim_slave_function; + + global_is_device_initialized = UX_TRUE; + + while (!rndis_device) + tx_thread_sleep(10); + + while (rndis_device -> ux_slave_class_rndis_link_state != UX_DEVICE_CLASS_RNDIS_LINK_STATE_UP) + tx_thread_sleep(10); + + /* Since host is CDC-ECM, it's waiting for the LINK_UP notification from the + interrupt endpoint. RNDIS does not send this, so we have to do it manually. */ + { + interrupt_transfer = &rndis_device->ux_slave_class_rndis_interrupt_endpoint->ux_slave_endpoint_transfer_request; + + /* Build the Network Notification response. */ + notification_buffer = interrupt_transfer->ux_slave_transfer_request_data_pointer; + + /* Set the request type. */ + *(notification_buffer + UX_SETUP_REQUEST_TYPE) = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + + /* Set the request itself. */ + *(notification_buffer + UX_SETUP_REQUEST) = 0; + + /* Set the value. It is the network link. */ + _ux_utility_short_put(notification_buffer + UX_SETUP_VALUE, (USHORT)(rndis_device->ux_slave_class_rndis_link_state)); + + /* Set the Index. It is interface. The interface used is the DATA interface. Here we simply take the interface number of the CONTROL and add 1 to it + as it is assumed the classes are contiguous in number. */ + _ux_utility_short_put(notification_buffer + UX_SETUP_INDEX, (USHORT)(rndis_device->ux_slave_class_rndis_interface->ux_slave_interface_descriptor.bInterfaceNumber + 1)); + + /* And the length is zero. */ + *(notification_buffer + UX_SETUP_LENGTH) = 0; + + /* Send the request to the device controller. */ + status = _ux_device_stack_transfer_request(interrupt_transfer, UX_DEVICE_CLASS_CDC_ECM_INTERRUPT_RESPONSE_LENGTH, + UX_DEVICE_CLASS_CDC_ECM_INTERRUPT_RESPONSE_LENGTH); + /* Check error code. */ + if (status != UX_SUCCESS) + test_control_return(0); + } + + for (num_iters = 0; num_iters < 100; num_iters++) + { + + for (i = 0; i < 10; i++) + write_packet_udp(&udp_socket_device, &packet_pool_device, HOST_IP_ADDRESS, HOST_SOCKET_PORT_UDP, global_basic_test_num_writes_device++, "device"); + + for (i = 0; i < 10; i++) + read_packet_udp(&udp_socket_device, global_basic_test_num_reads_device++, "device"); + } +} \ No newline at end of file diff --git a/test/regression/usbx_standalone_cdc_acm_basic_memory_test.c b/test/regression/usbx_standalone_cdc_acm_basic_memory_test.c new file mode 100644 index 00000000..0a713ae9 --- /dev/null +++ b/test/regression/usbx_standalone_cdc_acm_basic_memory_test.c @@ -0,0 +1,828 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" +#include "ux_host_class_cdc_acm.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static TX_THREAD ux_test_thread_host_simulation; +static TX_THREAD ux_test_thread_slave_simulation; +static void ux_test_thread_host_simulation_entry(ULONG); +static void ux_test_thread_slave_simulation_entry(ULONG); + +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +static UCHAR cdc_acm_slave_change; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_cdc_sem_usage; +static ULONG rsc_cdc_sem_get_count; +static ULONG rsc_cdc_mutex_usage; +static ULONG rsc_cdc_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +/* Define device framework. */ + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 93 +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 103 +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Configuration 1 descriptor 9 bytes */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Endpoint 0x83 descriptor 7 bytes */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, /* @ 93 - 14 + 2 = 81 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, /* @ 93 - 7 + 2 = 88 */ + 0x02, + 0x40, 0x00, + 0x00, + +}; + +#define DEVICE_FRAMEWORK_EPA_POS_1_FS (DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 14 + 2) +#define DEVICE_FRAMEWORK_EPA_POS_2_FS (DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 7 + 2) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor */ + 0x05, 0x24, 0x06, + 0x00, + 0x01, + + /* Call Management Functional Descriptor */ + 0x05, 0x24, 0x01, + 0x00, + 0x01, + + /* Endpoint 0x83 descriptor */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor */ + 0x07, 0x05, 0x02, /* @ 103 - 14 + 2 = 91 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor */ + 0x07, 0x05, 0x81, /* @ 103 - 7 + 2 = 98 */ + 0x02, + 0x40, 0x00, + 0x00, + +}; + +#define DEVICE_FRAMEWORK_EPA_POS_1_HS (DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 14 + 2) +#define DEVICE_FRAMEWORK_EPA_POS_2_HS (DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 7 + 2) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 + }; + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +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; +} + +static UINT demo_class_cdc_acm_get(void) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_CDC_ACM *cdc_acm_host; + + + /* Find the main cdc_acm container */ + status = ux_host_stack_class_get(_ux_system_host_class_cdc_acm_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* We get the first instance of the cdc_acm device */ + do + { + + status = ux_host_stack_class_instance_get(class, 0, (void **) &cdc_acm_host); +#if defined(UX_HOST_STANDALONE) + ux_system_tasks_run(); +#else + tx_thread_sleep(10); +#endif + } while (status != UX_SUCCESS); + + /* We still need to wait for the cdc_acm status to be live */ + while (cdc_acm_host -> ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + { +#if defined(UX_HOST_STANDALONE) + ux_system_tasks_run(); +#else + tx_thread_sleep(10); +#endif + } + + /* Isolate both the control and data interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_DATA_CLASS) + { + /* This is the data interface. */ + cdc_acm_host_data = cdc_acm_host; + + /* In that case, the second one should be the control interface. */ + status = ux_host_stack_class_instance_get(class, 1, (void **) &cdc_acm_host); + + /* Check error. */ + if (status != UX_SUCCESS) + return(status); + + /* Check for the control interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + + /* This is the control interface. */ + cdc_acm_host_control = cdc_acm_host; + + return(UX_SUCCESS); + + } + } + else + { + /* Check for the control interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + + /* This is the control interface. */ + cdc_acm_host_control = cdc_acm_host; + + /* In that case, the second one should be the data interface. */ + status = ux_host_stack_class_instance_get(class, 1, (void **) &cdc_acm_host); + + /* Check error. */ + if (status != UX_SUCCESS) + return(status); + + /* Check for the data interface. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_DATA_CLASS) + { + + /* This is the data interface. */ + cdc_acm_host_data = cdc_acm_host; + + return(UX_SUCCESS); + + } + } + } + + /* Return ERROR. */ + return(UX_ERROR); +} + +static UINT demo_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + +#if defined(UX_HOST_STANDALONE) + case UX_STANDALONE_WAIT_BACKGROUND_TASK: + tx_thread_relinquish(); + break; +#endif + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; +} + +static VOID test_swap_framework_bulk_ep_descriptors(VOID) +{ +UCHAR tmp; + + tmp = device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_1_FS]; + device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_1_FS] = device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_2_FS]; + device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_2_FS] = tmp; + + tmp = device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_1_HS]; + device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_1_HS] = device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_2_HS]; + device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_2_HS] = tmp; +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *_params) +{ + + set_cfg_counter ++; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_sem_get_on_set_cfg = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_standalone_cdc_acm_basic_memory_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + /* Inform user. */ + printf("Running STANDALONE CDC ACM Basic Memory Test........................ "); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* 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 #1\n"); + 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(demo_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #2\n"); + test_control_return(1); + } + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_entry); + if (status != UX_SUCCESS) + { + + printf("ERROR #3\n"); + 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 #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + + if(status!=UX_SUCCESS) + { + + printf("ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #7\n"); + 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 #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_host_simulation, "tx demo host simulation", ux_test_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 #8\n"); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&ux_test_thread_slave_simulation, "tx demo slave simulation", ux_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #9\n"); + test_control_return(1); + } +} + +void ux_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_SLAVE_CLASS_CDC_ACM * cdc_acm_slave_bak; +UX_HOST_CLASS_CDC_ACM * cdc_acm_host_ctrl_bak; +UX_HOST_CLASS_CDC_ACM * cdc_acm_host_data_bak; +ULONG test_n; +ULONG mem_free; +ULONG retry; + + stepinfo("\n"); + + /* Find the cdc_acm class and wait for the link to be up. */ + status = demo_class_cdc_acm_get(); + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #10\n"); + test_control_return(1); + } + + /* Save slave instance for later tests. */ + cdc_acm_slave_bak = cdc_acm_slave; + /* Save host instances for later tests. */ + cdc_acm_host_ctrl_bak = cdc_acm_host_control; + cdc_acm_host_data_bak = cdc_acm_host_data; + + /* Test disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_count_reset(); + ux_test_utility_sim_mutex_create_count_reset(); + ux_test_utility_sim_sem_create_count_reset(); + ux_test_utility_sim_sem_get_count_reset(); + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + + /* Save free memory usage. */ + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + for (retry = 0; (retry < 10) && (cdc_acm_host_control == UX_NULL || cdc_acm_host_data == UX_NULL); retry ++) + tx_thread_sleep(10); + + /* Log create counts for further tests. */ + rsc_enum_mutex_usage = rsc_mutex_on_set_cfg; + rsc_enum_sem_usage = rsc_sem_on_set_cfg; + rsc_enum_mem_alloc_count = rsc_mem_alloc_cnt_on_set_cfg; + /* Log create counts when instances active for further tests. */ + rsc_cdc_mutex_usage = ux_test_utility_sim_mutex_create_count() - rsc_enum_mutex_usage; + rsc_cdc_sem_usage = ux_test_utility_sim_sem_create_count() - rsc_enum_sem_usage; + rsc_cdc_mem_alloc_count = ux_test_utility_sim_mem_alloc_count() - rsc_enum_mem_alloc_count; + + /* Lock log base for tests. */ + ux_test_utility_sim_mem_alloc_log_lock(); + + stepinfo("enum mem: %ld\n", rsc_enum_mem_alloc_count); + stepinfo("cdc mem : %ld\n", rsc_cdc_mem_alloc_count); + stepinfo("mem free: %ld, %ld\n", _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); + + /* Simulate detach and attach for FS enumeration, + and check if there is memory error in normal enumeration. + */ + stepinfo(">>>>>>>>>>>> Enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < 3; test_n++) + { + stepinfo("%4ld / 2\n", test_n); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #11.%ld: Memory level different after re-enumerations %ld <> %ld\n", test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on error. */ + ux_test_breakable_sleep(100, sleep_break_on_error); + + /* Check */ + if (!cdc_acm_host_control || !cdc_acm_host_data) + { + + printf("ERROR #12.%ld: Enumeration fail\n", test_n); + test_control_return(1); + } + } + + /* Simulate detach and attach for FS enumeration, + and test possible memory allocation error handlings. + */ + if (rsc_cdc_mem_alloc_count) stepinfo(">>>>>>>>>>>> Memory errors enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_cdc_mem_alloc_count; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_cdc_mem_alloc_count - 1); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #11.%ld: Memory level different after re-enumerations %ld <> %ld\n", test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Set memory error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n + rsc_enum_mem_alloc_count); + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on errors. */ + ux_test_breakable_sleep(100, sleep_break_on_error); + + /* Check error */ + if (cdc_acm_host_control && cdc_acm_host_data) + { + + printf("ERROR #12.%ld: device detected when there is memory error\n", test_n); + test_control_return(1); + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + } + ux_test_utility_sim_mem_alloc_error_generation_stop(); + if (rsc_cdc_mem_alloc_count) stepinfo("\n"); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_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 ux_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Keep running device stack tasks. */ + ux_system_tasks_run(); + tx_thread_relinquish(); + } +} diff --git a/test/regression/usbx_standalone_cdc_acm_basic_test.c b/test/regression/usbx_standalone_cdc_acm_basic_test.c new file mode 100644 index 00000000..ecc0b02f --- /dev/null +++ b/test/regression/usbx_standalone_cdc_acm_basic_test.c @@ -0,0 +1,1216 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" +#include "ux_host_class_cdc_acm.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static TX_THREAD ux_test_thread_host_simulation; +static TX_THREAD ux_test_thread_slave_simulation; +static void ux_test_thread_host_simulation_entry(ULONG); +static void ux_test_thread_slave_simulation_entry(ULONG); + +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; +static UX_HOST_CLASS_CDC_ACM_RECEPTION cdc_acm_host_reception; +static UCHAR cdc_acm_host_reception_buffer[UX_DEMO_RECEPTION_BUFFER_SIZE]; +static UINT cdc_acm_host_reception_status = 0; +static ULONG cdc_acm_host_reception_count = 0; +static UCHAR cdc_acm_host_read_buffer[UX_SLAVE_REQUEST_DATA_MAX_LENGTH * 2]; +static ULONG cdc_acm_host_read_buffer_length; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; +static UCHAR cdc_acm_slave_change; +static UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_PARAMETER cdc_acm_slave_line_coding; +static UX_SLAVE_CLASS_CDC_ACM_LINE_STATE_PARAMETER cdc_acm_slave_line_state; +static ULONG device_read_length = UX_SLAVE_REQUEST_DATA_MAX_LENGTH; +static UCHAR device_buffer[UX_SLAVE_REQUEST_DATA_MAX_LENGTH * 2]; + +static UCHAR host_buffer[UX_SLAVE_REQUEST_DATA_MAX_LENGTH * 2]; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_cdc_sem_usage; +static ULONG rsc_cdc_sem_get_count; +static ULONG rsc_cdc_mutex_usage; +static ULONG rsc_cdc_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +/* Define device framework. */ + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 93 +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 103 +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Configuration 1 descriptor 9 bytes */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Endpoint 0x83 descriptor 7 bytes */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, /* @ 93 - 14 + 2 = 81 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, /* @ 93 - 7 + 2 = 88 */ + 0x02, + 0x40, 0x00, + 0x00, + +}; + +#define DEVICE_FRAMEWORK_EPA_POS_1_FS (DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 14 + 2) +#define DEVICE_FRAMEWORK_EPA_POS_2_FS (DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 7 + 2) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor */ + 0x05, 0x24, 0x06, + 0x00, + 0x01, + + /* Call Management Functional Descriptor */ + 0x05, 0x24, 0x01, + 0x00, + 0x01, + + /* Endpoint 0x83 descriptor */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor */ + 0x07, 0x05, 0x02, /* @ 103 - 14 + 2 = 91 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor */ + 0x07, 0x05, 0x81, /* @ 103 - 7 + 2 = 98 */ + 0x02, + 0x40, 0x00, + 0x00, + +}; + +#define DEVICE_FRAMEWORK_EPA_POS_1_HS (DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 14 + 2) +#define DEVICE_FRAMEWORK_EPA_POS_2_HS (DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 7 + 2) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 + }; + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +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; +} + +static UINT demo_class_cdc_acm_get(void) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_CDC_ACM *cdc_acm_host; + + + /* Find the main cdc_acm container */ + status = ux_host_stack_class_get(_ux_system_host_class_cdc_acm_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* We get the first instance of the cdc_acm device */ + do + { + + status = ux_host_stack_class_instance_get(class, 0, (void **) &cdc_acm_host); +#if defined(UX_HOST_STANDALONE) + ux_system_tasks_run(); +#else + tx_thread_sleep(10); +#endif + } while (status != UX_SUCCESS); + + /* We still need to wait for the cdc_acm status to be live */ + while (cdc_acm_host -> ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + { +#if defined(UX_HOST_STANDALONE) + ux_system_tasks_run(); +#else + tx_thread_sleep(10); +#endif + } + + /* Isolate both the control and data interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_DATA_CLASS) + { + /* This is the data interface. */ + cdc_acm_host_data = cdc_acm_host; + + /* In that case, the second one should be the control interface. */ + status = ux_host_stack_class_instance_get(class, 1, (void **) &cdc_acm_host); + + /* Check error. */ + if (status != UX_SUCCESS) + return(status); + + /* Check for the control interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + + /* This is the control interface. */ + cdc_acm_host_control = cdc_acm_host; + + return(UX_SUCCESS); + + } + } + else + { + /* Check for the control interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + + /* This is the control interface. */ + cdc_acm_host_control = cdc_acm_host; + + /* In that case, the second one should be the data interface. */ + status = ux_host_stack_class_instance_get(class, 1, (void **) &cdc_acm_host); + + /* Check error. */ + if (status != UX_SUCCESS) + return(status); + + /* Check for the data interface. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_DATA_CLASS) + { + + /* This is the data interface. */ + cdc_acm_host_data = cdc_acm_host; + + return(UX_SUCCESS); + + } + } + } + + /* Return ERROR. */ + return(UX_ERROR); +} + +static UINT demo_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + +#if defined(UX_HOST_STANDALONE) + case UX_STANDALONE_WAIT_BACKGROUND_TASK: + tx_thread_relinquish(); + break; +#endif + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; + + /* Get new paramster. */ + ux_device_class_cdc_acm_ioctl(cdc_acm_slave, + UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING, + (VOID*)&cdc_acm_slave_line_coding); + ux_device_class_cdc_acm_ioctl(cdc_acm_slave, + UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING, + (VOID*)&cdc_acm_slave_line_state); +} + +static VOID test_swap_framework_bulk_ep_descriptors(VOID) +{ +UCHAR tmp; + + tmp = device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_1_FS]; + device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_1_FS] = device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_2_FS]; + device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_2_FS] = tmp; + + tmp = device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_1_HS]; + device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_1_HS] = device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_2_HS]; + device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_2_HS] = tmp; +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *_params) +{ + + set_cfg_counter ++; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_sem_get_on_set_cfg = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_standalone_cdc_acm_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + /* Inform user. */ + printf("Running STANDALONE CDC ACM Basic Test............................... "); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* 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 #1\n"); + 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(demo_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #2\n"); + test_control_return(1); + } + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_entry); + if (status != UX_SUCCESS) + { + + printf("ERROR #3\n"); + 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 #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + + if(status!=UX_SUCCESS) + { + + printf("ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #7\n"); + 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 #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_host_simulation, "tx demo host simulation", ux_test_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 #8\n"); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&ux_test_thread_slave_simulation, "tx demo slave simulation", ux_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #9\n"); + test_control_return(1); + } +} + +#if defined(UX_HOST_STANDALONE) +static void test_host_delay(ULONG ticks) +{ +ULONG t_start = tx_time_get(); +ULONG t_now, t_elapsed; + while(1) + { + ux_system_tasks_run(); + tx_thread_relinquish(); + if (ticks != TX_WAIT_FOREVER) + { + if (ticks == 0) + break; + t_now = tx_time_get(); + t_elapsed = _ux_utility_time_elapsed(t_start, t_now); + if (t_elapsed > ticks) + break; + } + } +} +#else +#define test_host_delay tx_thread_sleep +#endif + +static void test_cdc_acm_device_ioctl_parameters(void) +{ +UINT status; + if (cdc_acm_slave == UX_NULL) + { + printf("ERROR #%d, device instance not ready\n", __LINE__); + test_control_return(1); + } + + /* Get and check default line coding. */ + ux_utility_memory_set(&cdc_acm_slave_line_coding, 0, sizeof(cdc_acm_slave_line_coding)); + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, + UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING, + (VOID*)&cdc_acm_slave_line_coding); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_baudrate == + UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_RATE); + UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_stop_bit == + UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_STOP_BIT); + UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_parity == + UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_PARITY); + UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_data_bit == + UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_DATA_BIT); + + /* Set new line coding, read back to test. */ + cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_baudrate ++; + cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_stop_bit ++; + cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_parity ++; + cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_data_bit ++; + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, + UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_CODING, + (VOID*)&cdc_acm_slave_line_coding); + UX_TEST_ASSERT(status == UX_SUCCESS); + + ux_utility_memory_set(&cdc_acm_slave_line_coding, 0, sizeof(cdc_acm_slave_line_coding)); + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, + UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING, + (VOID*)&cdc_acm_slave_line_coding); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_baudrate == + UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_RATE + 1); + UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_stop_bit == + UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_STOP_BIT + 1); + UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_parity == + UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_PARITY + 1); + UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_data_bit == + UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_DATA_BIT + 1); + + /* Set line coding back. */ + cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_baudrate --; + cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_stop_bit --; + cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_parity --; + cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_data_bit --; + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, + UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_CODING, + (VOID*)&cdc_acm_slave_line_coding); + UX_TEST_ASSERT(status == UX_SUCCESS); + + /* Get and check line state. */ + ux_utility_memory_set(&cdc_acm_slave_line_state, 0, sizeof(cdc_acm_slave_line_state)); + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, + UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_STATE, + (VOID*)&cdc_acm_slave_line_state); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_dtr == 1); + UX_TEST_ASSERT(cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_rts == 1); + + /* Set new line state, read back to test. */ + cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_dtr ++; + cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_rts ++; + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, + UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_STATE, + (VOID*)&cdc_acm_slave_line_state); + UX_TEST_ASSERT(status == UX_SUCCESS); + + ux_utility_memory_set(&cdc_acm_slave_line_state, 0, sizeof(cdc_acm_slave_line_state)); + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, + UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_STATE, + (VOID*)&cdc_acm_slave_line_state); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_dtr == 2); + UX_TEST_ASSERT(cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_rts == 2); + + /* Set line state back. */ + cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_dtr --; + cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_rts --; + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, + UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_STATE, + (VOID*)&cdc_acm_slave_line_state); + UX_TEST_ASSERT(status == UX_SUCCESS); +} + + +static void test_thread_host_reception_callback(UX_HOST_CLASS_CDC_ACM *cdc_acm, UINT status, UCHAR *reception_buffer, ULONG reception_size) +{ +ULONG i; + + /* And move to the next reception buffer. Check if we are at the end of the application buffer. */ + if (cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_tail + + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_block_size >= + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_buffer + + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_buffer_size) + + /* We are at the end of the buffer. Move back to the beginning. */ + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_tail = + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_buffer; + + else + + /* Program the tail to be after the current buffer. */ + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_tail += + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_block_size; + + cdc_acm_host_reception_status = status; + cdc_acm_host_reception_count ++; + + /* Save buffer. */ + for (i = 0; + (i < reception_size) && + (cdc_acm_host_read_buffer_length < sizeof(cdc_acm_host_read_buffer)); + i ++, cdc_acm_host_read_buffer_length ++) + { + cdc_acm_host_read_buffer[cdc_acm_host_read_buffer_length] = reception_buffer[i]; + } + + return; +} + + +static void test_cdc_acm_device_read_length_set(ULONG new_length) +{ + if (device_read_length == new_length) + return; + tx_thread_sleep(1); + if (new_length < 64) + device_read_length = 64; + else + { + /* Align with 64. */ + device_read_length = (new_length & 63u) ? ((new_length & ~63u) + 64) : new_length; + } +#if !defined(UX_DEVICE_STANDALONE) + /* Cancel the pending read to apply new length. */ + ux_device_class_cdc_acm_ioctl(cdc_acm_slave, + UX_SLAVE_CLASS_CDC_ACM_IOCTL_ABORT_PIPE, + (VOID*)UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_RCV); +#else + /* Wait a while to let device background task do action. */ + tx_thread_sleep(2); +#endif +} + + +static void test_cdc_acm_device_read_write_blocking(void) +{ +UINT status; +ULONG actual_length; +UCHAR test_chr; +ULONG test_length; +ULONG i, test; +#undef N_TEST +#define N_TEST 5 +struct { + UCHAR chr; + ULONG len; +} tests[N_TEST] = { + {'$', 1}, + {'A', 64}, + {'N', 65}, + {'3', UX_SLAVE_REQUEST_DATA_MAX_LENGTH - 64}, + {'G', UX_SLAVE_REQUEST_DATA_MAX_LENGTH}, +}; + + for (test = 0; test < N_TEST; test ++) + { + test_chr = tests[test].chr; + test_length = tests[test].len; + test_cdc_acm_device_read_length_set(test_length); + + for (i = 0; i < test_length; i ++) + { + host_buffer[i] = test_chr; + } + + /* Blocking write. */ + status = ux_host_class_cdc_acm_write(cdc_acm_host_data, host_buffer, + test_length, &actual_length); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "test_length %ld\n", test_length); + if (((test_length & 63) == 0) && actual_length != device_read_length) + { + status = ux_host_class_cdc_acm_write(cdc_acm_host_data, host_buffer, + 0, &actual_length); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "test_length %ld\n", test_length); + } + + /* Blocking read. */ + _ux_utility_memory_set(host_buffer, ~test_chr, test_length); + status = ux_host_class_cdc_acm_read(cdc_acm_host_data, host_buffer, + test_length, &actual_length); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "test_length %ld\n", test_length); + if (actual_length != test_length) + { + printf("ERROR #%d, length not match %ld <> %ld\n", __LINE__, test_length, actual_length); + test_control_return(1); + } + for (i = 0; i < test_length; i ++) + { + UX_TEST_ASSERT_MESSAGE(host_buffer[i] == test_chr, "test_length %ld\n", test_length); + } + } +} + + +#if defined(UX_HOST_STANDALONE) + +static ULONG test_cdc_acm_host_write_callback_count = 0; +static UINT test_cdc_acm_host_write_callback_status; +static ULONG test_cdc_acm_host_write_callback_actual_length; +static VOID test_cdc_acm_host_write_callback(UX_HOST_CLASS_CDC_ACM *cdc_acm, + UINT status, ULONG actual_length) +{ + test_cdc_acm_host_write_callback_count ++; + test_cdc_acm_host_write_callback_status = status; + test_cdc_acm_host_write_callback_actual_length = actual_length; +} + +/* Uses _write_with_callback. */ + +static UINT test_cdc_acm_host_write(UX_HOST_CLASS_CDC_ACM *cdc_acm, + UCHAR *data_pointer, + ULONG requested_length, + ULONG *actual_length) +{ +UINT status; +ULONG i; + + status = ux_host_class_cdc_acm_ioctl(cdc_acm, + UX_HOST_CLASS_CDC_ACM_IOCTL_WRITE_CALLBACK, + (VOID*)test_cdc_acm_host_write_callback); + if (status != UX_SUCCESS) + return(status); + + test_cdc_acm_host_write_callback_count = 0; + status = ux_host_class_cdc_acm_write_with_callback(cdc_acm, data_pointer, requested_length); + if (status != UX_SUCCESS) + { + printf("ERROR #%d : write exec error 0x%x\n", __LINE__, status); + return(status); + } + test_host_delay(requested_length/64 + 1); + if (test_cdc_acm_host_write_callback_count == 0) + { + printf("ERROR #%d : write timeout\n", __LINE__); + return(UX_TRANSFER_TIMEOUT); + } + status = ux_host_class_cdc_acm_ioctl(cdc_acm, + UX_HOST_CLASS_CDC_ACM_IOCTL_GET_WRITE_STATUS, + (VOID*)actual_length); + if (status != test_cdc_acm_host_write_callback_status || + *actual_length != test_cdc_acm_host_write_callback_actual_length) + { + printf("ERROR #%d : write status conflict\n", __LINE__); + return(UX_ERROR); + } + return(UX_SUCCESS); +} +#else +#define test_cdc_acm_host_write ux_host_class_cdc_acm_write +#endif + + +static void test_cdc_acm_device_read_write(void) +{ +UINT status; +ULONG actual_length; +UCHAR test_chr; +ULONG test_length; +ULONG i, test; +#undef N_TEST +#define N_TEST 6 +struct { + UCHAR chr; + ULONG len; +} tests[N_TEST] = { + {'$', 1}, + {'A', 64}, + {'N', 65}, + {'3', UX_SLAVE_REQUEST_DATA_MAX_LENGTH - 64}, + {'G', UX_SLAVE_REQUEST_DATA_MAX_LENGTH}, + {'H', UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1}, +}; + + /* Read packet by packet on device side. */ + test_cdc_acm_device_read_length_set(64); + + /* Reception parameter */ + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_block_size = UX_DEMO_RECEPTION_BLOCK_SIZE; + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_buffer = cdc_acm_host_reception_buffer; + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_buffer_size = UX_DEMO_RECEPTION_BUFFER_SIZE; + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_callback = test_thread_host_reception_callback; + + /* Start reception. */ + status = ux_host_class_cdc_acm_reception_start(cdc_acm_host_data, &cdc_acm_host_reception); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: reception start fail %x\n", __LINE__, status); + test_control_return(1); + } + + for (test = 0; test < N_TEST; test ++) + { + test_chr = tests[test].chr; + test_length = tests[test].len; + + for (i = 0; i < test_length; i ++) + { + host_buffer[i] = test_chr; + cdc_acm_host_read_buffer[i] = ~test_chr; + } + cdc_acm_host_read_buffer_length = 0; + + status = test_cdc_acm_host_write(cdc_acm_host_data, host_buffer, + test_length, &actual_length); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "test_length %ld\n", test_length); + if (((test_length & 63) == 0) && actual_length != device_read_length) + { + status = test_cdc_acm_host_write(cdc_acm_host_data, host_buffer, + 0, &actual_length); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "test_length %ld\n", test_length); + } + + /* Wait a while for background reception. */ + test_host_delay(test_length/64 + 1); + + UX_TEST_ASSERT_MESSAGE(cdc_acm_host_reception_status == UX_SUCCESS, "test_length %ld\n", test_length); + if (cdc_acm_host_read_buffer_length != test_length) + { + printf("ERROR #%d, length not match %ld <> %ld\n", __LINE__, + test_length, cdc_acm_host_read_buffer_length); + test_control_return(1); + } + for (i = 0; i < test_length; i ++) + { + UX_TEST_ASSERT_MESSAGE(cdc_acm_host_read_buffer[i] == test_chr, "test_length %ld\n", test_length); + } + } + + /* Stop reception. */ + ux_host_class_cdc_acm_reception_stop(cdc_acm_host_data, &cdc_acm_host_reception); +} + +void ux_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; + + stepinfo("\n"); + + /* Find the cdc_acm class and wait for the link to be up. */ + status = demo_class_cdc_acm_get(); + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #10\n"); + test_control_return(1); + } + + test_cdc_acm_device_ioctl_parameters(); + test_cdc_acm_device_read_write_blocking(); + test_cdc_acm_device_read_write(); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_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 ux_test_thread_slave_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG actual_length; +ULONG read_length = device_read_length; +ULONG write_length, write_zlp = UX_FALSE; +#define CDC_ACM_DEVICE_STATE_READ UX_STATE_STEP +#define CDC_ACM_DEVICE_STATE_WRITE UX_STATE_STEP + 1 +#define CDC_ACM_DEVICE_STATE_ZLP UX_STATE_STEP + 2 +UINT cdc_acm_device_state = UX_STATE_RESET; + + while(1) + { + +#if defined(UX_DEVICE_STANDALONE) + + /* Keep running device stack tasks. */ + ux_system_tasks_run(); + + /* Reset state if read length changed. */ + if (read_length != device_read_length) + { + cdc_acm_device_state = UX_STATE_RESET; + read_length = device_read_length; + } + + /* CDC ACM echo state machine. */ + switch(cdc_acm_device_state) + { + case UX_STATE_RESET: + if (cdc_acm_slave == UX_NULL) + break; + + { + ux_device_class_cdc_acm_ioctl(cdc_acm_slave, + UX_SLAVE_CLASS_CDC_ACM_IOCTL_ABORT_PIPE, + (VOID*)UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_XMIT); + ux_device_class_cdc_acm_ioctl(cdc_acm_slave, + UX_SLAVE_CLASS_CDC_ACM_IOCTL_ABORT_PIPE, + (VOID*)UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_RCV); + cdc_acm_device_state = CDC_ACM_DEVICE_STATE_READ; + } + /* Fall through. */ + case CDC_ACM_DEVICE_STATE_READ: + if (cdc_acm_slave == UX_NULL) + { + cdc_acm_device_state = UX_STATE_RESET; + break; + } + status = ux_device_class_cdc_acm_read_run(cdc_acm_slave, + device_buffer, device_read_length, &actual_length); + if (status < UX_STATE_NEXT) + { + printf("ERROR #%d: read status 0x%x\n", __LINE__, status); + return; + } + if (status == UX_STATE_NEXT) + { + write_length = actual_length; + if ((actual_length < device_read_length) && + ((actual_length & 63) == 0)) + { + write_zlp = UX_TRUE; + } + cdc_acm_device_state = CDC_ACM_DEVICE_STATE_WRITE; + } + break; + case CDC_ACM_DEVICE_STATE_WRITE: + if (cdc_acm_slave == UX_NULL) + { + cdc_acm_device_state = UX_STATE_RESET; + break; + } + status = ux_device_class_cdc_acm_write_run(cdc_acm_slave, + device_buffer, write_length, &actual_length); + if (status < UX_STATE_NEXT) + { + printf("ERROR #%d: write status 0x%x\n", __LINE__, status); + return; + } + if (status == UX_STATE_NEXT) + { + if (write_zlp && ((write_length % 64) == 0)) + { + cdc_acm_device_state = CDC_ACM_DEVICE_STATE_ZLP; + break; + } + cdc_acm_device_state = CDC_ACM_DEVICE_STATE_READ; + break; + } + break; + case CDC_ACM_DEVICE_STATE_ZLP: + if (cdc_acm_slave == UX_NULL) + { + cdc_acm_device_state = UX_STATE_RESET; + break; + } + status = ux_device_class_cdc_acm_write_run(cdc_acm_slave, + device_buffer, 0, &actual_length); + if (status < UX_STATE_NEXT) + { + printf("ERROR #%d: ZLP status 0x%x\n", __LINE__, status); + return; + } + if (status == UX_STATE_NEXT) + cdc_acm_device_state = CDC_ACM_DEVICE_STATE_READ; + break; + default: + cdc_acm_device_state = UX_STATE_RESET; + } + + /* Let other threads run. */ + tx_thread_relinquish(); +#else + + if (cdc_acm_slave == UX_NULL) + { + tx_thread_sleep(1); + continue; + } + /* Force reading packet by packet. */ + status = ux_device_class_cdc_acm_read(cdc_acm_slave, device_buffer, + device_read_length, &actual_length); + if (status == UX_SUCCESS) + { + write_length = actual_length; + status = ux_device_class_cdc_acm_write(cdc_acm_slave, device_buffer, + write_length, &actual_length); + } +#endif + } +} diff --git a/test/regression/usbx_standalone_device_cdc_acm_basic_memory_test.c b/test/regression/usbx_standalone_device_cdc_acm_basic_memory_test.c new file mode 100644 index 00000000..2c12d121 --- /dev/null +++ b/test/regression/usbx_standalone_device_cdc_acm_basic_memory_test.c @@ -0,0 +1,812 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" +#include "ux_host_class_cdc_acm.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static TX_THREAD ux_test_thread_host_simulation; +static TX_THREAD ux_test_thread_slave_simulation; +static void ux_test_thread_host_simulation_entry(ULONG); +static void ux_test_thread_slave_simulation_entry(ULONG); + +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +static UCHAR cdc_acm_slave_change; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_cdc_sem_usage; +static ULONG rsc_cdc_sem_get_count; +static ULONG rsc_cdc_mutex_usage; +static ULONG rsc_cdc_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +/* Define device framework. */ + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 93 +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 103 +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Configuration 1 descriptor 9 bytes */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Endpoint 0x83 descriptor 7 bytes */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, /* @ 93 - 14 + 2 = 81 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, /* @ 93 - 7 + 2 = 88 */ + 0x02, + 0x40, 0x00, + 0x00, + +}; + +#define DEVICE_FRAMEWORK_EPA_POS_1_FS (DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 14 + 2) +#define DEVICE_FRAMEWORK_EPA_POS_2_FS (DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 7 + 2) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor */ + 0x05, 0x24, 0x06, + 0x00, + 0x01, + + /* Call Management Functional Descriptor */ + 0x05, 0x24, 0x01, + 0x00, + 0x01, + + /* Endpoint 0x83 descriptor */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor */ + 0x07, 0x05, 0x02, /* @ 103 - 14 + 2 = 91 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor */ + 0x07, 0x05, 0x81, /* @ 103 - 7 + 2 = 98 */ + 0x02, + 0x40, 0x00, + 0x00, + +}; + +#define DEVICE_FRAMEWORK_EPA_POS_1_HS (DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 14 + 2) +#define DEVICE_FRAMEWORK_EPA_POS_2_HS (DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 7 + 2) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 + }; + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +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; +} + +static UINT demo_class_cdc_acm_get(void) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_CDC_ACM *cdc_acm_host; + + + /* Find the main cdc_acm container */ + status = ux_host_stack_class_get(_ux_system_host_class_cdc_acm_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* We get the first instance of the cdc_acm device */ + do + { + + status = ux_host_stack_class_instance_get(class, 0, (void **) &cdc_acm_host); + tx_thread_sleep(10); + } while (status != UX_SUCCESS); + + /* We still need to wait for the cdc_acm status to be live */ + while (cdc_acm_host -> ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + tx_thread_sleep(10); + + /* Isolate both the control and data interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_DATA_CLASS) + { + /* This is the data interface. */ + cdc_acm_host_data = cdc_acm_host; + + /* In that case, the second one should be the control interface. */ + status = ux_host_stack_class_instance_get(class, 1, (void **) &cdc_acm_host); + + /* Check error. */ + if (status != UX_SUCCESS) + return(status); + + /* Check for the control interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + + /* This is the control interface. */ + cdc_acm_host_control = cdc_acm_host; + + return(UX_SUCCESS); + + } + } + else + { + /* Check for the control interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + + /* This is the control interface. */ + cdc_acm_host_control = cdc_acm_host; + + /* In that case, the second one should be the data interface. */ + status = ux_host_stack_class_instance_get(class, 1, (void **) &cdc_acm_host); + + /* Check error. */ + if (status != UX_SUCCESS) + return(status); + + /* Check for the data interface. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_DATA_CLASS) + { + + /* This is the data interface. */ + cdc_acm_host_data = cdc_acm_host; + + return(UX_SUCCESS); + + } + } + } + + /* Return ERROR. */ + return(UX_ERROR); +} + +static UINT demo_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; +} + +static VOID test_swap_framework_bulk_ep_descriptors(VOID) +{ +UCHAR tmp; + + tmp = device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_1_FS]; + device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_1_FS] = device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_2_FS]; + device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_2_FS] = tmp; + + tmp = device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_1_HS]; + device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_1_HS] = device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_2_HS]; + device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_2_HS] = tmp; +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *_params) +{ + + set_cfg_counter ++; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_sem_get_on_set_cfg = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_standalone_device_cdc_acm_basic_memory_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + /* Inform user. */ + printf("Running STANDALONE CDC ACM Basic Memory Test........................ "); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* 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 #1\n"); + 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(demo_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #2\n"); + test_control_return(1); + } + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_entry); + if (status != UX_SUCCESS) + { + + printf("ERROR #3\n"); + 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 #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + + if(status!=UX_SUCCESS) + { + + printf("ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #7\n"); + 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 #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_host_simulation, "tx demo host simulation", ux_test_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 #8\n"); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&ux_test_thread_slave_simulation, "tx demo slave simulation", ux_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #9\n"); + test_control_return(1); + } +} + +void ux_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_SLAVE_CLASS_CDC_ACM * cdc_acm_slave_bak; +UX_HOST_CLASS_CDC_ACM * cdc_acm_host_ctrl_bak; +UX_HOST_CLASS_CDC_ACM * cdc_acm_host_data_bak; +ULONG test_n; +ULONG mem_free; +ULONG retry; + + stepinfo("\n"); + + /* Find the cdc_acm class and wait for the link to be up. */ + status = demo_class_cdc_acm_get(); + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #10\n"); + test_control_return(1); + } + + /* Save slave instance for later tests. */ + cdc_acm_slave_bak = cdc_acm_slave; + /* Save host instances for later tests. */ + cdc_acm_host_ctrl_bak = cdc_acm_host_control; + cdc_acm_host_data_bak = cdc_acm_host_data; + + /* Test disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_count_reset(); + ux_test_utility_sim_mutex_create_count_reset(); + ux_test_utility_sim_sem_create_count_reset(); + ux_test_utility_sim_sem_get_count_reset(); + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + + /* Save free memory usage. */ + mem_free = _ux_system->ux_system_regular_memory_pool_free; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + for (retry = 0; (retry < 10) && (cdc_acm_host_control == UX_NULL || cdc_acm_host_data == UX_NULL); retry ++) + tx_thread_sleep(10); + + /* Log create counts for further tests. */ + rsc_enum_mutex_usage = rsc_mutex_on_set_cfg; + rsc_enum_sem_usage = rsc_sem_on_set_cfg; + rsc_enum_mem_alloc_count = rsc_mem_alloc_cnt_on_set_cfg; + /* Log create counts when instances active for further tests. */ + rsc_cdc_mutex_usage = ux_test_utility_sim_mutex_create_count() - rsc_enum_mutex_usage; + rsc_cdc_sem_usage = ux_test_utility_sim_sem_create_count() - rsc_enum_sem_usage; + rsc_cdc_mem_alloc_count = ux_test_utility_sim_mem_alloc_count() - rsc_enum_mem_alloc_count; + + /* Lock log base for tests. */ + ux_test_utility_sim_mem_alloc_log_lock(); + + stepinfo("enum mem: %ld\n", rsc_enum_mem_alloc_count); + stepinfo("cdc mem : %ld\n", rsc_cdc_mem_alloc_count); + stepinfo("mem free: %ld, %ld\n", _ux_system->ux_system_regular_memory_pool_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available); + + /* Simulate detach and attach for FS enumeration, + and check if there is memory error in normal enumeration. + */ + stepinfo(">>>>>>>>>>>> Enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < 3; test_n++) + { + stepinfo("%4ld / 2\n", test_n); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system->ux_system_regular_memory_pool_free; + else if (mem_free != _ux_system->ux_system_regular_memory_pool_free) + { + + printf("ERROR #11.%ld: Memory level different after re-enumerations %ld <> %ld\n", test_n, mem_free, _ux_system->ux_system_regular_memory_pool_free); + test_control_return(1); + } + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on error. */ + ux_test_breakable_sleep(100, sleep_break_on_error); + + /* Check */ + if (!cdc_acm_host_control || !cdc_acm_host_data) + { + + printf("ERROR #12.%ld: Enumeration fail\n", test_n); + test_control_return(1); + } + } + + /* Simulate detach and attach for FS enumeration, + and test possible memory allocation error handlings. + */ + if (rsc_cdc_mem_alloc_count) stepinfo(">>>>>>>>>>>> Memory errors enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_cdc_mem_alloc_count; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_cdc_mem_alloc_count - 1); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system->ux_system_regular_memory_pool_free; + else if (mem_free != _ux_system->ux_system_regular_memory_pool_free) + { + + printf("ERROR #11.%ld: Memory level different after re-enumerations %ld <> %ld\n", test_n, mem_free, _ux_system->ux_system_regular_memory_pool_free); + test_control_return(1); + } + + /* Set memory error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n + rsc_enum_mem_alloc_count); + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on errors. */ + ux_test_breakable_sleep(100, sleep_break_on_error); + + /* Check error */ + if (cdc_acm_host_control && cdc_acm_host_data) + { + + printf("ERROR #12.%ld: device detected when there is memory error\n", test_n); + test_control_return(1); + } + stepinfo("mem free: %ld\n", _ux_system->ux_system_regular_memory_pool_free); + } + ux_test_utility_sim_mem_alloc_error_generation_stop(); + if (rsc_cdc_mem_alloc_count) stepinfo("\n"); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_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 ux_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Keep running device stack tasks. */ + ux_system_tasks_run(); + tx_thread_relinquish(); + } +} diff --git a/test/regression/usbx_standalone_device_cdc_acm_basic_test.c b/test/regression/usbx_standalone_device_cdc_acm_basic_test.c new file mode 100644 index 00000000..a2441223 --- /dev/null +++ b/test/regression/usbx_standalone_device_cdc_acm_basic_test.c @@ -0,0 +1,1003 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" +#include "ux_host_class_cdc_acm.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static TX_THREAD ux_test_thread_host_simulation; +static TX_THREAD ux_test_thread_slave_simulation; +static void ux_test_thread_host_simulation_entry(ULONG); +static void ux_test_thread_slave_simulation_entry(ULONG); + +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; +static UX_HOST_CLASS_CDC_ACM_RECEPTION cdc_acm_host_reception; +static UCHAR cdc_acm_host_reception_buffer[UX_DEMO_RECEPTION_BUFFER_SIZE]; +static UINT cdc_acm_host_reception_status = 0; +static ULONG cdc_acm_host_reception_count = 0; +static UCHAR cdc_acm_host_read_buffer[UX_SLAVE_REQUEST_DATA_MAX_LENGTH * 2]; +static ULONG cdc_acm_host_read_buffer_length; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; +static UCHAR cdc_acm_slave_change; +static UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_PARAMETER cdc_acm_slave_line_coding; +static UX_SLAVE_CLASS_CDC_ACM_LINE_STATE_PARAMETER cdc_acm_slave_line_state; +static ULONG device_read_length = UX_SLAVE_REQUEST_DATA_MAX_LENGTH; +static UCHAR device_buffer[UX_SLAVE_REQUEST_DATA_MAX_LENGTH * 2]; + +static UCHAR host_buffer[UX_SLAVE_REQUEST_DATA_MAX_LENGTH * 2]; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_cdc_sem_usage; +static ULONG rsc_cdc_sem_get_count; +static ULONG rsc_cdc_mutex_usage; +static ULONG rsc_cdc_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +/* Define device framework. */ + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 93 +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 103 +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Configuration 1 descriptor 9 bytes */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Endpoint 0x83 descriptor 7 bytes */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, /* @ 93 - 14 + 2 = 81 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, /* @ 93 - 7 + 2 = 88 */ + 0x02, + 0x40, 0x00, + 0x00, + +}; + +#define DEVICE_FRAMEWORK_EPA_POS_1_FS (DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 14 + 2) +#define DEVICE_FRAMEWORK_EPA_POS_2_FS (DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 7 + 2) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor */ + 0x05, 0x24, 0x06, + 0x00, + 0x01, + + /* Call Management Functional Descriptor */ + 0x05, 0x24, 0x01, + 0x00, + 0x01, + + /* Endpoint 0x83 descriptor */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor */ + 0x07, 0x05, 0x02, /* @ 103 - 14 + 2 = 91 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor */ + 0x07, 0x05, 0x81, /* @ 103 - 7 + 2 = 98 */ + 0x02, + 0x40, 0x00, + 0x00, + +}; + +#define DEVICE_FRAMEWORK_EPA_POS_1_HS (DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 14 + 2) +#define DEVICE_FRAMEWORK_EPA_POS_2_HS (DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 7 + 2) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 + }; + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +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; +} + +static UINT demo_class_cdc_acm_get(void) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_CDC_ACM *cdc_acm_host; + + + /* Find the main cdc_acm container */ + status = ux_host_stack_class_get(_ux_system_host_class_cdc_acm_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* We get the first instance of the cdc_acm device */ + do + { + + status = ux_host_stack_class_instance_get(class, 0, (void **) &cdc_acm_host); + tx_thread_sleep(10); + } while (status != UX_SUCCESS); + + /* We still need to wait for the cdc_acm status to be live */ + while (cdc_acm_host -> ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + tx_thread_sleep(10); + + /* Isolate both the control and data interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_DATA_CLASS) + { + /* This is the data interface. */ + cdc_acm_host_data = cdc_acm_host; + + /* In that case, the second one should be the control interface. */ + status = ux_host_stack_class_instance_get(class, 1, (void **) &cdc_acm_host); + + /* Check error. */ + if (status != UX_SUCCESS) + return(status); + + /* Check for the control interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + + /* This is the control interface. */ + cdc_acm_host_control = cdc_acm_host; + + return(UX_SUCCESS); + + } + } + else + { + /* Check for the control interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + + /* This is the control interface. */ + cdc_acm_host_control = cdc_acm_host; + + /* In that case, the second one should be the data interface. */ + status = ux_host_stack_class_instance_get(class, 1, (void **) &cdc_acm_host); + + /* Check error. */ + if (status != UX_SUCCESS) + return(status); + + /* Check for the data interface. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_DATA_CLASS) + { + + /* This is the data interface. */ + cdc_acm_host_data = cdc_acm_host; + + return(UX_SUCCESS); + + } + } + } + + /* Return ERROR. */ + return(UX_ERROR); +} + +static UINT demo_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; + + /* Get new paramster. */ + ux_device_class_cdc_acm_ioctl(cdc_acm_slave, + UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING, + (VOID*)&cdc_acm_slave_line_coding); + ux_device_class_cdc_acm_ioctl(cdc_acm_slave, + UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING, + (VOID*)&cdc_acm_slave_line_state); +} + +static VOID test_swap_framework_bulk_ep_descriptors(VOID) +{ +UCHAR tmp; + + tmp = device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_1_FS]; + device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_1_FS] = device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_2_FS]; + device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_2_FS] = tmp; + + tmp = device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_1_HS]; + device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_1_HS] = device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_2_HS]; + device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_2_HS] = tmp; +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *_params) +{ + + set_cfg_counter ++; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_sem_get_on_set_cfg = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_standalone_device_cdc_acm_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + /* Inform user. */ + printf("Running STANDALONE CDC ACM Basic Test............................... "); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* 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 #1\n"); + 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(demo_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #2\n"); + test_control_return(1); + } + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_entry); + if (status != UX_SUCCESS) + { + + printf("ERROR #3\n"); + 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 #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + + if(status!=UX_SUCCESS) + { + + printf("ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #7\n"); + 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 #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_host_simulation, "tx demo host simulation", ux_test_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 #8\n"); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&ux_test_thread_slave_simulation, "tx demo slave simulation", ux_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #9\n"); + test_control_return(1); + } +} + +static void test_cdc_acm_device_ioctl_parameters(void) +{ +UINT status; + if (cdc_acm_slave == UX_NULL) + { + printf("ERROR #%d, device instance not ready\n", __LINE__); + test_control_return(1); + } + + /* Get and check default line coding. */ + ux_utility_memory_set(&cdc_acm_slave_line_coding, 0, sizeof(cdc_acm_slave_line_coding)); + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, + UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING, + (VOID*)&cdc_acm_slave_line_coding); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_baudrate == + UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_RATE); + UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_stop_bit == + UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_STOP_BIT); + UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_parity == + UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_PARITY); + UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_data_bit == + UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_DATA_BIT); + + /* Set new line coding, read back to test. */ + cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_baudrate ++; + cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_stop_bit ++; + cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_parity ++; + cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_data_bit ++; + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, + UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_CODING, + (VOID*)&cdc_acm_slave_line_coding); + UX_TEST_ASSERT(status == UX_SUCCESS); + + ux_utility_memory_set(&cdc_acm_slave_line_coding, 0, sizeof(cdc_acm_slave_line_coding)); + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, + UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING, + (VOID*)&cdc_acm_slave_line_coding); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_baudrate == + UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_RATE + 1); + UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_stop_bit == + UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_STOP_BIT + 1); + UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_parity == + UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_PARITY + 1); + UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_data_bit == + UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_DATA_BIT + 1); + + /* Set line coding back. */ + cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_baudrate --; + cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_stop_bit --; + cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_parity --; + cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_data_bit --; + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, + UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_CODING, + (VOID*)&cdc_acm_slave_line_coding); + UX_TEST_ASSERT(status == UX_SUCCESS); + + /* Get and check line state. */ + ux_utility_memory_set(&cdc_acm_slave_line_state, 0, sizeof(cdc_acm_slave_line_state)); + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, + UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_STATE, + (VOID*)&cdc_acm_slave_line_state); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_dtr == 1); + UX_TEST_ASSERT(cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_rts == 1); + + /* Set new line state, read back to test. */ + cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_dtr ++; + cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_rts ++; + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, + UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_STATE, + (VOID*)&cdc_acm_slave_line_state); + UX_TEST_ASSERT(status == UX_SUCCESS); + + ux_utility_memory_set(&cdc_acm_slave_line_state, 0, sizeof(cdc_acm_slave_line_state)); + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, + UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_STATE, + (VOID*)&cdc_acm_slave_line_state); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_dtr == 2); + UX_TEST_ASSERT(cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_rts == 2); + + /* Set line state back. */ + cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_dtr --; + cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_rts --; + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, + UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_STATE, + (VOID*)&cdc_acm_slave_line_state); + UX_TEST_ASSERT(status == UX_SUCCESS); +} + + +static void test_thread_host_reception_callback(UX_HOST_CLASS_CDC_ACM *cdc_acm, UINT status, UCHAR *reception_buffer, ULONG reception_size) +{ +ULONG i; + + /* And move to the next reception buffer. Check if we are at the end of the application buffer. */ + if (cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_tail + + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_block_size >= + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_buffer + + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_buffer_size) + + /* We are at the end of the buffer. Move back to the beginning. */ + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_tail = + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_buffer; + + else + + /* Program the tail to be after the current buffer. */ + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_tail += + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_block_size; + + cdc_acm_host_reception_status = status; + cdc_acm_host_reception_count ++; + + /* Save buffer. */ + for (i = 0; + (i < reception_size) && + (cdc_acm_host_read_buffer_length < sizeof(cdc_acm_host_read_buffer)); + i ++, cdc_acm_host_read_buffer_length ++) + { + cdc_acm_host_read_buffer[cdc_acm_host_read_buffer_length] = reception_buffer[i]; + } + + return; +} + +static void test_cdc_acm_device_read_write(void) +{ +UINT status; +ULONG actual_length; +UCHAR test_chr; +ULONG test_length; +ULONG i, test; +#define N_TEST 6 +struct { + UCHAR chr; + ULONG len; +} tests[N_TEST] = { + {'$', 1}, {'A', 64}, {'N', 65}, + {'3', UX_SLAVE_REQUEST_DATA_MAX_LENGTH - 64}, + {'G', UX_SLAVE_REQUEST_DATA_MAX_LENGTH}, + {'H', UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1}, +}; + + /* Reception parameter */ + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_block_size = UX_DEMO_RECEPTION_BLOCK_SIZE; + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_buffer = cdc_acm_host_reception_buffer; + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_buffer_size = UX_DEMO_RECEPTION_BUFFER_SIZE; + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_callback = test_thread_host_reception_callback; + + /* Start reception. */ + status = ux_host_class_cdc_acm_reception_start(cdc_acm_host_data, &cdc_acm_host_reception); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: reception start fail %x\n", __LINE__, status); + test_control_return(1); + } + + for (test = 0; test < N_TEST; test ++) + { + test_chr = tests[test].chr; + test_length = tests[test].len; + + for (i = 0; i < test_length; i ++) + { + host_buffer[i] = test_chr; + cdc_acm_host_read_buffer[i] = ~test_chr; + } + cdc_acm_host_read_buffer_length = 0; + + status = ux_host_class_cdc_acm_write(cdc_acm_host_data, host_buffer, + test_length, &actual_length); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "test_length %ld\n", test_length); + if ((test_length & 63) == 0) + { + status = ux_host_class_cdc_acm_write(cdc_acm_host_data, host_buffer, + 0, &actual_length); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "test_length %ld\n", test_length); + } + /* Wait a while for background reception. */ + tx_thread_sleep(test_length/64 + 1); + + UX_TEST_ASSERT_MESSAGE(cdc_acm_host_reception_status == UX_SUCCESS, "test_length %ld\n", test_length); + if (cdc_acm_host_read_buffer_length != test_length) + { + printf("ERROR #%d, length not match %ld <> %ld\n", __LINE__, + test_length, cdc_acm_host_read_buffer_length); + test_control_return(1); + } + for (i = 0; i < test_length; i ++) + { + UX_TEST_ASSERT_MESSAGE(cdc_acm_host_read_buffer[i] == test_chr, "test_length %ld\n", test_length); + } + } + + /* Stop reception. */ + ux_host_class_cdc_acm_reception_stop(cdc_acm_host_data, &cdc_acm_host_reception); +} + +void ux_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; + + stepinfo("\n"); + + /* Find the cdc_acm class and wait for the link to be up. */ + status = demo_class_cdc_acm_get(); + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #10\n"); + test_control_return(1); + } + + test_cdc_acm_device_ioctl_parameters(); + test_cdc_acm_device_read_write(); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_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 ux_test_thread_slave_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG actual_length; +ULONG read_length = device_read_length; +ULONG write_length, write_zlp = UX_FALSE; +#define CDC_ACM_DEVICE_STATE_READ UX_STATE_STEP +#define CDC_ACM_DEVICE_STATE_WRITE UX_STATE_STEP + 1 +#define CDC_ACM_DEVICE_STATE_ZLP UX_STATE_STEP + 2 +UINT cdc_acm_device_state = UX_STATE_RESET; + + while(1) + { + + /* Keep running device stack tasks. */ + ux_system_tasks_run(); + + /* Reset state if read length changed. */ + if (read_length != device_read_length) + { + cdc_acm_device_state = UX_STATE_RESET; + read_length = device_read_length; + } + + /* CDC ACM echo state machine. */ + switch(cdc_acm_device_state) + { + case UX_STATE_RESET: + if (cdc_acm_slave != UX_NULL) + { + ux_device_class_cdc_acm_ioctl(cdc_acm_slave, + UX_SLAVE_CLASS_CDC_ACM_IOCTL_ABORT_PIPE, + (VOID*)UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_XMIT); + ux_device_class_cdc_acm_ioctl(cdc_acm_slave, + UX_SLAVE_CLASS_CDC_ACM_IOCTL_ABORT_PIPE, + (VOID*)UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_RCV); + cdc_acm_device_state = CDC_ACM_DEVICE_STATE_READ; + } + break; + case CDC_ACM_DEVICE_STATE_READ: + if (cdc_acm_slave == UX_NULL) + { + cdc_acm_device_state = UX_STATE_RESET; + break; + } + status = ux_device_class_cdc_acm_read_run(cdc_acm_slave, + device_buffer, device_read_length, &actual_length); + if (status < UX_STATE_NEXT) + { + printf("ERROR #%d: read status 0x%x\n", __LINE__, status); + return; + } + if (status == UX_STATE_NEXT) + { + write_length = actual_length; + if ((actual_length < device_read_length) && + ((actual_length & 63) == 0)) + { + write_zlp = UX_TRUE; + } + cdc_acm_device_state = CDC_ACM_DEVICE_STATE_WRITE; + } + break; + case CDC_ACM_DEVICE_STATE_WRITE: + if (cdc_acm_slave == UX_NULL) + { + cdc_acm_device_state = UX_STATE_RESET; + break; + } + status = ux_device_class_cdc_acm_write_run(cdc_acm_slave, + device_buffer, write_length, &actual_length); + if (status < UX_STATE_NEXT) + { + printf("ERROR #%d: write status 0x%x\n", __LINE__, status); + return; + } + if (status == UX_STATE_NEXT) + { + if (write_zlp && ((write_length % 64) == 0)) + { + cdc_acm_device_state = CDC_ACM_DEVICE_STATE_ZLP; + break; + } + cdc_acm_device_state = CDC_ACM_DEVICE_STATE_READ; + break; + } + case CDC_ACM_DEVICE_STATE_ZLP: + if (cdc_acm_slave == UX_NULL) + { + cdc_acm_device_state = UX_STATE_RESET; + break; + } + status = ux_device_class_cdc_acm_write_run(cdc_acm_slave, + device_buffer, 0, &actual_length); + if (status < UX_STATE_NEXT) + { + printf("ERROR #%d: ZLP status 0x%x\n", __LINE__, status); + return; + } + if (status == UX_STATE_NEXT) + cdc_acm_device_state = CDC_ACM_DEVICE_STATE_READ; + break; + default: + cdc_acm_device_state = UX_STATE_RESET; + } + + /* Let other threads run. */ + tx_thread_relinquish(); + } +} diff --git a/test/regression/usbx_standalone_device_cdc_acm_transmission_test.c b/test/regression/usbx_standalone_device_cdc_acm_transmission_test.c new file mode 100644 index 00000000..966c686e --- /dev/null +++ b/test/regression/usbx_standalone_device_cdc_acm_transmission_test.c @@ -0,0 +1,898 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" +#include "ux_host_class_cdc_acm.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static TX_THREAD ux_test_thread_host_simulation; +static TX_THREAD ux_test_thread_slave_simulation; +static void ux_test_thread_host_simulation_entry(ULONG); +static void ux_test_thread_slave_simulation_entry(ULONG); + +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; +static UX_HOST_CLASS_CDC_ACM_RECEPTION cdc_acm_host_reception; +static UCHAR cdc_acm_host_reception_buffer[UX_DEMO_RECEPTION_BUFFER_SIZE]; +static UINT cdc_acm_host_reception_status = 0; +static ULONG cdc_acm_host_reception_count = 0; +static UCHAR cdc_acm_host_read_buffer[UX_SLAVE_REQUEST_DATA_MAX_LENGTH * 2]; +static ULONG cdc_acm_host_read_buffer_length; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; +static UCHAR cdc_acm_slave_change; +static UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_PARAMETER cdc_acm_slave_line_coding; +static UX_SLAVE_CLASS_CDC_ACM_LINE_STATE_PARAMETER cdc_acm_slave_line_state; +static ULONG device_read_length = UX_SLAVE_REQUEST_DATA_MAX_LENGTH; +static UCHAR device_buffer[UX_SLAVE_REQUEST_DATA_MAX_LENGTH * 2]; +static UX_SLAVE_CLASS_CDC_ACM_CALLBACK_PARAMETER cdc_acm_slave_callback; + +static UCHAR host_buffer[UX_SLAVE_REQUEST_DATA_MAX_LENGTH * 2]; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_cdc_sem_usage; +static ULONG rsc_cdc_sem_get_count; +static ULONG rsc_cdc_mutex_usage; +static ULONG rsc_cdc_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +/* Define device framework. */ + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 93 +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 103 +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Configuration 1 descriptor 9 bytes */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Endpoint 0x83 descriptor 7 bytes */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, /* @ 93 - 14 + 2 = 81 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, /* @ 93 - 7 + 2 = 88 */ + 0x02, + 0x40, 0x00, + 0x00, + +}; + +#define DEVICE_FRAMEWORK_EPA_POS_1_FS (DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 14 + 2) +#define DEVICE_FRAMEWORK_EPA_POS_2_FS (DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 7 + 2) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor */ + 0x05, 0x24, 0x06, + 0x00, + 0x01, + + /* Call Management Functional Descriptor */ + 0x05, 0x24, 0x01, + 0x00, + 0x01, + + /* Endpoint 0x83 descriptor */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor */ + 0x07, 0x05, 0x02, /* @ 103 - 14 + 2 = 91 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor */ + 0x07, 0x05, 0x81, /* @ 103 - 7 + 2 = 98 */ + 0x02, + 0x40, 0x00, + 0x00, + +}; + +#define DEVICE_FRAMEWORK_EPA_POS_1_HS (DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 14 + 2) +#define DEVICE_FRAMEWORK_EPA_POS_2_HS (DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 7 + 2) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 + }; + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +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; +} + +static UINT demo_class_cdc_acm_get(void) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_CDC_ACM *cdc_acm_host; + + + /* Find the main cdc_acm container */ + status = ux_host_stack_class_get(_ux_system_host_class_cdc_acm_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* We get the first instance of the cdc_acm device */ + do + { + + status = ux_host_stack_class_instance_get(class, 0, (void **) &cdc_acm_host); + tx_thread_sleep(10); + } while (status != UX_SUCCESS); + + /* We still need to wait for the cdc_acm status to be live */ + while (cdc_acm_host -> ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + tx_thread_sleep(10); + + /* Isolate both the control and data interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_DATA_CLASS) + { + /* This is the data interface. */ + cdc_acm_host_data = cdc_acm_host; + + /* In that case, the second one should be the control interface. */ + status = ux_host_stack_class_instance_get(class, 1, (void **) &cdc_acm_host); + + /* Check error. */ + if (status != UX_SUCCESS) + return(status); + + /* Check for the control interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + + /* This is the control interface. */ + cdc_acm_host_control = cdc_acm_host; + + return(UX_SUCCESS); + + } + } + else + { + /* Check for the control interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + + /* This is the control interface. */ + cdc_acm_host_control = cdc_acm_host; + + /* In that case, the second one should be the data interface. */ + status = ux_host_stack_class_instance_get(class, 1, (void **) &cdc_acm_host); + + /* Check error. */ + if (status != UX_SUCCESS) + return(status); + + /* Check for the data interface. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_DATA_CLASS) + { + + /* This is the data interface. */ + cdc_acm_host_data = cdc_acm_host; + + return(UX_SUCCESS); + + } + } + } + + /* Return ERROR. */ + return(UX_ERROR); +} + +static UINT demo_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; + + /* Get new paramster. */ + ux_device_class_cdc_acm_ioctl(cdc_acm_slave, + UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING, + (VOID*)&cdc_acm_slave_line_coding); + ux_device_class_cdc_acm_ioctl(cdc_acm_slave, + UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING, + (VOID*)&cdc_acm_slave_line_state); +} + +static VOID test_swap_framework_bulk_ep_descriptors(VOID) +{ +UCHAR tmp; + + tmp = device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_1_FS]; + device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_1_FS] = device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_2_FS]; + device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_2_FS] = tmp; + + tmp = device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_1_HS]; + device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_1_HS] = device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_2_HS]; + device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_2_HS] = tmp; +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *_params) +{ + + set_cfg_counter ++; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_sem_get_on_set_cfg = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_standalone_device_cdc_acm_transmission_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + /* Inform user. */ + printf("Running STANDALONE CDC ACM Transmission Test........................ "); +#ifdef UX_DEVICE_CLASS_CDC_ACM_TRANSMISSION_DISABLE + printf("Skipped\n"); + test_control_return(0); + return; +#endif + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* 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 #1\n"); + 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(demo_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #2\n"); + test_control_return(1); + } + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_entry); + if (status != UX_SUCCESS) + { + + printf("ERROR #3\n"); + 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 #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + + if(status!=UX_SUCCESS) + { + + printf("ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #7\n"); + 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 #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_host_simulation, "tx demo host simulation", ux_test_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 #8\n"); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&ux_test_thread_slave_simulation, "tx demo slave simulation", ux_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #9\n"); + test_control_return(1); + } +} + +static void test_thread_host_reception_callback(UX_HOST_CLASS_CDC_ACM *cdc_acm, UINT status, UCHAR *reception_buffer, ULONG reception_size) +{ +ULONG i; + + /* And move to the next reception buffer. Check if we are at the end of the application buffer. */ + if (cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_tail + + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_block_size >= + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_buffer + + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_buffer_size) + + /* We are at the end of the buffer. Move back to the beginning. */ + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_tail = + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_buffer; + + else + + /* Program the tail to be after the current buffer. */ + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_tail += + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_block_size; + + cdc_acm_host_reception_status = status; + cdc_acm_host_reception_count ++; + + /* Save buffer. */ + for (i = 0; + (i < reception_size) && + (cdc_acm_host_read_buffer_length < sizeof(cdc_acm_host_read_buffer)); + i ++, cdc_acm_host_read_buffer_length ++) + { + cdc_acm_host_read_buffer[cdc_acm_host_read_buffer_length] = reception_buffer[i]; + } + + return; +} + +static void test_cdc_acm_device_transmission(void) +{ +UINT status; +ULONG actual_length; +UCHAR test_chr; +ULONG test_length; +ULONG i, test; +#define N_TEST 6 +struct { + UCHAR chr; + ULONG len; +} tests[N_TEST] = { + {'$', 1}, {'A', 64}, {'N', 65}, + {'3', UX_SLAVE_REQUEST_DATA_MAX_LENGTH - 64}, + {'G', UX_SLAVE_REQUEST_DATA_MAX_LENGTH}, + {'H', UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1}, +}; + + /* Reception parameter */ + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_block_size = UX_DEMO_RECEPTION_BLOCK_SIZE; + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_buffer = cdc_acm_host_reception_buffer; + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_buffer_size = UX_DEMO_RECEPTION_BUFFER_SIZE; + cdc_acm_host_reception.ux_host_class_cdc_acm_reception_callback = test_thread_host_reception_callback; + + /* Start reception. */ + status = ux_host_class_cdc_acm_reception_start(cdc_acm_host_data, &cdc_acm_host_reception); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: reception start fail %x\n", __LINE__, status); + test_control_return(1); + } + + for (test = 0; test < N_TEST; test ++) + { + test_chr = tests[test].chr; + test_length = tests[test].len; + + for (i = 0; i < test_length; i ++) + { + host_buffer[i] = test_chr; + cdc_acm_host_read_buffer[i] = ~test_chr; + } + cdc_acm_host_read_buffer_length = 0; + + status = ux_host_class_cdc_acm_write(cdc_acm_host_data, host_buffer, + test_length, &actual_length); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "test_length %ld\n", test_length); + if ((test_length & 63) == 0) + { + status = ux_host_class_cdc_acm_write(cdc_acm_host_data, host_buffer, + 0, &actual_length); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "test_length %ld\n", test_length); + } + /* Wait a while for background reception. */ + tx_thread_sleep(test_length/64 + 10); + + UX_TEST_ASSERT_MESSAGE(cdc_acm_host_reception_status == UX_SUCCESS, "test_length %ld\n", test_length); + if (cdc_acm_host_read_buffer_length != test_length) + { + printf("ERROR #%d, length not match %ld <> %ld\n", __LINE__, + test_length, cdc_acm_host_read_buffer_length); + test_control_return(1); + } + for (i = 0; i < test_length; i ++) + { + UX_TEST_ASSERT_MESSAGE(cdc_acm_host_read_buffer[i] == test_chr, "test_length %ld\n", test_length); + } + } + + /* Stop reception. */ + ux_host_class_cdc_acm_reception_stop(cdc_acm_host_data, &cdc_acm_host_reception); +} + +void ux_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; + + stepinfo("\n"); + + /* Find the cdc_acm class and wait for the link to be up. */ + status = demo_class_cdc_acm_get(); + if (status != UX_SUCCESS) + { + + /* CDC ACM basic test error. */ + printf("ERROR #10\n"); + test_control_return(1); + } + + test_cdc_acm_device_transmission(); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_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); + +} + +#define TEST_N_BUFFER 64 +static UCHAR test_cdc_acm_device_fifo[TEST_N_BUFFER][64]; +static ULONG test_cdc_acm_device_fifo_length[TEST_N_BUFFER]; +static ULONG test_cdc_acm_device_fifo_read_count; +static ULONG test_cdc_acm_device_fifo_write_count; +static UINT test_cdc_acm_device_fifo_read_status; +static UINT test_cdc_acm_device_fifo_write_status; +static UINT test_cdc_acm_device_write_callback( + struct UX_SLAVE_CLASS_CDC_ACM_STRUCT *cdc_acm, + UINT status, ULONG length) +{ +UINT fifo_index; + test_cdc_acm_device_fifo_write_status = status; + test_cdc_acm_device_fifo_write_count ++; + if (test_cdc_acm_device_fifo_write_count >= test_cdc_acm_device_fifo_read_count) + return(0); + + fifo_index = test_cdc_acm_device_fifo_write_count % TEST_N_BUFFER; + status = ux_device_class_cdc_acm_write_with_callback(cdc_acm_slave, + test_cdc_acm_device_fifo[fifo_index], + test_cdc_acm_device_fifo_length[fifo_index]); + if (status != UX_SUCCESS) + { + printf("ERROR #%d write fail %x\n", __LINE__, status); + test_control_return(1); + } + return(0); +} +static UINT test_cdc_acm_device_read_callback( + struct UX_SLAVE_CLASS_CDC_ACM_STRUCT *cdc_acm, + UINT status, UCHAR *data_pointer, ULONG length) +{ +UINT fifo_index = test_cdc_acm_device_fifo_read_count % TEST_N_BUFFER; +UINT start = test_cdc_acm_device_fifo_read_count == test_cdc_acm_device_fifo_write_count; + test_cdc_acm_device_fifo_read_status = status; + if (status != UX_SUCCESS) + return(0); + if (test_cdc_acm_device_fifo_read_count - test_cdc_acm_device_fifo_write_count > TEST_N_BUFFER) + { + printf("ERROR #%d fifo (%d) overflow\n", __LINE__, TEST_N_BUFFER); + return(0); + } + + test_cdc_acm_device_fifo_read_count ++; + ux_utility_memory_copy(test_cdc_acm_device_fifo[fifo_index], data_pointer, length); + test_cdc_acm_device_fifo_length[fifo_index] = length; + if (!start) + return(0); + + /* Try write. */ + fifo_index = test_cdc_acm_device_fifo_write_count % TEST_N_BUFFER; + ux_device_class_cdc_acm_write_with_callback(cdc_acm_slave, + test_cdc_acm_device_fifo[fifo_index], + test_cdc_acm_device_fifo_length[fifo_index]); + return(0); +} + + +void ux_test_thread_slave_simulation_entry(ULONG arg) +{ + +UINT status; +UX_SLAVE_CLASS_CDC_ACM *cdc_acm = UX_NULL; + + cdc_acm_slave_callback.ux_device_class_cdc_acm_parameter_read_callback = test_cdc_acm_device_read_callback; + cdc_acm_slave_callback.ux_device_class_cdc_acm_parameter_write_callback = test_cdc_acm_device_write_callback; + + while(1) + { + + /* Keep running device stack tasks. */ + ux_system_tasks_run(); + + if (cdc_acm != cdc_acm_slave && cdc_acm_slave) + { + cdc_acm = cdc_acm_slave; + + /* Start transmission. */ + test_cdc_acm_device_fifo_read_count = 0; + test_cdc_acm_device_fifo_write_count = 0; + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, + UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START, + (VOID*)&cdc_acm_slave_callback); + if (status != UX_SUCCESS) + { + printf("ERROR %d transmission start fail %x\n", __LINE__, status); + test_control_return(1); + } + } + + /* Let other threads run. */ + tx_thread_relinquish(); + } +} diff --git a/test/regression/usbx_standalone_device_storage_basic_test.c b/test/regression/usbx_standalone_device_storage_basic_test.c new file mode 100644 index 00000000..660bae25 --- /dev/null +++ b/test/regression/usbx_standalone_device_storage_basic_test.c @@ -0,0 +1,2964 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_stack.h" +#include "ux_device_class_storage.h" + +#include "ux_host_stack.h" +#include "ux_host_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#define _storage_media_is_mounted() (global_storage_media->ux_host_class_storage_media_status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED) +#if defined(UX_HOST_CLASS_STORAGE_NO_FILEX) +FX_MEDIA *_ux_host_class_storage_driver_media(INT i); +VOID _ux_host_class_storage_driver_entry(FX_MEDIA *media); +VOID _ux_host_class_storage_media_insert(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG format_open); +VOID _ux_host_class_storage_media_remove(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +INT _ux_host_class_storage_media_index(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +FX_MEDIA *_ux_host_class_storage_media_fx_media(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +UCHAR *_ux_host_class_storage_media_fx_media_memory(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); + +#endif + +/* Define constants. */ +#define UX_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 3) + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ +VOID _fx_ram_driver(FX_MEDIA *media_ptr); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_device_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); +static void tx_demo_thread_device_simulation_entry(ULONG); + +static UINT ux_test_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst); + +static UINT demo_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +static FX_MEDIA *media; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk1; +static FX_MEDIA ram_disk2; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static UCHAR buffer1[512]; +static UCHAR buffer2[512]; + +static FX_MEDIA *ram_disks[] = {&ram_disk1, &ram_disk2}; +static UCHAR *buffers[] = {buffer1, buffer2}; +static CHAR *ram_disk_memory[] = { ram_disk_memory1, ram_disk_memory2 }; + +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static ULONG ram_disk_rw_fail_mode = 0; /* 1: BulkIN, 2: BulkOUT, 0: DISK. 0x80: once */ +#define ram_disk_rw_fail_mode_bulk_in() ((ram_disk_rw_fail_mode & 0x7F) == 1) +#define ram_disk_rw_fail_mode_bulk_out() ((ram_disk_rw_fail_mode & 0x7F) == 2) +#define ram_disk_rw_fail_mode_disk() ((ram_disk_rw_fail_mode & 0x7F) == 0) +#define ram_disk_rw_fail_mode_one_shot() ((ram_disk_rw_fail_mode & 0x80) > 0) +static ULONG ram_disk_rw_fail_after = 0xFFFFFFFFu; +static ULONG ram_disk_rw_count = 0; +static ULONG ram_disk_rw_wait_delay = 0; +static ULONG ram_disk_rw_wait_start = 0; +static UCHAR ram_disk_rw_wait_state = 0;/* 0: idle, 1: wait */ + +static CHAR ram_disk_flush = 0; +static UINT ram_disk_flush_status = UX_STATE_NEXT; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00 + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x02, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x02, 0x00 + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + + +static UX_TEST_HCD_SIM_ACTION fail_on_bulkin[] = { +/* 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_DCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x81, UX_NULL, 0, UX_ERROR, + UX_STATE_ERROR, UX_NULL, + UX_FALSE}, /* Invoke callback & no continue */ +{ 0 } +}; + + +static UX_TEST_HCD_SIM_ACTION fail_on_bulkout[] = { +/* 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_DCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_ERROR, + UX_STATE_ERROR, UX_NULL, + UX_FALSE}, /* Invoke callback & no continue */ +{ 0 } +}; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + storage_media = UX_NULL; + media = UX_NULL; +#endif + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + tx_thread_sleep(UX_MS_TO_TICK_NON_ZERO(10)); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *) class -> ux_host_class_media; + media = &storage_media -> ux_host_class_storage_media; +#endif + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_ext != UX_NULL && + class -> ux_host_class_media != UX_NULL) + { + return(UX_SUCCESS); + } + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + +static UINT sleep_break_on_connect(VOID) +{ + if (host_storage_instance_get(0) == UX_SUCCESS) + return(1); + if (error_callback_counter >= 3) + return(1); + return(0); +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *_params) +{ + + set_cfg_counter ++; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_sem_get_on_set_cfg = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_device_storage_basic_standalone_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +ULONG mem_free; +ULONG test_n; + + + /* Inform user. */ + printf("Running STANDALONE Device Storage Basic Test........................ "); +#ifndef UX_DEVICE_STANDALONE + printf("Skip\n"); + test_control_return(0); +#endif + + stepinfo("\n"); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Format the ram drive. */ + status = fx_media_format(&ram_disk1, _fx_ram_driver, ram_disk_memory1, buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + status |= fx_media_format(&ram_disk2, _fx_ram_driver, ram_disk_memory2, buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + if (status != FX_SUCCESS) + { + + /* Storage basic test error. */ + printf("ERROR #8\n"); + test_control_return(1); + } + + /* Open the ram_disk. */ + status = fx_media_open(&ram_disk1, "RAM DISK1", _fx_ram_driver, ram_disk_memory1, buffer1, 512); + status |= fx_media_open(&ram_disk2, "RAM DISK2", _fx_ram_driver, ram_disk_memory2, buffer2, 512); + if (status != FX_SUCCESS) + { + + /* Storage basic test error. */ + printf("ERROR %d\n", __LINE__); + test_control_return(1); + } + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* 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 #%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 device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 2; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_media_flush; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_flush = demo_media_flush; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_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(); + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(ux_test_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main device simulation thread. */ + status = tx_thread_create(&tx_demo_thread_device_simulation, "tx demo device simulation", tx_demo_thread_device_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 21, 21, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + stack_pointer += UX_DEMO_STACK_SIZE; + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static void tx_demo_thread_device_simulation_entry(ULONG arg) +{ + while(1) + { + + /* Run device tasks. */ + ux_system_tasks_run(); + + /* Relinquish to other thread. */ + tx_thread_relinquish(); + } +} + +static ULONG _test_dw_minus(ULONG d0, ULONG d1) +{ + if (d0 >= d1) + return(d0 - d1); + return(d0 + (0xFFFFFFFF - d1)); +} + +static UINT _media_driver_read(FX_MEDIA *media, + VOID (*_media_driver)(FX_MEDIA *), + UCHAR *buffer, ULONG lba, ULONG n_lb) +{ +UINT status; + + if (lba == 0) + { + media->fx_media_driver_logical_sector = lba; + media->fx_media_driver_sectors = n_lb; + media->fx_media_driver_request = FX_DRIVER_BOOT_READ; + media->fx_media_driver_buffer = buffer; + _media_driver(media); + *(buffer) = 0xeb; + *(buffer+1) = 0x3c; + *(buffer+2) = 0x90; + *(buffer+21) = 0xF8; + + *(buffer+24) = 0x01; + *(buffer+26) = 0x10; + *(buffer+28) = 0x01; + + *(buffer+510) = 0x55; + *(buffer+511) = 0xaa; + ux_utility_memory_copy(buffer+0x36,"FAT12",5); + + if (media->fx_media_driver_status != FX_SUCCESS) + { + printf("%s:%d: FX error 0x%x\n", __FILE__, __LINE__, media->fx_media_driver_status); + return(UX_ERROR); + } + + lba++; + n_lb --; + buffer += 512; + } + media->fx_media_driver_logical_sector = lba; + media->fx_media_driver_sectors = n_lb; + media->fx_media_driver_request = FX_DRIVER_READ; + media->fx_media_driver_buffer = buffer; + _media_driver(media); + if (media->fx_media_driver_status != FX_SUCCESS) + { + stepinfo("%s:%d: FX error 0x%x\n", __FILE__, __LINE__, media->fx_media_driver_status); + return(UX_ERROR); + } + return(UX_SUCCESS); +} + +static UINT _media_driver_write(FX_MEDIA *media, + VOID (*_media_driver)(FX_MEDIA *), + UCHAR *buffer, ULONG lba, ULONG n_lb) +{ +UINT status; + + if (lba == 0) + { + media -> fx_media_driver_logical_sector = 0; + media -> fx_media_driver_sectors = 1; + media -> fx_media_driver_request = FX_DRIVER_BOOT_WRITE; + media -> fx_media_driver_buffer = buffer; + _media_driver(media); + + if (media->fx_media_driver_status != FX_SUCCESS) + { + printf("%s:%d: FX error 0x%x\n", __FILE__, __LINE__, media->fx_media_driver_status); + return(UX_ERROR); + } + + lba ++; + n_lb --; + buffer += 512; + } + if (n_lb) + { + media -> fx_media_driver_logical_sector = lba; + media -> fx_media_driver_sectors = n_lb; + media -> fx_media_driver_request = FX_DRIVER_WRITE; + media -> fx_media_driver_buffer = buffer; + _media_driver(media); + + if (media->fx_media_driver_status != FX_SUCCESS) + { + printf("%s:%d: FX error 0x%x\n", __FILE__, __LINE__, media->fx_media_driver_status); + return(UX_ERROR); + } + } + return(UX_SUCCESS); +} + +static UINT _test_host_class_storage_inquiry(UX_HOST_CLASS_STORAGE *storage, + UCHAR flags, ULONG data_length, ULONG cb_length, + UCHAR page_code, UCHAR *response, ULONG response_length) +{ +UINT status; +UCHAR *cbw; +UINT command_length; + + /* Use a pointer for the cbw, easier to manipulate. */ + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + /* Initialize the CBW for this command. */ + _ux_host_class_storage_cbw_initialize(storage, flags, data_length, cb_length); + + /* Prepare the INQUIRY command block. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_INQUIRY; + + /* Store the page code. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_PAGE_CODE) = page_code; + + /* Store the length of the Inquiry Response. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_ALLOCATION_LENGTH) = (UCHAR)response_length; + + /* Send the command to transport layer. */ + status = _ux_host_class_storage_transport(storage, response); + + /* Return completion status. */ + return(status); +} +static UINT test_host_class_storage_inquiry(UX_HOST_CLASS_STORAGE *storage, UCHAR page_code, UCHAR *response, ULONG response_length) +{ + _test_host_class_storage_inquiry(storage, + UX_HOST_CLASS_STORAGE_DATA_IN, + UX_HOST_CLASS_STORAGE_INQUIRY_RESPONSE_LENGTH, + UX_HOST_CLASS_STORAGE_INQUIRY_COMMAND_LENGTH_SBC, + page_code, response, response_length); +} + +static UINT _test_send_cbw_EX(int __line__, ULONG length) +{ + +UX_TRANSFER *transfer_request; +UINT status; +UCHAR *cbw; + + stepinfo(">>>>> %d.%d: CBW\n", __LINE__, __line__); + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + transfer_request -> ux_transfer_request_data_pointer = cbw; + transfer_request -> ux_transfer_request_requested_length = length; + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} +static UINT _test_send_cbw(int __line__) +{ + _test_send_cbw_EX(__line__, UX_HOST_CLASS_STORAGE_CBW_LENGTH); +} + +static UINT _test_transfer_data(int __line__, UCHAR *data, ULONG size, UCHAR do_read) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + stepinfo(">>>>> %d.%d: DATA\n", __LINE__, __line__); + transfer_request = do_read ? + &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request : + &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + transfer_request -> ux_transfer_request_data_pointer = data; + transfer_request -> ux_transfer_request_requested_length = size; + + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_wait_csw_EX(int __line__) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + stepinfo(">>>>> %d.%d: CSW_Ex\n", __LINE__, __line__); + + /* Get the pointer to the transfer request, on the bulk in endpoint. */ + transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + /* Fill in the transfer_request parameters. */ + transfer_request -> ux_transfer_request_data_pointer = (UCHAR *) &storage -> ux_host_class_storage_csw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CSW_LENGTH; + + /* Get the CSW on the bulk in endpoint. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + return(status); + + /* Wait for the completion of the transfer request. */ + status = _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* If OK, we are done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static VOID _test_clear_stall(UCHAR clear_read_stall) +{ + +UX_ENDPOINT *endpoint; + + + endpoint = clear_read_stall ? + storage -> ux_host_class_storage_bulk_in_endpoint : + storage -> ux_host_class_storage_bulk_out_endpoint; + _ux_host_stack_endpoint_reset(endpoint); +} + +static UINT _test_wait_csw(int __line__) +{ +UINT status; + + stepinfo(">>>>> %d.%d: CSW\n", __LINE__, __line__); + status = _test_wait_csw_EX(__LINE__); + if (status == UX_TRANSFER_STALLED) + { + _test_clear_stall(UX_TRUE); + status = _test_wait_csw_EX(__LINE__); + } + return(status); +} + +static UINT _test_request_sense(void) +{ + +UINT status; +UX_TRANSFER *transfer_request; +UCHAR *cbw; +UCHAR *request_sense_response; +ULONG sense_code; +UINT command_length = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_COMMAND_LENGTH_SBC; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + _ux_utility_memory_copy(storage -> ux_host_class_storage_saved_cbw, storage -> ux_host_class_storage_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + _ux_host_class_storage_cbw_initialize(storage, UX_HOST_CLASS_STORAGE_DATA_IN, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_REQUEST_SENSE; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_ALLOCATION_LENGTH) = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH; + request_sense_response = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH); + if (request_sense_response == UX_NULL) + return(UX_MEMORY_INSUFFICIENT); + status = _test_send_cbw(__LINE__); + if (status == UX_SUCCESS) + { + status = _test_transfer_data(__LINE__, request_sense_response, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, UX_TRUE); + if (status == UX_SUCCESS) + { + status = _test_wait_csw(__LINE__); + if (status == UX_SUCCESS) + { + + sense_code = (((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_SENSE_KEY)) & 0x0f) << 16; + sense_code |= ((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE)) << 8; + sense_code |= (ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE_QUALIFIER); + + storage -> ux_host_class_storage_sense_code = sense_code; + } + } + } + _ux_utility_memory_free(request_sense_response); + _ux_utility_memory_copy(storage -> ux_host_class_storage_cbw, storage -> ux_host_class_storage_saved_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + return(status); +} + +typedef struct cbw_read_struct +{ + UCHAR flags_pos; + UCHAR lba_pos; + UCHAR lba_size; + UCHAR len_pos; + UCHAR len_size; +} cbw_read_struct_t; +static cbw_read_struct_t cbw_READ_info[] = +{ + { 1, 2, 2, 4, 1}, + { 1, 2, 4, 7, 2}, + { 1, 2, 4, 6, 4}, + { 1, 2, 8, 10, 4}, + {10, 12, 8, 28, 4} +}; +static UCHAR _read_op(UCHAR op_code) +{ + switch(op_code) + { + case 0x28: return 1; + case 0xA8: return 2; + case 0x88: return 3; + case 0x7F: return 4; + case 0x08: return 0; + default: return 0xFF; + } +} +static void _test_init_cbw_READ_EX( + UCHAR flags, ULONG data_length, + UCHAR op6_10_12_16_32, ULONG lba, ULONG len) +{ +UCHAR *cbw; +UINT command_length; +UCHAR op = _read_op(op6_10_12_16_32); +UINT i; + + + if (op >= 5) + return; + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, flags, data_length, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = op6_10_12_16_32; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + cbw_READ_info[op].flags_pos) = 0; + for (i = cbw_READ_info[op].lba_pos + cbw_READ_info[op].lba_size - 1; i >= cbw_READ_info[op].lba_pos; i --) + { + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + i) = (UCHAR)lba; + lba >>= 8; + } + for (i = cbw_READ_info[op].len_pos + cbw_READ_info[op].len_size - 1; i >= cbw_READ_info[op].len_size; i --) + { + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + i) = (UCHAR)len; + len >>= 8; + } +} +static void _test_init_cbw_READ(UCHAR op6_10_12_16_32, ULONG lba, ULONG len) +{ + _test_init_cbw_READ_EX(0x80, len * 512, op6_10_12_16_32, lba, len); +} + +typedef struct cbw_write_struct +{ + UCHAR flags_pos; + UCHAR lba_pos; + UCHAR lba_size; + UCHAR len_pos; + UCHAR len_size; +} cbw_write_struct_t; +static cbw_write_struct_t cbw_WRITE_info[] = +{ + { 1, 2, 2, 4, 1}, + { 1, 2, 4, 7, 2}, + { 1, 2, 4, 6, 4}, + { 1, 2, 8, 10, 4}, + {10, 12, 8, 28, 4} +}; +static UCHAR _write_op(UCHAR op_code) +{ + switch(op_code) + { + case 0x2A: return 1; + case 0xAA: return 2; + case 0x8A: return 3; + case 0x7F: return 4; + case 0x0A: return 0; + default: return 0xFF; + } +} +static void _test_init_cbw_WRITE_EX(UCHAR flags, ULONG data_length, + UCHAR op6_10_12_16_32, ULONG lba, ULONG len) +{ + +UCHAR *cbw; +UINT command_length; +UCHAR op = _write_op(op6_10_12_16_32); +UINT i; + + + if (op >= 5) + return; + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, flags, data_length, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = op6_10_12_16_32; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + cbw_WRITE_info[op].flags_pos) = 0; + for (i = cbw_WRITE_info[op].lba_pos + cbw_WRITE_info[op].lba_size - 1; i >= cbw_WRITE_info[op].lba_pos; i --) + { + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + i) = (UCHAR)lba; + lba >>= 8; + } + for (i = cbw_WRITE_info[op].len_pos + cbw_WRITE_info[op].len_size - 1; i >= cbw_WRITE_info[op].len_size; i --) + { + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + i) = (UCHAR)len; + len >>= 8; + } +} +static void _test_init_cbw_WRITE(UCHAR op6_10_12_16_32, ULONG lba, ULONG len) +{ + _test_init_cbw_WRITE_EX(0x00, len * 512, op6_10_12_16_32, lba, len); +} + +static void _test_init_cbw_REQUEST_SENSE(ULONG data_length) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0x80, data_length, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_REQUEST_SENSE; +} + +static void _test_init_cbw_TEST_READY(ULONG data_length) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0x00, data_length, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_TEST_READY; +} + +static void _test_init_cbw_FORMAT_UNIT(void) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, 0, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_FORMAT; +} + +static void _test_init_cbw_START_STOP(void) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, 0, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_START_STOP; +} + +static void _test_init_cbw_VERIFY(void) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, 0, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_VERIFY; +} + +static void _test_init_cbw_MODE_SELECT(ULONG data_length) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, data_length, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SELECT; +} + +static void _test_init_cbw_MODE_SENSE(UCHAR op6, UCHAR page_code, ULONG buffer_length) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0x80, buffer_length, command_length); + if (op6) + { + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE_SHORT; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PARAMETER_LIST_LENGTH_6) = (UCHAR)buffer_length; + } + else + { + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE; + _ux_utility_short_put_big_endian(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PARAMETER_LIST_LENGTH_10, (USHORT)buffer_length); + } + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PC_PAGE_CODE) = page_code; +} + +static void _test_init_cbw_SYNCHRONIZE_CACHE(UCHAR op16, UCHAR immed, ULONG lba, ULONG nb_blocks) +{ + +UCHAR *cbw; +UINT command_length; + + + (void)op16; + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, 0, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_SYNCHRONIZE_CACHE_FLAGS) = immed ? UX_SLAVE_CLASS_STORAGE_SYNCHRONIZE_CACHE_FLAGS_IMMED : 0; + _ux_utility_long_put_big_endian(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_SYNCHRONIZE_CACHE_LBA, lba); + _ux_utility_short_put_big_endian(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_SYNCHRONIZE_CACHE_NUMBER_OF_BLOCKS, (USHORT)nb_blocks); +} + +static void _test_init_cbw_PREVENT_ALLOW_MEDIA_REMOVAL(void) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, 0, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_PREVENT_ALLOW_MEDIA_REMOVAL; +} + + +static void _msc_cbw_fail_cases_test(const char* __file__, int __line__) +{ +UINT status; +UCHAR *cbw; + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + stepinfo("\n%s:%d:MSC CBW fail tests\n", __file__, __line__); + + stepinfo(">>>>>>>>>>>>>>>> Test VERIFY CBW length error\n"); + _test_init_cbw_VERIFY(); + status = _test_send_cbw_EX(__LINE__, UX_HOST_CLASS_STORAGE_CBW_LENGTH - 1); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + stepinfo(">>>>>>>>>>>>>>>> Test VERIFY CBW LUN error\n"); + _test_init_cbw_VERIFY(); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_LUN + 0) = 0xFF; + status = _test_send_cbw_EX(__LINE__, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + stepinfo(">>>>>>>>>>>>>>>> Test VERIFY CBW Signature error\n"); + _test_init_cbw_VERIFY(); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_SIGNATURE + 0) = 0xFF; + status = _test_send_cbw_EX(__LINE__, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + stepinfo(">>>>>>>>>>>>>>>> Test VERIFY CBW CBW_CB length error\n"); + _test_init_cbw_VERIFY(); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB_LENGTH + 0) = 0; + status = _test_send_cbw_EX(__LINE__, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + _test_clear_stall(UX_TRUE); + _test_init_cbw_VERIFY(); + status = _test_send_cbw_EX(__LINE__, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + stepinfo(">>>>>>>>>>>>>>>> Test CBW CMD unknown error\n"); + _test_init_cbw_VERIFY(); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = 0xFF; + status = _test_send_cbw_EX(__LINE__, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); +} + + +static void _msc_get_max_lun_cases_test(const char* __file__, int __line__) +{ +UINT status; +UX_DEVICE *device; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; + + stepinfo("\n%s:%d:MSC GET_MAX_LUN tests\n", __file__, __line__); + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: device_get fail\n", __LINE__, __line__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Send transfer request - GetMaxLun. */ + transfer_request -> ux_transfer_request_data_pointer = UX_NULL; + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_SLAVE_CLASS_STORAGE_GET_MAX_LUN; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceNumber; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS && status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Invalid wValue. */ + transfer_request -> ux_transfer_request_value = 1; + transfer_request -> ux_transfer_request_index = storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceNumber; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Invalid wIndex. */ + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceNumber + 1; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Send transfer request - UX_SLAVE_CLASS_STORAGE_RESET. */ + transfer_request -> ux_transfer_request_function = UX_SLAVE_CLASS_STORAGE_RESET; + + /* Invalid wValue. */ + transfer_request -> ux_transfer_request_value = 1; + transfer_request -> ux_transfer_request_index = storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceNumber; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Invalid wIndex. */ + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceNumber + 1; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Invalid wLength. */ + transfer_request -> ux_transfer_request_data_pointer = (UCHAR*)&status; + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceNumber; + transfer_request -> ux_transfer_request_requested_length = 1; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void _msc_inquiry_cases_test(const char* __file__, int __line__) +{ +UINT status; +UX_SLAVE_DEVICE *slave_device; +UX_SLAVE_CLASS *slave_class; +UX_SLAVE_CLASS_STORAGE *slave_storage; + + stepinfo("\n%s:%d:MSC INQUIRY tests\n", __file__, __line__); + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(standard)\n"); + status = test_host_class_storage_inquiry(storage, 0x00, buffer, 64); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(standard, UX_SLAVE_CLASS_STORAGE_MEDIA_CDROM)\n"); + slave_device = &_ux_system_slave->ux_system_slave_device; + slave_class = _ux_system_slave->ux_system_slave_interface_class_array[0]; + slave_storage = (UX_SLAVE_CLASS_STORAGE *)slave_class->ux_slave_class_instance; + slave_storage -> ux_slave_class_storage_lun[0].ux_slave_class_storage_media_type = UX_SLAVE_CLASS_STORAGE_MEDIA_CDROM; + status = test_host_class_storage_inquiry(storage, 0x00, buffer, 64); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(unknown page code)\n"); + status = test_host_class_storage_inquiry(storage, 0xEF, buffer, 64); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(big buffer)\n"); + status = _test_host_class_storage_inquiry(storage, 0x80, + 64, + UX_HOST_CLASS_STORAGE_INQUIRY_COMMAND_LENGTH_SBC, + 0x00, buffer, 64); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(Hi <> Do)\n"); + status = _test_host_class_storage_inquiry(storage, 0x00, + UX_HOST_CLASS_STORAGE_INQUIRY_RESPONSE_LENGTH, + UX_HOST_CLASS_STORAGE_INQUIRY_COMMAND_LENGTH_SBC, + 0x00, buffer, UX_HOST_CLASS_STORAGE_INQUIRY_RESPONSE_LENGTH); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(Hi <> Do)\n"); + status = _test_host_class_storage_inquiry(storage, 0x00, + 0, + UX_HOST_CLASS_STORAGE_INQUIRY_COMMAND_LENGTH_SBC, + 0x00, buffer, UX_HOST_CLASS_STORAGE_INQUIRY_RESPONSE_LENGTH); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } +} + +static void _msc_read_cases_test(const char* __file__, int __line__) +{ +UINT status; + + stepinfo("\n%s:%d:MSC READ tests\n", __file__, __line__); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_READ32 - success\n"); + _test_init_cbw_READ(UX_SLAVE_CLASS_STORAGE_SCSI_READ32, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 512, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_READ16 - status fail\n"); + ram_disk_status = UX_ERROR; + _test_init_cbw_READ(UX_SLAVE_CLASS_STORAGE_SCSI_READ16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 512, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + ram_disk_status = UX_SUCCESS; + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_READ16 - transfer fail\n"); + _test_init_cbw_READ(UX_SLAVE_CLASS_STORAGE_SCSI_READ16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + ux_test_dcd_sim_slave_set_actions(fail_on_bulkin); + status = _test_transfer_data(__LINE__, buffer, 512, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_READ16 - Case(7) Hi < Di\n"); + _test_init_cbw_READ_EX(0x80, 0, UX_SLAVE_CLASS_STORAGE_SCSI_READ16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 512, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_READ16 - Case(8) Hi <> Do\n"); + _test_init_cbw_READ_EX(0x00, 512, UX_SLAVE_CLASS_STORAGE_SCSI_READ16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 512, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_READ16 - Case(5) Hi > Di\n"); + _test_init_cbw_READ_EX(0x80, 1024, UX_SLAVE_CLASS_STORAGE_SCSI_READ16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 1024, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); +} + +static void _msc_write_cases_test(const char* __file__, int __line__) +{ +UINT status; +UX_SLAVE_DEVICE *slave_device; +UX_SLAVE_CLASS *slave_class; +UX_SLAVE_CLASS_STORAGE *slave_storage; + + stepinfo("\n%s:%d:MSC WRITE tests\n", __file__, __line__); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_WRITE32 - success\n"); + _test_init_cbw_WRITE(UX_SLAVE_CLASS_STORAGE_SCSI_WRITE32, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 512, UX_FALSE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16 - status fail\n"); + ram_disk_status = UX_ERROR; + _test_init_cbw_WRITE(UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 512, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + ram_disk_status = UX_SUCCESS; + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16 - transfer fail\n"); + _test_init_cbw_WRITE(UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + ux_test_dcd_sim_slave_set_actions(fail_on_bulkout); + status = _test_transfer_data(__LINE__, buffer, 512, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16 - WP fail\n"); + slave_device = &_ux_system_slave->ux_system_slave_device; + slave_class = _ux_system_slave->ux_system_slave_interface_class_array[0]; + slave_storage = (UX_SLAVE_CLASS_STORAGE *)slave_class->ux_slave_class_instance; + slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_read_only_flag = UX_TRUE; + _test_init_cbw_WRITE(UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 512, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_read_only_flag = UX_FALSE; + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16 - Case (3) Hn < Do\n"); + _test_init_cbw_WRITE_EX(0x00, 0, UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + #if 0 /* Host expect no data. */ + status = _test_transfer_data(__LINE__, buffer, 512, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + #endif + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16 - Case (8) Hi <> Do\n"); + _test_init_cbw_WRITE_EX(0x80, 512, UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 512, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16 - Case (9) Ho > Do\n"); + _test_init_cbw_WRITE_EX(0x00, 1024, UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 1024, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); +} + +static void _msc_request_sense_cases_test(const char* __file__, int __line__) +{ +UINT status; + + stepinfo("\n%s:%d:MSC REQUEST_SENSE tests\n", __file__, __line__); + + _test_init_cbw_REQUEST_SENSE(64); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 64, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); +} + +static void _msc_test_ready_cases_test(const char* __file__, int __line__) +{ +UINT status; + + stepinfo("\n%s:%d:MSC UNIT_READY tests\n", __file__, __line__); + + _test_init_cbw_TEST_READY(64); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 64, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); +} + +static void _msc_format_unit_cases_test(const char* __file__, int __line__) +{ +UINT status; + + stepinfo("\n%s:%d:MSC FORMAT_UNIT tests\n", __file__, __line__); + + _test_init_cbw_FORMAT_UNIT(); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + #if 0 /* Host expects no data. */ + status = _test_transfer_data(__LINE__, "test dead beef", 15, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + #endif + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_request_sense(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void _msc_start_stop_cases_test(const char* __file__, int __line__) +{ +UINT status; + + stepinfo("\n%s:%d:MSC START_STOP tests\n", __file__, __line__); + + _test_init_cbw_START_STOP(); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void _msc_verify_cases_test(const char* __file__, int __line__) +{ +UINT status; + + stepinfo("\n%s:%d:MSC VERIFY tests\n", __file__, __line__); + + _test_init_cbw_VERIFY(); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void _msc_mode_sense_cases_test(const char* __file__, int __line__) +{ +UINT status; +UX_SLAVE_DEVICE *slave_device; +UX_SLAVE_CLASS *slave_class; +UX_SLAVE_CLASS_STORAGE *slave_storage; + + stepinfo("\n%s:%d:MSC MODE_SENSE tests\n", __file__, __line__); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(PAGE_CODE_CDROM):\n"); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(PAGE_CODE_CDROM) - 128B\n"); + _test_init_cbw_MODE_SENSE(UX_FALSE, UX_SLAVE_CLASS_STORAGE_MMC2_PAGE_CODE_CDROM, 128); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(PAGE_CODE_CDROM) - 74B\n"); + _test_init_cbw_MODE_SENSE(UX_TRUE, UX_SLAVE_CLASS_STORAGE_MMC2_PAGE_CODE_CDROM, 74); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 74, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Change read_only_flag */ + slave_device = &_ux_system_slave->ux_system_slave_device; + slave_class = _ux_system_slave->ux_system_slave_interface_class_array[0]; + slave_storage = (UX_SLAVE_CLASS_STORAGE *)slave_class->ux_slave_class_instance; + slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_read_only_flag = UX_TRUE; + + /************ UX_SLAVE_CLASS_STORAGE_PAGE_CODE_CACHE ****************/ + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(PAGE_CODE_CACHE):\n"); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(PAGE_CODE_CACHE) - 128B\n"); + _test_init_cbw_MODE_SENSE(UX_FALSE, UX_SLAVE_CLASS_STORAGE_PAGE_CODE_CACHE, 128); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(PAGE_CODE_CACHE) - 24B\n"); + _test_init_cbw_MODE_SENSE(UX_TRUE, UX_SLAVE_CLASS_STORAGE_PAGE_CODE_CACHE, 24); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 24, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(PAGE_CODE_CACHE) - 24B\n"); + slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_flush = demo_media_flush; + _test_init_cbw_MODE_SENSE(UX_TRUE, UX_SLAVE_CLASS_STORAGE_PAGE_CODE_CACHE, 24); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 24, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /************ UX_SLAVE_CLASS_STORAGE_PAGE_CODE_IEC ****************/ + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(PAGE_CODE_IEC) - 128B\n"); + _test_init_cbw_MODE_SENSE(UX_FALSE, UX_SLAVE_CLASS_STORAGE_PAGE_CODE_IEC, 128); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(PAGE_CODE_IEC) - 16B\n"); + _test_init_cbw_MODE_SENSE(UX_TRUE, UX_SLAVE_CLASS_STORAGE_PAGE_CODE_IEC, 16); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 16, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /************ 0x3F ****************/ + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(0x3F) - 128B\n"); + _test_init_cbw_MODE_SENSE(UX_FALSE, 0x3F, 128); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /************ 0x3F ****************/ + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(0x3F) - %dB\n", + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE + 8); + _test_init_cbw_MODE_SENSE(UX_FALSE, 0x3F, UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE + 8); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void _msc_mode_select_cases_test(const char* __file__, int __line__) +{ +UINT status; + + stepinfo("\n%s:%d:MSC MODE_SELECT tests\n", __file__, __line__); + + _test_init_cbw_MODE_SELECT(15); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, "test dead beef", 15, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_request_sense(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void _msc_synchronous_cache_cases_test(const char* __file__, int __line__) +{ +UINT status; +UX_SLAVE_DEVICE *slave_device; +UX_SLAVE_CLASS *slave_class; +UX_SLAVE_CLASS_STORAGE *slave_storage; + + stepinfo("\n%s:%d:MSC SYNCHRONOUS_CACHE tests\n", __file__, __line__); + + slave_device = &_ux_system_slave->ux_system_slave_device; + slave_class = _ux_system_slave->ux_system_slave_interface_class_array[0]; + slave_storage = (UX_SLAVE_CLASS_STORAGE *)slave_class->ux_slave_class_instance; + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE no CB - success\n"); + slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_flush = UX_NULL; + slave_storage->ux_slave_class_storage_lun[1].ux_slave_class_storage_media_flush = UX_NULL; + _test_init_cbw_SYNCHRONIZE_CACHE(UX_FALSE, UX_FALSE, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE - success\n"); + slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_flush = demo_media_flush; + slave_storage->ux_slave_class_storage_lun[1].ux_slave_class_storage_media_flush = demo_media_flush; + _test_init_cbw_SYNCHRONIZE_CACHE(UX_FALSE, UX_FALSE, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE - status fail\n"); + _test_init_cbw_SYNCHRONIZE_CACHE(UX_FALSE, UX_FALSE, 0, 1); + ram_disk_status = UX_ERROR; + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw_EX(__LINE__); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw_EX(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_request_sense(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + ram_disk_status = UX_SUCCESS; + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE - flush fail\n"); + _test_init_cbw_SYNCHRONIZE_CACHE(UX_FALSE, UX_FALSE, 0, 1); + ram_disk_flush_status = UX_STATE_ERROR; + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw_EX(__LINE__); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw_EX(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + ram_disk_flush_status = UX_STATE_NEXT; +} + +static void _msc_prevent_allow_removal_cases_test(const char* __file__, int __line__) +{ +UINT status; + + stepinfo("\n%s:%d:MSC PREVENT_ALLOW_MEDIA_REMOVAL tests\n", __file__, __line__); + + _test_init_cbw_PREVENT_ALLOW_MEDIA_REMOVAL(); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + + +static void _msc_media_read_test(const char* __file__, int __line__) +{ +UINT status; +ULONG test_n; +ULONG test_size[] = { + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 2 / 512, + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 3 / 512, + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 2 / 512 + 1}; + + stepinfo("\n%s:%d:MSC Media Read tests\n", __file__, __line__); + + if (media == UX_NULL || media -> fx_media_id == 0) + { + printf("ERROR %d: media error\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Disk read(1) test\n"); + { + status = fx_media_read(media, 48, buffer); + if (status != FX_SUCCESS) + { + printf("ERROR %d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + } + + /* Disk read multiple test. */ + for (test_n = 0; test_n < sizeof(test_size)/sizeof(test_size[0]); test_n ++) + { + + stepinfo(">>>>>>>>>>>> Disk read(%d) test\n", test_size[test_n]); + status = _media_driver_read(media, _ux_host_class_storage_driver_entry, + buffer, 0, test_size[test_n]); + if (status != UX_SUCCESS) + { + printf("ERROR %d.%ld: 0x%x\n", __LINE__, test_n, status); + test_control_return(1); + } + } +} + +static void _msc_media_write_read_test(const char* __file__, int __line__) +{ +UINT status; +ULONG test_n; +INT i; +ULONG test_size[] = { + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 2 / 512, + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 3 / 512, + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 2 / 512 + 1}; + + stepinfo("\n%s:%d:MSC Media Write & Read tests\n", __file__, __line__); + + /* Check if media still available. */ + if (media == UX_NULL || media -> fx_media_id == 0) + { + printf("ERROR %d: media error\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Disk write(1)/read(1) test\n"); + { + for(i = 0; i < 512; i ++) + buffer[i] = i; + status = fx_media_write(media, 48, buffer); + if (status != FX_SUCCESS) + { + printf("ERROR %d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_utility_memory_set(buffer, 0x00, 512); + status = fx_media_read(media, 48, buffer); + if (status != FX_SUCCESS) + { + printf("ERROR %d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + for (i = 0; i < 512; i ++) + { + if (buffer[i] != (UCHAR)i) + { + printf("ERROR %d: %d <> %d\n", __LINE__, i, buffer[i]); + test_control_return(1); + } + } + } + + /* Disk write/read multiple test. */ + for (test_n = 0; test_n < sizeof(test_size)/sizeof(test_size[0]); test_n ++) + { + stepinfo(">>>>>>>>>>>> Disk write(%ld)/read(%ld) test\n", + test_size[test_n], test_size[test_n]); + + for(i = 0; i < test_size[test_n] * 512; i ++) + buffer[i] = (UCHAR)(i + (i >> 8)); + status = _media_driver_write(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size[test_n]); + if (status != FX_SUCCESS) + { + printf("ERROR %d.%ld: 0x%x\n", __LINE__, test_n, status); + test_control_return(1); + } + _ux_utility_memory_set(buffer, 0x00, test_size[test_n] * 512); + status = _media_driver_read(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size[test_n]); + if (status != FX_SUCCESS) + { + printf("ERROR %d.%ld: 0x%x\n", __LINE__, test_n, status); + test_control_return(1); + } + for (i = 0; i < 512; i ++) + { + if (buffer[i] != (UCHAR)(i + (i >> 8))) + { + printf("ERROR %d: %d <> %d\n", __LINE__, i, buffer[i]); + test_control_return(1); + } + } + } +} + +static void _msc_enumeration_test(const char* __file__, int __line__, unsigned option) +{ +UINT status; +ULONG mem_free; +ULONG test_n; + + stepinfo("\n%s:%d:MSC Enumeration tests\n", __file__, __line__); + + stepinfo(">>>>>>>>>>>> Enumeration information collection\n"); + { + + /* Test disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check connection. */ + status = host_storage_instance_get(0); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_count_reset(); + ux_test_utility_sim_mutex_create_count_reset(); + ux_test_utility_sim_sem_create_count_reset(); + ux_test_utility_sim_sem_get_count_reset(); + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + + /* Save free memory usage. */ + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Check connection. */ + status = host_storage_instance_get(50); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Log create counts for further tests. */ + rsc_enum_mutex_usage = rsc_mutex_on_set_cfg; + rsc_enum_sem_usage = rsc_sem_on_set_cfg; + rsc_enum_mem_alloc_count = rsc_mem_alloc_cnt_on_set_cfg; + /* Log create counts when instances active for further tests. */ + rsc_storage_mutex_usage = ux_test_utility_sim_mutex_create_count() - rsc_enum_mutex_usage; + rsc_storage_sem_usage = ux_test_utility_sim_sem_create_count() - rsc_enum_sem_usage; + rsc_storage_mem_alloc_count = ux_test_utility_sim_mem_alloc_count() - rsc_enum_mem_alloc_count; + + /* Lock log base for tests. */ + ux_test_utility_sim_mem_alloc_log_lock(); + + stepinfo("enum mem: %ld\n", rsc_enum_mem_alloc_count); + stepinfo("storage mem : %ld\n", rsc_storage_mem_alloc_count); + stepinfo("mem free: %ld, %ld\n", _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); + } + + /* Simulate detach and attach for FS enumeration, + and check if there is memory error in normal enumeration. + */ + if (option & (1u)) + { + stepinfo(">>>>>>>>>>>> Enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < 3; test_n++) + { + stepinfo("%4ld / 2\n", test_n); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check */ + if (host_storage_instance_get(0) == UX_SUCCESS) + { + + printf("ERROR #%d.%ld: Disconnect fail\n", __LINE__, test_n); + test_control_return(1); + } + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Wait and break on error. */ + error_callback_counter = 0; + ux_test_breakable_sleep( + (UX_MS_TO_TICK_NON_ZERO(UX_RH_ENUMERATION_RETRY_DELAY) + + UX_MS_TO_TICK_NON_ZERO(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY)) * + 3, + sleep_break_on_connect); + + /* Check */ + if (host_storage_instance_get(0) != UX_SUCCESS) + { + + printf("ERROR #%d.%ld: Enumeration fail\n", __LINE__, test_n); + test_control_return(1); + } + } + stepinfo("\n"); + } + + /* Simulate detach and attach for FS enumeration, + and test possible memory allocation error handlings. + */ + if (option & (2u)) + { + if (rsc_storage_mem_alloc_count) stepinfo(">>>>>>>>>>>> Memory errors enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_storage_mem_alloc_count; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_storage_mem_alloc_count - 1); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check */ + if (host_storage_instance_get(0) == UX_SUCCESS) + { + + printf("ERROR #%d.%ld: Disconnect fail\n", __LINE__, test_n); + test_control_return(1); + } + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Set memory error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n + rsc_enum_mem_alloc_count); + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on errors. */ + ux_test_breakable_sleep(100, sleep_break_on_error); + + /* Check error */ + if (host_storage_instance_get(0) == UX_SUCCESS) + { + + /* Could be media errors, + in this case instance is ready, + check error trap. */ + if (error_callback_counter == 0) + { + printf("ERROR #%d.%ld: device detected when there is memory error\n", __LINE__, test_n); + test_control_return(1); + } + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + } + ux_test_utility_sim_mem_alloc_error_generation_stop(); + if (rsc_storage_mem_alloc_count) stepinfo("\n"); + } +} + +static void _msc_media_write_read_misc_test(const char* __file__, int __line__) +{ +UINT status; +UINT test_size = UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 3 / 512; +UINT test_n; +ULONG test_start; +ULONG test_ticks; +INT i; + + stepinfo("\n%s:%d:MSC Media Read tests\n", __file__, __line__); + + if (media == UX_NULL || media -> fx_media_id == 0) + { + printf("ERROR %d.%d: media error\n", __LINE__, __line__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Disk read(%d) test - tick obtain\n", test_size); + test_start = tx_time_get(); + status = _media_driver_read(media, _ux_host_class_storage_driver_entry, + buffer, 0, test_size); + test_ticks = _test_dw_minus(tx_time_get(), test_start); + if (status != UX_SUCCESS) + { + printf("ERROR %d.%d: 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + test_ticks /= 3; + stepinfo(" :: Buffer XFR time: %ld ticks\n", test_ticks); + + stepinfo(">>>>>>>>>>>> Disk write/read(%d) test - slow disk write/read\n", test_size); + ram_disk_rw_wait_delay = ((test_ticks + 1) >> 1) + 1; + for(test_n = 0; test_n < 4; test_n ++) + { + stepinfo(">>>>>>>>>>>> Disk write/read(%d) test - disk write/read wait %ld\n", + test_size, ram_disk_rw_wait_delay); + for(i = 0; i < test_size * 512; i ++) + buffer[i] = (UCHAR)(i + (i >> 8)); + ram_disk_rw_wait_start = tx_time_get(); + status = _media_driver_write(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size); + if (status != FX_SUCCESS) + { + printf("ERROR %d.%d.%d: 0x%x\n", __LINE__, __line__, test_n, status); + test_control_return(1); + } + _ux_utility_memory_set(buffer, 0x00, test_size * 512); + ram_disk_rw_wait_start = tx_time_get(); + status = _media_driver_read(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size); + if (status != FX_SUCCESS) + { + printf("ERROR %d.%d.%d: 0x%x\n", __LINE__, __line__, test_n, status); + test_control_return(1); + } + for (i = 0; i < 512; i ++) + { + if (buffer[i] != (UCHAR)(i + (i >> 8))) + { + printf("ERROR %d.%d.%d: %d <> %d\n", __LINE__, __line__, test_n, i, buffer[i]); + test_control_return(1); + } + } + ram_disk_rw_wait_delay <<= 1; + } + + stepinfo(">>>>>>>>>>>> Disk read(%d) test - USB fail while disk waiting\n", test_size); + ram_disk_rw_wait_start = tx_time_get(); + ram_disk_rw_count = 0; + ram_disk_rw_fail_mode = 0x81; + ram_disk_rw_fail_after = 1; + status = _media_driver_read(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size); + if (status == UX_SUCCESS) + { + printf("ERROR %d.%d: 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Disk write(%d) test - USB fail while disk waiting\n", test_size); + ram_disk_rw_wait_start = tx_time_get(); + ram_disk_rw_count = 0; + ram_disk_rw_fail_mode = 0x82; + ram_disk_rw_fail_after = 0; + status = _media_driver_write(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size); + if (0 /*status == UX_SUCCESS*/) + { + printf("ERROR %d.%d: 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + + /* Restore: no disk wait delay. */ + ram_disk_rw_fail_after = 0xFFFFFFFF; + ram_disk_rw_wait_delay = 0; +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; + + + /* Find the storage class. */ + status = host_storage_instance_get(800); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> MSC Basic test\n"); + + _msc_media_read_test(__FILE__, __LINE__); + _msc_enumeration_test(__FILE__, __LINE__, 3); +#if 0 /* Moved to read write test. */ + _msc_media_write_read_test(__FILE__, __LINE__); + _msc_media_write_read_misc_test(__FILE__, __LINE__); +#endif +#if 0 /* Moved to CV test. */ + stepinfo(">>>>>>>>>>>> MSC Error & CV cases test\n"); + +#ifndef UX_STANDALONE + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)storage->ux_host_class_storage_class->ux_host_class_ext)->ux_host_class_thread); +#endif + + _msc_cbw_fail_cases_test(__FILE__, __LINE__); + + _msc_get_max_lun_cases_test(__FILE__, __LINE__); + _msc_inquiry_cases_test(__FILE__, __LINE__); + _msc_read_cases_test(__FILE__, __LINE__); + _msc_write_cases_test(__FILE__, __LINE__); + _msc_request_sense_cases_test(__FILE__, __LINE__); + _msc_test_ready_cases_test(__FILE__, __LINE__); + _msc_format_unit_cases_test(__FILE__, __LINE__); + _msc_start_stop_cases_test(__FILE__, __LINE__); + _msc_verify_cases_test(__FILE__, __LINE__); + _msc_mode_sense_cases_test(__FILE__, __LINE__); + _msc_mode_select_cases_test(__FILE__, __LINE__); + _msc_synchronous_cache_cases_test(__FILE__, __LINE__); + _msc_prevent_allow_removal_cases_test(__FILE__, __LINE__); + +#ifndef UX_STANDALONE + /* Resume the class driver thread. */ + _ux_utility_thread_resume(&((UX_HOST_CLASS_STORAGE_EXT*)storage->ux_host_class_storage_class->ux_host_class_ext)->ux_host_class_thread); +#endif +#endif + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +static UCHAR lun_init_done[2] = {0, 0}; +UINT status; +ULONG mstatus = UX_SLAVE_CLASS_STORAGE_SENSE_KEY_NO_SENSE; + + + (void)storage; + (void)media_id; + + if (ram_disk_status) + { + status = ram_disk_status; + if (media_status) + *media_status = ram_disk_media_status; + ram_disk_status = UX_SUCCESS; + ram_disk_status_sent = UX_TRUE; + return(status); + } + + if (lun > 1) + status = (UX_ERROR); + else if (lun_init_done[lun] > 0) + status = (UX_SUCCESS); + else + { + lun_init_done[lun] ++; + mstatus = UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8); + status = (UX_ERROR); + } + + if (media_status) + *media_status = mstatus; + + return status; +} + +static UINT demo_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + +UINT status = 0; + + /* Abort. */ + if (data_pointer == UX_NULL) + { + ram_disk_rw_wait_state = 0; + return(UX_STATE_NEXT); + } + + /* Media RW fail simulation. */ + if (ram_disk_rw_fail_after < 0xFFFFFFFF) + { + ram_disk_rw_count ++; + if (ram_disk_rw_count >= ram_disk_rw_fail_after) + { + if (ram_disk_rw_fail_mode_one_shot()) + { + ram_disk_rw_fail_after = 0xFFFFFFFF; + ram_disk_rw_count = 0; + } + if (ram_disk_rw_fail_mode_bulk_in()) + ux_test_dcd_sim_slave_set_actions(fail_on_bulkin); + else if (ram_disk_rw_fail_mode_bulk_out()) + ux_test_dcd_sim_slave_set_actions(fail_on_bulkout); + else if (ram_disk_rw_fail_mode_disk()) + { + *media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x02,0x54,0x00); + return(UX_STATE_ERROR); + } + } + } + + /* Media RW wait simulation. */ + if (ram_disk_rw_wait_delay) + { + if (_test_dw_minus(tx_time_get(), ram_disk_rw_wait_start) < ram_disk_rw_wait_delay) + { + ram_disk_rw_wait_state = 1; + return(UX_STATE_WAIT); + } + ram_disk_rw_wait_state = 0; + ram_disk_rw_wait_start = tx_time_get(); + } + + status = _media_driver_read(ram_disks[lun], _fx_ram_driver, data_pointer, lba, number_blocks); + if (status != UX_SUCCESS) + { + *media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x02,0x54,0x00); + return(UX_STATE_ERROR); + } + return(UX_STATE_NEXT); +} + +static UINT demo_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + +UINT status = 0; + + /* Abort. */ + if (data_pointer == UX_NULL) + { + ram_disk_rw_wait_state = 0; + return(UX_STATE_NEXT); + } + + /* Media RW fail simulation. */ + if (ram_disk_rw_fail_after < 0xFFFFFFFF) + { + ram_disk_rw_count ++; + if (ram_disk_rw_count >= ram_disk_rw_fail_after) + { + if (ram_disk_rw_fail_mode_one_shot()) + { + ram_disk_rw_fail_after = 0xFFFFFFFF; + ram_disk_rw_count = 0; + } + if (ram_disk_rw_fail_mode_bulk_in()) + ux_test_dcd_sim_slave_set_actions(fail_on_bulkin); + else if (ram_disk_rw_fail_mode_bulk_out()) + ux_test_dcd_sim_slave_set_actions(fail_on_bulkout); + else if (ram_disk_rw_fail_mode_disk()) + { + *media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x02,0x54,0x00); + return(UX_STATE_ERROR); + } + } + } + /* Media RW wait simulation. */ + if (ram_disk_rw_wait_delay) + { + if (_test_dw_minus(tx_time_get(), ram_disk_rw_wait_start) < ram_disk_rw_wait_delay) + { + ram_disk_rw_wait_state = 1; + return(UX_STATE_WAIT); + } + ram_disk_rw_wait_state = 0; + ram_disk_rw_wait_start = tx_time_get(); + } + + status = _media_driver_write(ram_disks[lun], _fx_ram_driver, data_pointer, lba, number_blocks); + if (status != UX_SUCCESS) + { + *media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x02,0x54,0x00); + return(UX_STATE_ERROR); + } + return(UX_STATE_NEXT); +} + +static UINT demo_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)number_blocks; + (void)lba; + (void)media_status; + + if (lun > 1) + return UX_STATE_ERROR; + + ram_disk_flush = UX_TRUE; + return ram_disk_flush_status; +} + +static UINT ux_test_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + + switch(event) + { + + case UX_DEVICE_INSERTION: + break; + + case UX_DEVICE_REMOVAL: + break; + +#if defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + case UX_STORAGE_MEDIA_INSERTION: + /* keep using first media. */ + if (_ux_host_class_storage_media_index((UX_HOST_CLASS_STORAGE_MEDIA*)inst) == 0) + { + _ux_host_class_storage_media_insert((UX_HOST_CLASS_STORAGE_MEDIA*)inst, 1); + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA*)inst; + media = _ux_host_class_storage_media_fx_media((UX_HOST_CLASS_STORAGE_MEDIA*)inst); + } + break; + + case UX_STORAGE_MEDIA_REMOVAL: + if (_ux_host_class_storage_media_index((UX_HOST_CLASS_STORAGE_MEDIA*)inst) == 0) + { + _ux_host_class_storage_media_remove((UX_HOST_CLASS_STORAGE_MEDIA*)inst); + storage_media = UX_NULL; + media = UX_NULL; + } + break; +#endif + + default: + break; + } + + return 0; +} + diff --git a/test/regression/usbx_standalone_device_storage_error_cv_test.c b/test/regression/usbx_standalone_device_storage_error_cv_test.c new file mode 100644 index 00000000..4fd64c3b --- /dev/null +++ b/test/regression/usbx_standalone_device_storage_error_cv_test.c @@ -0,0 +1,2957 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_stack.h" +#include "ux_device_class_storage.h" + +#include "ux_host_stack.h" +#include "ux_host_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#define _storage_media_is_mounted() (global_storage_media->ux_host_class_storage_media_status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED) +#if defined(UX_HOST_CLASS_STORAGE_NO_FILEX) +FX_MEDIA *_ux_host_class_storage_driver_media(INT i); +VOID _ux_host_class_storage_driver_entry(FX_MEDIA *media); +VOID _ux_host_class_storage_media_insert(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG format_open); +VOID _ux_host_class_storage_media_remove(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +INT _ux_host_class_storage_media_index(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +FX_MEDIA *_ux_host_class_storage_media_fx_media(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +UCHAR *_ux_host_class_storage_media_fx_media_memory(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); + +#endif + +/* Define constants. */ +#define UX_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 3) + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ +VOID _fx_ram_driver(FX_MEDIA *media_ptr); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_device_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); +static void tx_demo_thread_device_simulation_entry(ULONG); + +static UINT ux_test_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst); + +static UINT demo_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +static FX_MEDIA *media; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk1; +static FX_MEDIA ram_disk2; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static UCHAR buffer1[512]; +static UCHAR buffer2[512]; + +static FX_MEDIA *ram_disks[] = {&ram_disk1, &ram_disk2}; +static UCHAR *buffers[] = {buffer1, buffer2}; +static CHAR *ram_disk_memory[] = { ram_disk_memory1, ram_disk_memory2 }; + +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static ULONG ram_disk_rw_fail_mode = 0; /* 1: BulkIN, 2: BulkOUT, 0: DISK. 0x80: once */ +#define ram_disk_rw_fail_mode_bulk_in() ((ram_disk_rw_fail_mode & 0x7F) == 1) +#define ram_disk_rw_fail_mode_bulk_out() ((ram_disk_rw_fail_mode & 0x7F) == 2) +#define ram_disk_rw_fail_mode_disk() ((ram_disk_rw_fail_mode & 0x7F) == 0) +#define ram_disk_rw_fail_mode_one_shot() ((ram_disk_rw_fail_mode & 0x80) > 0) +static ULONG ram_disk_rw_fail_after = 0xFFFFFFFFu; +static ULONG ram_disk_rw_count = 0; +static ULONG ram_disk_rw_wait_delay = 0; +static ULONG ram_disk_rw_wait_start = 0; +static UCHAR ram_disk_rw_wait_state = 0;/* 0: idle, 1: wait */ + +static CHAR ram_disk_flush = 0; +static UINT ram_disk_flush_status = UX_STATE_NEXT; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00 + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x02, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x02, 0x00 + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + + +static UX_TEST_HCD_SIM_ACTION fail_on_bulkin[] = { +/* 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_DCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x81, UX_NULL, 0, UX_ERROR, + UX_STATE_ERROR, UX_NULL, + UX_FALSE}, /* Invoke callback & no continue */ +{ 0 } +}; + + +static UX_TEST_HCD_SIM_ACTION fail_on_bulkout[] = { +/* 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_DCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_ERROR, + UX_STATE_ERROR, UX_NULL, + UX_FALSE}, /* Invoke callback & no continue */ +{ 0 } +}; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + storage_media = UX_NULL; + media = UX_NULL; +#endif + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + tx_thread_sleep(UX_MS_TO_TICK_NON_ZERO(10)); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *) class -> ux_host_class_media; + media = &storage_media -> ux_host_class_storage_media; +#endif + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_ext != UX_NULL && + class -> ux_host_class_media != UX_NULL) + { + return(UX_SUCCESS); + } + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + +static UINT sleep_break_on_connect(VOID) +{ + if (host_storage_instance_get(0) == UX_SUCCESS) + return(1); + if (error_callback_counter >= 3) + return(1); + return(0); +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *_params) +{ + + set_cfg_counter ++; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_sem_get_on_set_cfg = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_standalone_device_storage_error_cv_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +ULONG mem_free; +ULONG test_n; + + + /* Inform user. */ + printf("Running STANDALONE Device Storage ERROR & CV Test................... "); +#ifndef UX_DEVICE_STANDALONE + printf("Skip\n"); + test_control_return(0); +#endif + + stepinfo("\n"); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Format the ram drive. */ + status = fx_media_format(&ram_disk1, _fx_ram_driver, ram_disk_memory1, buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + status |= fx_media_format(&ram_disk2, _fx_ram_driver, ram_disk_memory2, buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + if (status != FX_SUCCESS) + { + + /* Storage basic test error. */ + printf("ERROR #8\n"); + test_control_return(1); + } + + /* Open the ram_disk. */ + status = fx_media_open(&ram_disk1, "RAM DISK1", _fx_ram_driver, ram_disk_memory1, buffer1, 512); + status |= fx_media_open(&ram_disk2, "RAM DISK2", _fx_ram_driver, ram_disk_memory2, buffer2, 512); + if (status != FX_SUCCESS) + { + + /* Storage basic test error. */ + printf("ERROR %d\n", __LINE__); + test_control_return(1); + } + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* 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 #%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 device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 2; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_media_flush; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_flush = demo_media_flush; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_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(); + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(ux_test_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main device simulation thread. */ + status = tx_thread_create(&tx_demo_thread_device_simulation, "tx demo device simulation", tx_demo_thread_device_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 21, 21, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + stack_pointer += UX_DEMO_STACK_SIZE; + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static void tx_demo_thread_device_simulation_entry(ULONG arg) +{ + while(1) + { + + /* Run device tasks. */ + ux_system_tasks_run(); + + /* Relinquish to other thread. */ + tx_thread_relinquish(); + } +} + +static ULONG _test_dw_minus(ULONG d0, ULONG d1) +{ + if (d0 >= d1) + return(d0 - d1); + return(d0 + (0xFFFFFFFF - d1)); +} + +static UINT _media_driver_read(FX_MEDIA *media, + VOID (*_media_driver)(FX_MEDIA *), + UCHAR *buffer, ULONG lba, ULONG n_lb) +{ +UINT status; + + if (lba == 0) + { + media->fx_media_driver_logical_sector = lba; + media->fx_media_driver_sectors = n_lb; + media->fx_media_driver_request = FX_DRIVER_BOOT_READ; + media->fx_media_driver_buffer = buffer; + _media_driver(media); + *(buffer) = 0xeb; + *(buffer+1) = 0x3c; + *(buffer+2) = 0x90; + *(buffer+21) = 0xF8; + + *(buffer+24) = 0x01; + *(buffer+26) = 0x10; + *(buffer+28) = 0x01; + + *(buffer+510) = 0x55; + *(buffer+511) = 0xaa; + ux_utility_memory_copy(buffer+0x36,"FAT12",5); + + if (media->fx_media_driver_status != FX_SUCCESS) + { + printf("%s:%d: FX error 0x%x\n", __FILE__, __LINE__, media->fx_media_driver_status); + return(UX_ERROR); + } + + lba++; + n_lb --; + buffer += 512; + } + media->fx_media_driver_logical_sector = lba; + media->fx_media_driver_sectors = n_lb; + media->fx_media_driver_request = FX_DRIVER_READ; + media->fx_media_driver_buffer = buffer; + _media_driver(media); + if (media->fx_media_driver_status != FX_SUCCESS) + { + stepinfo("%s:%d: FX error 0x%x\n", __FILE__, __LINE__, media->fx_media_driver_status); + return(UX_ERROR); + } + return(UX_SUCCESS); +} + +static UINT _media_driver_write(FX_MEDIA *media, + VOID (*_media_driver)(FX_MEDIA *), + UCHAR *buffer, ULONG lba, ULONG n_lb) +{ +UINT status; + + if (lba == 0) + { + media -> fx_media_driver_logical_sector = 0; + media -> fx_media_driver_sectors = 1; + media -> fx_media_driver_request = FX_DRIVER_BOOT_WRITE; + media -> fx_media_driver_buffer = buffer; + _media_driver(media); + + if (media->fx_media_driver_status != FX_SUCCESS) + { + printf("%s:%d: FX error 0x%x\n", __FILE__, __LINE__, media->fx_media_driver_status); + return(UX_ERROR); + } + + lba ++; + n_lb --; + buffer += 512; + } + if (n_lb) + { + media -> fx_media_driver_logical_sector = lba; + media -> fx_media_driver_sectors = n_lb; + media -> fx_media_driver_request = FX_DRIVER_WRITE; + media -> fx_media_driver_buffer = buffer; + _media_driver(media); + + if (media->fx_media_driver_status != FX_SUCCESS) + { + printf("%s:%d: FX error 0x%x\n", __FILE__, __LINE__, media->fx_media_driver_status); + return(UX_ERROR); + } + } + return(UX_SUCCESS); +} + +static UINT _test_host_class_storage_inquiry(UX_HOST_CLASS_STORAGE *storage, + UCHAR flags, ULONG data_length, ULONG cb_length, + UCHAR page_code, UCHAR *response, ULONG response_length) +{ +UINT status; +UCHAR *cbw; +UINT command_length; + + /* Use a pointer for the cbw, easier to manipulate. */ + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + /* Initialize the CBW for this command. */ + _ux_host_class_storage_cbw_initialize(storage, flags, data_length, cb_length); + + /* Prepare the INQUIRY command block. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_INQUIRY; + + /* Store the page code. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_PAGE_CODE) = page_code; + + /* Store the length of the Inquiry Response. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_ALLOCATION_LENGTH) = (UCHAR)response_length; + + /* Send the command to transport layer. */ + status = _ux_host_class_storage_transport(storage, response); + + /* Return completion status. */ + return(status); +} +static UINT test_host_class_storage_inquiry(UX_HOST_CLASS_STORAGE *storage, UCHAR page_code, UCHAR *response, ULONG response_length) +{ + _test_host_class_storage_inquiry(storage, + UX_HOST_CLASS_STORAGE_DATA_IN, + UX_HOST_CLASS_STORAGE_INQUIRY_RESPONSE_LENGTH, + UX_HOST_CLASS_STORAGE_INQUIRY_COMMAND_LENGTH_SBC, + page_code, response, response_length); +} + +static UINT _test_send_cbw_EX(int __line__, ULONG length) +{ + +UX_TRANSFER *transfer_request; +UINT status; +UCHAR *cbw; + + stepinfo(">>>>> %d.%d: CBW\n", __LINE__, __line__); + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + transfer_request -> ux_transfer_request_data_pointer = cbw; + transfer_request -> ux_transfer_request_requested_length = length; + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} +static UINT _test_send_cbw(int __line__) +{ + _test_send_cbw_EX(__line__, UX_HOST_CLASS_STORAGE_CBW_LENGTH); +} + +static UINT _test_transfer_data(int __line__, UCHAR *data, ULONG size, UCHAR do_read) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + stepinfo(">>>>> %d.%d: DATA\n", __LINE__, __line__); + transfer_request = do_read ? + &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request : + &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + transfer_request -> ux_transfer_request_data_pointer = data; + transfer_request -> ux_transfer_request_requested_length = size; + + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_wait_csw_EX(int __line__) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + stepinfo(">>>>> %d.%d: CSW_Ex\n", __LINE__, __line__); + + /* Get the pointer to the transfer request, on the bulk in endpoint. */ + transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + /* Fill in the transfer_request parameters. */ + transfer_request -> ux_transfer_request_data_pointer = (UCHAR *) &storage -> ux_host_class_storage_csw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CSW_LENGTH; + + /* Get the CSW on the bulk in endpoint. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + return(status); + + /* Wait for the completion of the transfer request. */ + status = _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* If OK, we are done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static VOID _test_clear_stall(UCHAR clear_read_stall) +{ + +UX_ENDPOINT *endpoint; + + + endpoint = clear_read_stall ? + storage -> ux_host_class_storage_bulk_in_endpoint : + storage -> ux_host_class_storage_bulk_out_endpoint; + _ux_host_stack_endpoint_reset(endpoint); +} + +static UINT _test_wait_csw(int __line__) +{ +UINT status; + + stepinfo(">>>>> %d.%d: CSW\n", __LINE__, __line__); + status = _test_wait_csw_EX(__LINE__); + if (status == UX_TRANSFER_STALLED) + { + _test_clear_stall(UX_TRUE); + status = _test_wait_csw_EX(__LINE__); + } + return(status); +} + +static UINT _test_request_sense(void) +{ + +UINT status; +UX_TRANSFER *transfer_request; +UCHAR *cbw; +UCHAR *request_sense_response; +ULONG sense_code; +UINT command_length = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_COMMAND_LENGTH_SBC; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + _ux_utility_memory_copy(storage -> ux_host_class_storage_saved_cbw, storage -> ux_host_class_storage_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + _ux_host_class_storage_cbw_initialize(storage, UX_HOST_CLASS_STORAGE_DATA_IN, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_REQUEST_SENSE; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_ALLOCATION_LENGTH) = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH; + request_sense_response = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH); + if (request_sense_response == UX_NULL) + return(UX_MEMORY_INSUFFICIENT); + status = _test_send_cbw(__LINE__); + if (status == UX_SUCCESS) + { + status = _test_transfer_data(__LINE__, request_sense_response, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, UX_TRUE); + if (status == UX_SUCCESS) + { + status = _test_wait_csw(__LINE__); + if (status == UX_SUCCESS) + { + + sense_code = (((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_SENSE_KEY)) & 0x0f) << 16; + sense_code |= ((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE)) << 8; + sense_code |= (ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE_QUALIFIER); + + storage -> ux_host_class_storage_sense_code = sense_code; + } + } + } + _ux_utility_memory_free(request_sense_response); + _ux_utility_memory_copy(storage -> ux_host_class_storage_cbw, storage -> ux_host_class_storage_saved_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + return(status); +} + +typedef struct cbw_read_struct +{ + UCHAR flags_pos; + UCHAR lba_pos; + UCHAR lba_size; + UCHAR len_pos; + UCHAR len_size; +} cbw_read_struct_t; +static cbw_read_struct_t cbw_READ_info[] = +{ + { 1, 2, 2, 4, 1}, + { 1, 2, 4, 7, 2}, + { 1, 2, 4, 6, 4}, + { 1, 2, 8, 10, 4}, + {10, 12, 8, 28, 4} +}; +static UCHAR _read_op(UCHAR op_code) +{ + switch(op_code) + { + case 0x28: return 1; + case 0xA8: return 2; + case 0x88: return 3; + case 0x7F: return 4; + case 0x08: return 0; + default: return 0xFF; + } +} +static void _test_init_cbw_READ_EX( + UCHAR flags, ULONG data_length, + UCHAR op6_10_12_16_32, ULONG lba, ULONG len) +{ +UCHAR *cbw; +UINT command_length; +UCHAR op = _read_op(op6_10_12_16_32); +UINT i; + + + if (op >= 5) + return; + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, flags, data_length, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = op6_10_12_16_32; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + cbw_READ_info[op].flags_pos) = 0; + for (i = cbw_READ_info[op].lba_pos + cbw_READ_info[op].lba_size - 1; i >= cbw_READ_info[op].lba_pos; i --) + { + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + i) = (UCHAR)lba; + lba >>= 8; + } + for (i = cbw_READ_info[op].len_pos + cbw_READ_info[op].len_size - 1; i >= cbw_READ_info[op].len_size; i --) + { + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + i) = (UCHAR)len; + len >>= 8; + } +} +static void _test_init_cbw_READ(UCHAR op6_10_12_16_32, ULONG lba, ULONG len) +{ + _test_init_cbw_READ_EX(0x80, len * 512, op6_10_12_16_32, lba, len); +} + +typedef struct cbw_write_struct +{ + UCHAR flags_pos; + UCHAR lba_pos; + UCHAR lba_size; + UCHAR len_pos; + UCHAR len_size; +} cbw_write_struct_t; +static cbw_write_struct_t cbw_WRITE_info[] = +{ + { 1, 2, 2, 4, 1}, + { 1, 2, 4, 7, 2}, + { 1, 2, 4, 6, 4}, + { 1, 2, 8, 10, 4}, + {10, 12, 8, 28, 4} +}; +static UCHAR _write_op(UCHAR op_code) +{ + switch(op_code) + { + case 0x2A: return 1; + case 0xAA: return 2; + case 0x8A: return 3; + case 0x7F: return 4; + case 0x0A: return 0; + default: return 0xFF; + } +} +static void _test_init_cbw_WRITE_EX(UCHAR flags, ULONG data_length, + UCHAR op6_10_12_16_32, ULONG lba, ULONG len) +{ + +UCHAR *cbw; +UINT command_length; +UCHAR op = _write_op(op6_10_12_16_32); +UINT i; + + + if (op >= 5) + return; + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, flags, data_length, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = op6_10_12_16_32; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + cbw_WRITE_info[op].flags_pos) = 0; + for (i = cbw_WRITE_info[op].lba_pos + cbw_WRITE_info[op].lba_size - 1; i >= cbw_WRITE_info[op].lba_pos; i --) + { + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + i) = (UCHAR)lba; + lba >>= 8; + } + for (i = cbw_WRITE_info[op].len_pos + cbw_WRITE_info[op].len_size - 1; i >= cbw_WRITE_info[op].len_size; i --) + { + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + i) = (UCHAR)len; + len >>= 8; + } +} +static void _test_init_cbw_WRITE(UCHAR op6_10_12_16_32, ULONG lba, ULONG len) +{ + _test_init_cbw_WRITE_EX(0x00, len * 512, op6_10_12_16_32, lba, len); +} + +static void _test_init_cbw_REQUEST_SENSE(ULONG data_length) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0x80, data_length, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_REQUEST_SENSE; +} + +static void _test_init_cbw_TEST_READY(ULONG data_length) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0x00, data_length, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_TEST_READY; +} + +static void _test_init_cbw_FORMAT_UNIT(void) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, 0, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_FORMAT; +} + +static void _test_init_cbw_START_STOP(void) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, 0, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_START_STOP; +} + +static void _test_init_cbw_VERIFY(void) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, 0, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_VERIFY; +} + +static void _test_init_cbw_MODE_SELECT(ULONG data_length) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, data_length, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SELECT; +} + +static void _test_init_cbw_MODE_SENSE(UCHAR op6, UCHAR page_code, ULONG buffer_length) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0x80, buffer_length, command_length); + if (op6) + { + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE_SHORT; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PARAMETER_LIST_LENGTH_6) = (UCHAR)buffer_length; + } + else + { + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE; + _ux_utility_short_put_big_endian(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PARAMETER_LIST_LENGTH_10, (USHORT)buffer_length); + } + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PC_PAGE_CODE) = page_code; +} + +static void _test_init_cbw_SYNCHRONIZE_CACHE(UCHAR op16, UCHAR immed, ULONG lba, ULONG nb_blocks) +{ + +UCHAR *cbw; +UINT command_length; + + + (void)op16; + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, 0, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_SYNCHRONIZE_CACHE_FLAGS) = immed ? UX_SLAVE_CLASS_STORAGE_SYNCHRONIZE_CACHE_FLAGS_IMMED : 0; + _ux_utility_long_put_big_endian(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_SYNCHRONIZE_CACHE_LBA, lba); + _ux_utility_short_put_big_endian(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_SYNCHRONIZE_CACHE_NUMBER_OF_BLOCKS, (USHORT)nb_blocks); +} + +static void _test_init_cbw_PREVENT_ALLOW_MEDIA_REMOVAL(void) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, 0, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_PREVENT_ALLOW_MEDIA_REMOVAL; +} + + +static void _msc_cbw_fail_cases_test(const char* __file__, int __line__) +{ +UINT status; +UCHAR *cbw; + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + stepinfo("\n%s:%d:MSC CBW fail tests\n", __file__, __line__); + + stepinfo(">>>>>>>>>>>>>>>> Test VERIFY CBW length error\n"); + _test_init_cbw_VERIFY(); + status = _test_send_cbw_EX(__LINE__, UX_HOST_CLASS_STORAGE_CBW_LENGTH - 1); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + stepinfo(">>>>>>>>>>>>>>>> Test VERIFY CBW LUN error\n"); + _test_init_cbw_VERIFY(); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_LUN + 0) = 0xFF; + status = _test_send_cbw_EX(__LINE__, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + stepinfo(">>>>>>>>>>>>>>>> Test VERIFY CBW Signature error\n"); + _test_init_cbw_VERIFY(); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_SIGNATURE + 0) = 0xFF; + status = _test_send_cbw_EX(__LINE__, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + stepinfo(">>>>>>>>>>>>>>>> Test VERIFY CBW CBW_CB length error\n"); + _test_init_cbw_VERIFY(); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB_LENGTH + 0) = 0; + status = _test_send_cbw_EX(__LINE__, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + _test_clear_stall(UX_TRUE); + _test_init_cbw_VERIFY(); + status = _test_send_cbw_EX(__LINE__, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + stepinfo(">>>>>>>>>>>>>>>> Test CBW CMD unknown error\n"); + _test_init_cbw_VERIFY(); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = 0xFF; + status = _test_send_cbw_EX(__LINE__, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); +} + + +static void _msc_get_max_lun_cases_test(const char* __file__, int __line__) +{ +UINT status; +UX_DEVICE *device; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; + + stepinfo("\n%s:%d:MSC GET_MAX_LUN tests\n", __file__, __line__); + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: device_get fail\n", __LINE__, __line__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Send transfer request - GetMaxLun. */ + transfer_request -> ux_transfer_request_data_pointer = UX_NULL; + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_SLAVE_CLASS_STORAGE_GET_MAX_LUN; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceNumber; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS && status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Invalid wValue. */ + transfer_request -> ux_transfer_request_value = 1; + transfer_request -> ux_transfer_request_index = storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceNumber; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Invalid wIndex. */ + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceNumber + 1; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Send transfer request - UX_SLAVE_CLASS_STORAGE_RESET. */ + transfer_request -> ux_transfer_request_function = UX_SLAVE_CLASS_STORAGE_RESET; + + /* Invalid wValue. */ + transfer_request -> ux_transfer_request_value = 1; + transfer_request -> ux_transfer_request_index = storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceNumber; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Invalid wIndex. */ + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceNumber + 1; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Invalid wLength. */ + transfer_request -> ux_transfer_request_data_pointer = (UCHAR*)&status; + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceNumber; + transfer_request -> ux_transfer_request_requested_length = 1; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void _msc_inquiry_cases_test(const char* __file__, int __line__) +{ +UINT status; +UX_SLAVE_DEVICE *slave_device; +UX_SLAVE_CLASS *slave_class; +UX_SLAVE_CLASS_STORAGE *slave_storage; + + stepinfo("\n%s:%d:MSC INQUIRY tests\n", __file__, __line__); + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(standard)\n"); + status = test_host_class_storage_inquiry(storage, 0x00, buffer, 64); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(standard, UX_SLAVE_CLASS_STORAGE_MEDIA_CDROM)\n"); + slave_device = &_ux_system_slave->ux_system_slave_device; + slave_class = _ux_system_slave->ux_system_slave_interface_class_array[0]; + slave_storage = (UX_SLAVE_CLASS_STORAGE *)slave_class->ux_slave_class_instance; + slave_storage -> ux_slave_class_storage_lun[0].ux_slave_class_storage_media_type = UX_SLAVE_CLASS_STORAGE_MEDIA_CDROM; + status = test_host_class_storage_inquiry(storage, 0x00, buffer, 64); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(unknown page code)\n"); + status = test_host_class_storage_inquiry(storage, 0xEF, buffer, 64); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(big buffer)\n"); + status = _test_host_class_storage_inquiry(storage, 0x80, + 64, + UX_HOST_CLASS_STORAGE_INQUIRY_COMMAND_LENGTH_SBC, + 0x00, buffer, 64); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(Hi <> Do)\n"); + status = _test_host_class_storage_inquiry(storage, 0x00, + UX_HOST_CLASS_STORAGE_INQUIRY_RESPONSE_LENGTH, + UX_HOST_CLASS_STORAGE_INQUIRY_COMMAND_LENGTH_SBC, + 0x00, buffer, UX_HOST_CLASS_STORAGE_INQUIRY_RESPONSE_LENGTH); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(Hi <> Do)\n"); + status = _test_host_class_storage_inquiry(storage, 0x00, + 0, + UX_HOST_CLASS_STORAGE_INQUIRY_COMMAND_LENGTH_SBC, + 0x00, buffer, UX_HOST_CLASS_STORAGE_INQUIRY_RESPONSE_LENGTH); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } +} + +static void _msc_read_cases_test(const char* __file__, int __line__) +{ +UINT status; + + stepinfo("\n%s:%d:MSC READ tests\n", __file__, __line__); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_READ32 - success\n"); + _test_init_cbw_READ(UX_SLAVE_CLASS_STORAGE_SCSI_READ32, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 512, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_READ16 - status fail\n"); + ram_disk_status = UX_ERROR; + _test_init_cbw_READ(UX_SLAVE_CLASS_STORAGE_SCSI_READ16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 512, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + ram_disk_status = UX_SUCCESS; + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_READ16 - transfer fail\n"); + _test_init_cbw_READ(UX_SLAVE_CLASS_STORAGE_SCSI_READ16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + ux_test_dcd_sim_slave_set_actions(fail_on_bulkin); + status = _test_transfer_data(__LINE__, buffer, 512, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_READ16 - Case(7) Hi < Di\n"); + _test_init_cbw_READ_EX(0x80, 0, UX_SLAVE_CLASS_STORAGE_SCSI_READ16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 512, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_READ16 - Case(8) Hi <> Do\n"); + _test_init_cbw_READ_EX(0x00, 512, UX_SLAVE_CLASS_STORAGE_SCSI_READ16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 512, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_READ16 - Case(5) Hi > Di\n"); + _test_init_cbw_READ_EX(0x80, 1024, UX_SLAVE_CLASS_STORAGE_SCSI_READ16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 1024, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); +} + +static void _msc_write_cases_test(const char* __file__, int __line__) +{ +UINT status; +UX_SLAVE_DEVICE *slave_device; +UX_SLAVE_CLASS *slave_class; +UX_SLAVE_CLASS_STORAGE *slave_storage; + + stepinfo("\n%s:%d:MSC WRITE tests\n", __file__, __line__); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_WRITE32 - success\n"); + _test_init_cbw_WRITE(UX_SLAVE_CLASS_STORAGE_SCSI_WRITE32, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 512, UX_FALSE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16 - status fail\n"); + ram_disk_status = UX_ERROR; + _test_init_cbw_WRITE(UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 512, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + ram_disk_status = UX_SUCCESS; + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16 - transfer fail\n"); + _test_init_cbw_WRITE(UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + ux_test_dcd_sim_slave_set_actions(fail_on_bulkout); + status = _test_transfer_data(__LINE__, buffer, 512, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + printf(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16 - WP fail\n"); + slave_device = &_ux_system_slave->ux_system_slave_device; + slave_class = _ux_system_slave->ux_system_slave_interface_class_array[0]; + slave_storage = (UX_SLAVE_CLASS_STORAGE *)slave_class->ux_slave_class_instance; + slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_read_only_flag = UX_TRUE; + _test_init_cbw_WRITE(UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 512, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_read_only_flag = UX_FALSE; + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16 - Case (3) Hn < Do\n"); + _test_init_cbw_WRITE_EX(0x00, 0, UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + #if 0 /* Host expect no data. */ + status = _test_transfer_data(__LINE__, buffer, 512, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + #endif + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16 - Case (8) Hi <> Do\n"); + _test_init_cbw_WRITE_EX(0x80, 512, UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 512, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16 - Case (9) Ho > Do\n"); + _test_init_cbw_WRITE_EX(0x00, 1024, UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 1024, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); +} + +static void _msc_request_sense_cases_test(const char* __file__, int __line__) +{ +UINT status; + + stepinfo("\n%s:%d:MSC REQUEST_SENSE tests\n", __file__, __line__); + + _test_init_cbw_REQUEST_SENSE(64); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 64, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); +} + +static void _msc_test_ready_cases_test(const char* __file__, int __line__) +{ +UINT status; + + stepinfo("\n%s:%d:MSC UNIT_READY tests\n", __file__, __line__); + + _test_init_cbw_TEST_READY(64); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 64, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); +} + +static void _msc_format_unit_cases_test(const char* __file__, int __line__) +{ +UINT status; + + stepinfo("\n%s:%d:MSC FORMAT_UNIT tests\n", __file__, __line__); + + _test_init_cbw_FORMAT_UNIT(); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + #if 0 /* Host expects no data. */ + status = _test_transfer_data(__LINE__, "test dead beef", 15, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + #endif + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_request_sense(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void _msc_start_stop_cases_test(const char* __file__, int __line__) +{ +UINT status; + + stepinfo("\n%s:%d:MSC START_STOP tests\n", __file__, __line__); + + _test_init_cbw_START_STOP(); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void _msc_verify_cases_test(const char* __file__, int __line__) +{ +UINT status; + + stepinfo("\n%s:%d:MSC VERIFY tests\n", __file__, __line__); + + _test_init_cbw_VERIFY(); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void _msc_mode_sense_cases_test(const char* __file__, int __line__) +{ +UINT status; +UX_SLAVE_DEVICE *slave_device; +UX_SLAVE_CLASS *slave_class; +UX_SLAVE_CLASS_STORAGE *slave_storage; + + stepinfo("\n%s:%d:MSC MODE_SENSE tests\n", __file__, __line__); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(PAGE_CODE_CDROM):\n"); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(PAGE_CODE_CDROM) - 128B\n"); + _test_init_cbw_MODE_SENSE(UX_FALSE, UX_SLAVE_CLASS_STORAGE_MMC2_PAGE_CODE_CDROM, 128); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(PAGE_CODE_CDROM) - 74B\n"); + _test_init_cbw_MODE_SENSE(UX_TRUE, UX_SLAVE_CLASS_STORAGE_MMC2_PAGE_CODE_CDROM, 74); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 74, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Change read_only_flag */ + slave_device = &_ux_system_slave->ux_system_slave_device; + slave_class = _ux_system_slave->ux_system_slave_interface_class_array[0]; + slave_storage = (UX_SLAVE_CLASS_STORAGE *)slave_class->ux_slave_class_instance; + slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_read_only_flag = UX_TRUE; + + /************ UX_SLAVE_CLASS_STORAGE_PAGE_CODE_CACHE ****************/ + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(PAGE_CODE_CACHE):\n"); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(PAGE_CODE_CACHE) - 128B\n"); + _test_init_cbw_MODE_SENSE(UX_FALSE, UX_SLAVE_CLASS_STORAGE_PAGE_CODE_CACHE, 128); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(PAGE_CODE_CACHE) - 24B\n"); + _test_init_cbw_MODE_SENSE(UX_TRUE, UX_SLAVE_CLASS_STORAGE_PAGE_CODE_CACHE, 24); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 24, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(PAGE_CODE_CACHE) - 24B\n"); + slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_flush = demo_media_flush; + _test_init_cbw_MODE_SENSE(UX_TRUE, UX_SLAVE_CLASS_STORAGE_PAGE_CODE_CACHE, 24); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 24, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /************ UX_SLAVE_CLASS_STORAGE_PAGE_CODE_IEC ****************/ + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(PAGE_CODE_IEC) - 128B\n"); + _test_init_cbw_MODE_SENSE(UX_FALSE, UX_SLAVE_CLASS_STORAGE_PAGE_CODE_IEC, 128); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(PAGE_CODE_IEC) - 16B\n"); + _test_init_cbw_MODE_SENSE(UX_TRUE, UX_SLAVE_CLASS_STORAGE_PAGE_CODE_IEC, 16); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 16, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /************ 0x3F ****************/ + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(0x3F) - 128B\n"); + _test_init_cbw_MODE_SENSE(UX_FALSE, 0x3F, 128); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /************ 0x3F ****************/ + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(0x3F) - %dB\n", + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE + 8); + _test_init_cbw_MODE_SENSE(UX_FALSE, 0x3F, UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE + 8); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void _msc_mode_select_cases_test(const char* __file__, int __line__) +{ +UINT status; + + stepinfo("\n%s:%d:MSC MODE_SELECT tests\n", __file__, __line__); + + _test_init_cbw_MODE_SELECT(15); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, "test dead beef", 15, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_request_sense(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void _msc_synchronous_cache_cases_test(const char* __file__, int __line__) +{ +UINT status; +UX_SLAVE_DEVICE *slave_device; +UX_SLAVE_CLASS *slave_class; +UX_SLAVE_CLASS_STORAGE *slave_storage; + + stepinfo("\n%s:%d:MSC SYNCHRONOUS_CACHE tests\n", __file__, __line__); + + slave_device = &_ux_system_slave->ux_system_slave_device; + slave_class = _ux_system_slave->ux_system_slave_interface_class_array[0]; + slave_storage = (UX_SLAVE_CLASS_STORAGE *)slave_class->ux_slave_class_instance; + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE no CB - success\n"); + slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_flush = UX_NULL; + slave_storage->ux_slave_class_storage_lun[1].ux_slave_class_storage_media_flush = UX_NULL; + _test_init_cbw_SYNCHRONIZE_CACHE(UX_FALSE, UX_FALSE, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE - success\n"); + slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_flush = demo_media_flush; + slave_storage->ux_slave_class_storage_lun[1].ux_slave_class_storage_media_flush = demo_media_flush; + _test_init_cbw_SYNCHRONIZE_CACHE(UX_FALSE, UX_FALSE, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE - status fail\n"); + _test_init_cbw_SYNCHRONIZE_CACHE(UX_FALSE, UX_FALSE, 0, 1); + ram_disk_status = UX_ERROR; + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw_EX(__LINE__); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw_EX(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_request_sense(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + ram_disk_status = UX_SUCCESS; + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE - flush fail\n"); + _test_init_cbw_SYNCHRONIZE_CACHE(UX_FALSE, UX_FALSE, 0, 1); + ram_disk_flush_status = UX_STATE_ERROR; + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw_EX(__LINE__); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw_EX(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + ram_disk_flush_status = UX_STATE_NEXT; +} + +static void _msc_prevent_allow_removal_cases_test(const char* __file__, int __line__) +{ +UINT status; + + stepinfo("\n%s:%d:MSC PREVENT_ALLOW_MEDIA_REMOVAL tests\n", __file__, __line__); + + _test_init_cbw_PREVENT_ALLOW_MEDIA_REMOVAL(); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + + +static void _msc_media_read_test(const char* __file__, int __line__) +{ +UINT status; +ULONG test_n; +ULONG test_size[] = { + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 2 / 512, + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 3 / 512, + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 2 / 512 + 1}; + + stepinfo("\n%s:%d:MSC Media Read tests\n", __file__, __line__); + + if (media == UX_NULL || media -> fx_media_id == 0) + { + printf("ERROR %d: media error\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Disk read(1) test\n"); + { + status = fx_media_read(media, 48, buffer); + if (status != FX_SUCCESS) + { + printf("ERROR %d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + } + + /* Disk read multiple test. */ + for (test_n = 0; test_n < sizeof(test_size)/sizeof(test_size[0]); test_n ++) + { + + stepinfo(">>>>>>>>>>>> Disk read(%d) test\n", test_size[test_n]); + status = _media_driver_read(media, _ux_host_class_storage_driver_entry, + buffer, 0, test_size[test_n]); + if (status != UX_SUCCESS) + { + printf("ERROR %d.%ld: 0x%x\n", __LINE__, test_n, status); + test_control_return(1); + } + } +} + +static void _msc_media_write_read_test(const char* __file__, int __line__) +{ +UINT status; +ULONG test_n; +INT i; +ULONG test_size[] = { + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 2 / 512, + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 3 / 512, + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 2 / 512 + 1}; + + stepinfo("\n%s:%d:MSC Media Write & Read tests\n", __file__, __line__); + + /* Check if media still available. */ + if (media == UX_NULL || media -> fx_media_id == 0) + { + printf("ERROR %d: media error\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Disk write(1)/read(1) test\n"); + { + for(i = 0; i < 512; i ++) + buffer[i] = i; + status = fx_media_write(media, 48, buffer); + if (status != FX_SUCCESS) + { + printf("ERROR %d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_utility_memory_set(buffer, 0x00, 512); + status = fx_media_read(media, 48, buffer); + if (status != FX_SUCCESS) + { + printf("ERROR %d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + for (i = 0; i < 512; i ++) + { + if (buffer[i] != (UCHAR)i) + { + printf("ERROR %d: %d <> %d\n", __LINE__, i, buffer[i]); + test_control_return(1); + } + } + } + + /* Disk write/read multiple test. */ + for (test_n = 0; test_n < sizeof(test_size)/sizeof(test_size[0]); test_n ++) + { + stepinfo(">>>>>>>>>>>> Disk write(%ld)/read(%ld) test\n", + test_size[test_n], test_size[test_n]); + + for(i = 0; i < test_size[test_n] * 512; i ++) + buffer[i] = (UCHAR)(i + (i >> 8)); + status = _media_driver_write(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size[test_n]); + if (status != FX_SUCCESS) + { + printf("ERROR %d.%ld: 0x%x\n", __LINE__, test_n, status); + test_control_return(1); + } + _ux_utility_memory_set(buffer, 0x00, test_size[test_n] * 512); + status = _media_driver_read(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size[test_n]); + if (status != FX_SUCCESS) + { + printf("ERROR %d.%ld: 0x%x\n", __LINE__, test_n, status); + test_control_return(1); + } + for (i = 0; i < 512; i ++) + { + if (buffer[i] != (UCHAR)(i + (i >> 8))) + { + printf("ERROR %d: %d <> %d\n", __LINE__, i, buffer[i]); + test_control_return(1); + } + } + } +} + +static void _msc_enumeration_test(const char* __file__, int __line__, unsigned option) +{ +UINT status; +ULONG mem_free; +ULONG test_n; + + stepinfo("\n%s:%d:MSC Enumeration tests\n", __file__, __line__); + + stepinfo(">>>>>>>>>>>> Enumeration information collection\n"); + { + + /* Test disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check connection. */ + status = host_storage_instance_get(0); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_count_reset(); + ux_test_utility_sim_mutex_create_count_reset(); + ux_test_utility_sim_sem_create_count_reset(); + ux_test_utility_sim_sem_get_count_reset(); + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + + /* Save free memory usage. */ + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Check connection. */ + status = host_storage_instance_get(50); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Log create counts for further tests. */ + rsc_enum_mutex_usage = rsc_mutex_on_set_cfg; + rsc_enum_sem_usage = rsc_sem_on_set_cfg; + rsc_enum_mem_alloc_count = rsc_mem_alloc_cnt_on_set_cfg; + /* Log create counts when instances active for further tests. */ + rsc_storage_mutex_usage = ux_test_utility_sim_mutex_create_count() - rsc_enum_mutex_usage; + rsc_storage_sem_usage = ux_test_utility_sim_sem_create_count() - rsc_enum_sem_usage; + rsc_storage_mem_alloc_count = ux_test_utility_sim_mem_alloc_count() - rsc_enum_mem_alloc_count; + + /* Lock log base for tests. */ + ux_test_utility_sim_mem_alloc_log_lock(); + + stepinfo("enum mem: %ld\n", rsc_enum_mem_alloc_count); + stepinfo("storage mem : %ld\n", rsc_storage_mem_alloc_count); + stepinfo("mem free: %ld, %ld\n", _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); + } + + /* Simulate detach and attach for FS enumeration, + and check if there is memory error in normal enumeration. + */ + if (option & (1u)) + { + stepinfo(">>>>>>>>>>>> Enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < 3; test_n++) + { + stepinfo("%4ld / 2\n", test_n); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check */ + if (host_storage_instance_get(0) == UX_SUCCESS) + { + + printf("ERROR #%d.%ld: Disconnect fail\n", __LINE__, test_n); + test_control_return(1); + } + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Wait and break on error. */ + error_callback_counter = 0; + ux_test_breakable_sleep( + (UX_MS_TO_TICK_NON_ZERO(UX_RH_ENUMERATION_RETRY_DELAY) + + UX_MS_TO_TICK_NON_ZERO(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY)) * + 3, + sleep_break_on_connect); + + /* Check */ + if (host_storage_instance_get(0) != UX_SUCCESS) + { + + printf("ERROR #%d.%ld: Enumeration fail\n", __LINE__, test_n); + test_control_return(1); + } + } + stepinfo("\n"); + } + + /* Simulate detach and attach for FS enumeration, + and test possible memory allocation error handlings. + */ + if (option & (2u)) + { + if (rsc_storage_mem_alloc_count) stepinfo(">>>>>>>>>>>> Memory errors enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_storage_mem_alloc_count; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_storage_mem_alloc_count - 1); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check */ + if (host_storage_instance_get(0) == UX_SUCCESS) + { + + printf("ERROR #%d.%ld: Disconnect fail\n", __LINE__, test_n); + test_control_return(1); + } + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Set memory error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n + rsc_enum_mem_alloc_count); + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on errors. */ + ux_test_breakable_sleep(100, sleep_break_on_error); + + /* Check error */ + if (host_storage_instance_get(0) == UX_SUCCESS) + { + + /* Could be media errors, + in this case instance is ready, + check error trap. */ + if (error_callback_counter == 0) + { + printf("ERROR #%d.%ld: device detected when there is memory error\n", __LINE__, test_n); + test_control_return(1); + } + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + } + ux_test_utility_sim_mem_alloc_error_generation_stop(); + if (rsc_storage_mem_alloc_count) stepinfo("\n"); + } +} + +static void _msc_media_write_read_misc_test(const char* __file__, int __line__) +{ +UINT status; +UINT test_size = UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 3 / 512; +UINT test_n; +ULONG test_start; +ULONG test_ticks; +INT i; + + stepinfo("\n%s:%d:MSC Media Read tests\n", __file__, __line__); + + if (media == UX_NULL || media -> fx_media_id == 0) + { + printf("ERROR %d.%d: media error\n", __LINE__, __line__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Disk read(%d) test - tick obtain\n", test_size); + test_start = tx_time_get(); + status = _media_driver_read(media, _ux_host_class_storage_driver_entry, + buffer, 0, test_size); + test_ticks = _test_dw_minus(tx_time_get(), test_start); + if (status != UX_SUCCESS) + { + printf("ERROR %d.%d: 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + test_ticks /= 3; + stepinfo(" :: Buffer XFR time: %ld ticks\n", test_ticks); + + stepinfo(">>>>>>>>>>>> Disk write/read(%d) test - slow disk write/read\n", test_size); + ram_disk_rw_wait_delay = ((test_ticks + 1) >> 1) + 1; + for(test_n = 0; test_n < 4; test_n ++) + { + stepinfo(">>>>>>>>>>>> Disk write/read(%d) test - disk write/read wait %ld\n", + test_size, ram_disk_rw_wait_delay); + for(i = 0; i < test_size * 512; i ++) + buffer[i] = (UCHAR)(i + (i >> 8)); + ram_disk_rw_wait_start = tx_time_get(); + status = _media_driver_write(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size); + if (status != FX_SUCCESS) + { + printf("ERROR %d.%d.%d: 0x%x\n", __LINE__, __line__, test_n, status); + test_control_return(1); + } + _ux_utility_memory_set(buffer, 0x00, test_size * 512); + ram_disk_rw_wait_start = tx_time_get(); + status = _media_driver_read(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size); + if (status != FX_SUCCESS) + { + printf("ERROR %d.%d.%d: 0x%x\n", __LINE__, __line__, test_n, status); + test_control_return(1); + } + for (i = 0; i < 512; i ++) + { + if (buffer[i] != (UCHAR)(i + (i >> 8))) + { + printf("ERROR %d.%d.%d: %d <> %d\n", __LINE__, __line__, test_n, i, buffer[i]); + test_control_return(1); + } + } + ram_disk_rw_wait_delay <<= 1; + } + + stepinfo(">>>>>>>>>>>> Disk read(%d) test - USB fail while disk waiting\n", test_size); + ram_disk_rw_wait_start = tx_time_get(); + ram_disk_rw_count = 0; + ram_disk_rw_fail_mode = 0x81; + ram_disk_rw_fail_after = 1; + status = _media_driver_read(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size); + if (status == UX_SUCCESS) + { + printf("ERROR %d.%d: 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Disk write(%d) test - USB fail while disk waiting\n", test_size); + ram_disk_rw_wait_start = tx_time_get(); + ram_disk_rw_count = 0; + ram_disk_rw_fail_mode = 0x82; + ram_disk_rw_fail_after = 0; + status = _media_driver_write(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size); + if (0 /*status == UX_SUCCESS*/) + { + printf("ERROR %d.%d: 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + + /* Restore: no disk wait delay. */ + ram_disk_rw_fail_after = 0xFFFFFFFF; + ram_disk_rw_wait_delay = 0; +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; + + + /* Find the storage class. */ + status = host_storage_instance_get(800); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> MSC Error & CV cases test\n"); + +#ifndef UX_STANDALONE + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)storage->ux_host_class_storage_class->ux_host_class_ext)->ux_host_class_thread); +#endif + + /* All tests are on LUN 0. */ + storage->ux_host_class_storage_lun = 0; + + _msc_cbw_fail_cases_test(__FILE__, __LINE__); + + _msc_get_max_lun_cases_test(__FILE__, __LINE__); + _msc_inquiry_cases_test(__FILE__, __LINE__); + _msc_read_cases_test(__FILE__, __LINE__); + _msc_write_cases_test(__FILE__, __LINE__); + _msc_request_sense_cases_test(__FILE__, __LINE__); + _msc_test_ready_cases_test(__FILE__, __LINE__); + _msc_format_unit_cases_test(__FILE__, __LINE__); + _msc_start_stop_cases_test(__FILE__, __LINE__); + _msc_verify_cases_test(__FILE__, __LINE__); + _msc_mode_sense_cases_test(__FILE__, __LINE__); + _msc_mode_select_cases_test(__FILE__, __LINE__); + _msc_synchronous_cache_cases_test(__FILE__, __LINE__); + _msc_prevent_allow_removal_cases_test(__FILE__, __LINE__); + +#ifndef UX_STANDALONE + /* Resume the class driver thread. */ + _ux_utility_thread_resume(&((UX_HOST_CLASS_STORAGE_EXT*)storage->ux_host_class_storage_class->ux_host_class_ext)->ux_host_class_thread); +#endif + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +static UCHAR lun_init_done[2] = {0, 0}; +UINT status; +ULONG mstatus = UX_SLAVE_CLASS_STORAGE_SENSE_KEY_NO_SENSE; + + + (void)storage; + (void)media_id; + + if (ram_disk_status) + { + status = ram_disk_status; + if (media_status) + *media_status = ram_disk_media_status; + ram_disk_status = UX_SUCCESS; + ram_disk_status_sent = UX_TRUE; + return(status); + } + + if (lun > 1) + status = (UX_ERROR); + else if (lun_init_done[lun] > 0) + status = (UX_SUCCESS); + else + { + lun_init_done[lun] ++; + mstatus = UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8); + status = (UX_ERROR); + } + + if (media_status) + *media_status = mstatus; + + return status; +} + +static UINT demo_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + +UINT status = 0; + + /* Abort. */ + if (data_pointer == UX_NULL) + { + ram_disk_rw_wait_state = 0; + return(UX_STATE_NEXT); + } + + /* Media RW fail simulation. */ + if (ram_disk_rw_fail_after < 0xFFFFFFFF) + { + ram_disk_rw_count ++; + if (ram_disk_rw_count >= ram_disk_rw_fail_after) + { + if (ram_disk_rw_fail_mode_one_shot()) + { + ram_disk_rw_fail_after = 0xFFFFFFFF; + ram_disk_rw_count = 0; + } + if (ram_disk_rw_fail_mode_bulk_in()) + ux_test_dcd_sim_slave_set_actions(fail_on_bulkin); + else if (ram_disk_rw_fail_mode_bulk_out()) + ux_test_dcd_sim_slave_set_actions(fail_on_bulkout); + else if (ram_disk_rw_fail_mode_disk()) + { + *media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x02,0x54,0x00); + return(UX_STATE_ERROR); + } + } + } + + /* Media RW wait simulation. */ + if (ram_disk_rw_wait_delay) + { + if (_test_dw_minus(tx_time_get(), ram_disk_rw_wait_start) < ram_disk_rw_wait_delay) + { + ram_disk_rw_wait_state = 1; + return(UX_STATE_WAIT); + } + ram_disk_rw_wait_state = 0; + ram_disk_rw_wait_start = tx_time_get(); + } + + status = _media_driver_read(ram_disks[lun], _fx_ram_driver, data_pointer, lba, number_blocks); + if (status != UX_SUCCESS) + { + *media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x02,0x54,0x00); + return(UX_STATE_ERROR); + } + return(UX_STATE_NEXT); +} + +static UINT demo_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + +UINT status = 0; + + /* Abort. */ + if (data_pointer == UX_NULL) + { + ram_disk_rw_wait_state = 0; + return(UX_STATE_NEXT); + } + + /* Media RW fail simulation. */ + if (ram_disk_rw_fail_after < 0xFFFFFFFF) + { + ram_disk_rw_count ++; + if (ram_disk_rw_count >= ram_disk_rw_fail_after) + { + if (ram_disk_rw_fail_mode_one_shot()) + { + ram_disk_rw_fail_after = 0xFFFFFFFF; + ram_disk_rw_count = 0; + } + if (ram_disk_rw_fail_mode_bulk_in()) + ux_test_dcd_sim_slave_set_actions(fail_on_bulkin); + else if (ram_disk_rw_fail_mode_bulk_out()) + ux_test_dcd_sim_slave_set_actions(fail_on_bulkout); + else if (ram_disk_rw_fail_mode_disk()) + { + *media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x02,0x54,0x00); + return(UX_STATE_ERROR); + } + } + } + /* Media RW wait simulation. */ + if (ram_disk_rw_wait_delay) + { + if (_test_dw_minus(tx_time_get(), ram_disk_rw_wait_start) < ram_disk_rw_wait_delay) + { + ram_disk_rw_wait_state = 1; + return(UX_STATE_WAIT); + } + ram_disk_rw_wait_state = 0; + ram_disk_rw_wait_start = tx_time_get(); + } + + status = _media_driver_write(ram_disks[lun], _fx_ram_driver, data_pointer, lba, number_blocks); + if (status != UX_SUCCESS) + { + *media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x02,0x54,0x00); + return(UX_STATE_ERROR); + } + return(UX_STATE_NEXT); +} + +static UINT demo_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)number_blocks; + (void)lba; + (void)media_status; + + if (lun > 1) + return UX_STATE_ERROR; + + ram_disk_flush = UX_TRUE; + return ram_disk_flush_status; +} + +static UINT ux_test_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + + switch(event) + { + + case UX_DEVICE_INSERTION: + break; + + case UX_DEVICE_REMOVAL: + break; + +#if defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + case UX_STORAGE_MEDIA_INSERTION: + /* keep using first media. */ + if (_ux_host_class_storage_media_index((UX_HOST_CLASS_STORAGE_MEDIA*)inst) == 0) + { + _ux_host_class_storage_media_insert((UX_HOST_CLASS_STORAGE_MEDIA*)inst, 1); + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA*)inst; + media = _ux_host_class_storage_media_fx_media((UX_HOST_CLASS_STORAGE_MEDIA*)inst); + } + break; + + case UX_STORAGE_MEDIA_REMOVAL: + if (_ux_host_class_storage_media_index((UX_HOST_CLASS_STORAGE_MEDIA*)inst) == 0) + { + _ux_host_class_storage_media_remove((UX_HOST_CLASS_STORAGE_MEDIA*)inst); + storage_media = UX_NULL; + media = UX_NULL; + } + break; +#endif + + default: + break; + } + + return 0; +} + diff --git a/test/regression/usbx_standalone_device_storage_read_write_test.c b/test/regression/usbx_standalone_device_storage_read_write_test.c new file mode 100644 index 00000000..5bc6a646 --- /dev/null +++ b/test/regression/usbx_standalone_device_storage_read_write_test.c @@ -0,0 +1,2931 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_stack.h" +#include "ux_device_class_storage.h" + +#include "ux_host_stack.h" +#include "ux_host_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#define _storage_media_is_mounted() (global_storage_media->ux_host_class_storage_media_status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED) +#if defined(UX_HOST_CLASS_STORAGE_NO_FILEX) +FX_MEDIA *_ux_host_class_storage_driver_media(INT i); +VOID _ux_host_class_storage_driver_entry(FX_MEDIA *media); +VOID _ux_host_class_storage_media_insert(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG format_open); +VOID _ux_host_class_storage_media_remove(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +INT _ux_host_class_storage_media_index(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +FX_MEDIA *_ux_host_class_storage_media_fx_media(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +UCHAR *_ux_host_class_storage_media_fx_media_memory(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); + +#endif + +/* Define constants. */ +#define UX_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 3) + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ +VOID _fx_ram_driver(FX_MEDIA *media_ptr); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_device_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); +static void tx_demo_thread_device_simulation_entry(ULONG); + +static UINT ux_test_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst); + +static UINT demo_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +static FX_MEDIA *media; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk1; +static FX_MEDIA ram_disk2; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static UCHAR buffer1[512]; +static UCHAR buffer2[512]; + +static FX_MEDIA *ram_disks[] = {&ram_disk1, &ram_disk2}; +static UCHAR *buffers[] = {buffer1, buffer2}; +static CHAR *ram_disk_memory[] = { ram_disk_memory1, ram_disk_memory2 }; + +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static ULONG ram_disk_rw_fail_mode = 0; /* 1: BulkIN, 2: BulkOUT, 0: DISK. 0x80: once */ +#define ram_disk_rw_fail_mode_bulk_in() ((ram_disk_rw_fail_mode & 0x7F) == 1) +#define ram_disk_rw_fail_mode_bulk_out() ((ram_disk_rw_fail_mode & 0x7F) == 2) +#define ram_disk_rw_fail_mode_disk() ((ram_disk_rw_fail_mode & 0x7F) == 0) +#define ram_disk_rw_fail_mode_one_shot() ((ram_disk_rw_fail_mode & 0x80) > 0) +static ULONG ram_disk_rw_fail_after = 0xFFFFFFFFu; +static ULONG ram_disk_rw_count = 0; +static ULONG ram_disk_rw_wait_delay = 0; +static ULONG ram_disk_rw_wait_start = 0; +static UCHAR ram_disk_rw_wait_state = 0;/* 0: idle, 1: wait */ + +static CHAR ram_disk_flush = 0; +static UINT ram_disk_flush_status = UX_STATE_NEXT; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00 + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x02, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x02, 0x00 + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + + +static UX_TEST_HCD_SIM_ACTION fail_on_bulkin[] = { +/* 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_DCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x81, UX_NULL, 0, UX_ERROR, + UX_STATE_ERROR, UX_NULL, + UX_FALSE}, /* Invoke callback & no continue */ +{ 0 } +}; + + +static UX_TEST_HCD_SIM_ACTION fail_on_bulkout[] = { +/* 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_DCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_ERROR, + UX_STATE_ERROR, UX_NULL, + UX_FALSE}, /* Invoke callback & no continue */ +{ 0 } +}; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + storage_media = UX_NULL; + media = UX_NULL; +#endif + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + tx_thread_sleep(UX_MS_TO_TICK_NON_ZERO(10)); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *) class -> ux_host_class_media; + media = &storage_media -> ux_host_class_storage_media; +#endif + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_ext != UX_NULL && + class -> ux_host_class_media != UX_NULL) + { + return(UX_SUCCESS); + } + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + +static UINT sleep_break_on_connect(VOID) +{ + if (host_storage_instance_get(0) == UX_SUCCESS) + return(1); + if (error_callback_counter >= 3) + return(1); + return(0); +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *_params) +{ + + set_cfg_counter ++; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_sem_get_on_set_cfg = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_device_storage_basic_standalone_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +ULONG mem_free; +ULONG test_n; + + + /* Inform user. */ + printf("Running STANDALONE Device Storage Read Write Test................... "); +#ifndef UX_DEVICE_STANDALONE + printf("Skip\n"); + test_control_return(0); +#endif + + stepinfo("\n"); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Format the ram drive. */ + status = fx_media_format(&ram_disk1, _fx_ram_driver, ram_disk_memory1, buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + status |= fx_media_format(&ram_disk2, _fx_ram_driver, ram_disk_memory2, buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + if (status != FX_SUCCESS) + { + + /* Storage basic test error. */ + printf("ERROR #8\n"); + test_control_return(1); + } + + /* Open the ram_disk. */ + status = fx_media_open(&ram_disk1, "RAM DISK1", _fx_ram_driver, ram_disk_memory1, buffer1, 512); + status |= fx_media_open(&ram_disk2, "RAM DISK2", _fx_ram_driver, ram_disk_memory2, buffer2, 512); + if (status != FX_SUCCESS) + { + + /* Storage basic test error. */ + printf("ERROR %d\n", __LINE__); + test_control_return(1); + } + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* 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 #%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 device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 2; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_media_flush; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_flush = demo_media_flush; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_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(); + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(ux_test_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main device simulation thread. */ + status = tx_thread_create(&tx_demo_thread_device_simulation, "tx demo device simulation", tx_demo_thread_device_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 21, 21, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + stack_pointer += UX_DEMO_STACK_SIZE; + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static void tx_demo_thread_device_simulation_entry(ULONG arg) +{ + while(1) + { + + /* Run device tasks. */ + ux_system_tasks_run(); + + /* Relinquish to other thread. */ + tx_thread_relinquish(); + } +} + +static ULONG _test_dw_minus(ULONG d0, ULONG d1) +{ + if (d0 >= d1) + return(d0 - d1); + return(d0 + (0xFFFFFFFF - d1)); +} + +static UINT _media_driver_read(FX_MEDIA *media, + VOID (*_media_driver)(FX_MEDIA *), + UCHAR *buffer, ULONG lba, ULONG n_lb) +{ +UINT status; + + if (lba == 0) + { + media->fx_media_driver_logical_sector = lba; + media->fx_media_driver_sectors = n_lb; + media->fx_media_driver_request = FX_DRIVER_BOOT_READ; + media->fx_media_driver_buffer = buffer; + _media_driver(media); + *(buffer) = 0xeb; + *(buffer+1) = 0x3c; + *(buffer+2) = 0x90; + *(buffer+21) = 0xF8; + + *(buffer+24) = 0x01; + *(buffer+26) = 0x10; + *(buffer+28) = 0x01; + + *(buffer+510) = 0x55; + *(buffer+511) = 0xaa; + ux_utility_memory_copy(buffer+0x36,"FAT12",5); + + if (media->fx_media_driver_status != FX_SUCCESS) + { + printf("%s:%d: FX error 0x%x\n", __FILE__, __LINE__, media->fx_media_driver_status); + return(UX_ERROR); + } + + lba++; + n_lb --; + buffer += 512; + } + media->fx_media_driver_logical_sector = lba; + media->fx_media_driver_sectors = n_lb; + media->fx_media_driver_request = FX_DRIVER_READ; + media->fx_media_driver_buffer = buffer; + _media_driver(media); + if (media->fx_media_driver_status != FX_SUCCESS) + { + stepinfo("%s:%d: FX error 0x%x\n", __FILE__, __LINE__, media->fx_media_driver_status); + return(UX_ERROR); + } + return(UX_SUCCESS); +} + +static UINT _media_driver_write(FX_MEDIA *media, + VOID (*_media_driver)(FX_MEDIA *), + UCHAR *buffer, ULONG lba, ULONG n_lb) +{ +UINT status; + + if (lba == 0) + { + media -> fx_media_driver_logical_sector = 0; + media -> fx_media_driver_sectors = 1; + media -> fx_media_driver_request = FX_DRIVER_BOOT_WRITE; + media -> fx_media_driver_buffer = buffer; + _media_driver(media); + + if (media->fx_media_driver_status != FX_SUCCESS) + { + printf("%s:%d: FX error 0x%x\n", __FILE__, __LINE__, media->fx_media_driver_status); + return(UX_ERROR); + } + + lba ++; + n_lb --; + buffer += 512; + } + if (n_lb) + { + media -> fx_media_driver_logical_sector = lba; + media -> fx_media_driver_sectors = n_lb; + media -> fx_media_driver_request = FX_DRIVER_WRITE; + media -> fx_media_driver_buffer = buffer; + _media_driver(media); + + if (media->fx_media_driver_status != FX_SUCCESS) + { + printf("%s:%d: FX error 0x%x\n", __FILE__, __LINE__, media->fx_media_driver_status); + return(UX_ERROR); + } + } + return(UX_SUCCESS); +} + +static UINT _test_host_class_storage_inquiry(UX_HOST_CLASS_STORAGE *storage, + UCHAR flags, ULONG data_length, ULONG cb_length, + UCHAR page_code, UCHAR *response, ULONG response_length) +{ +UINT status; +UCHAR *cbw; +UINT command_length; + + /* Use a pointer for the cbw, easier to manipulate. */ + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + /* Initialize the CBW for this command. */ + _ux_host_class_storage_cbw_initialize(storage, flags, data_length, cb_length); + + /* Prepare the INQUIRY command block. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_INQUIRY; + + /* Store the page code. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_PAGE_CODE) = page_code; + + /* Store the length of the Inquiry Response. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_ALLOCATION_LENGTH) = (UCHAR)response_length; + + /* Send the command to transport layer. */ + status = _ux_host_class_storage_transport(storage, response); + + /* Return completion status. */ + return(status); +} +static UINT test_host_class_storage_inquiry(UX_HOST_CLASS_STORAGE *storage, UCHAR page_code, UCHAR *response, ULONG response_length) +{ + _test_host_class_storage_inquiry(storage, + UX_HOST_CLASS_STORAGE_DATA_IN, + UX_HOST_CLASS_STORAGE_INQUIRY_RESPONSE_LENGTH, + UX_HOST_CLASS_STORAGE_INQUIRY_COMMAND_LENGTH_SBC, + page_code, response, response_length); +} + +static UINT _test_send_cbw_EX(int __line__, ULONG length) +{ + +UX_TRANSFER *transfer_request; +UINT status; +UCHAR *cbw; + + stepinfo(">>>>> %d.%d: CBW\n", __LINE__, __line__); + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + transfer_request -> ux_transfer_request_data_pointer = cbw; + transfer_request -> ux_transfer_request_requested_length = length; + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} +static UINT _test_send_cbw(int __line__) +{ + _test_send_cbw_EX(__line__, UX_HOST_CLASS_STORAGE_CBW_LENGTH); +} + +static UINT _test_transfer_data(int __line__, UCHAR *data, ULONG size, UCHAR do_read) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + stepinfo(">>>>> %d.%d: DATA\n", __LINE__, __line__); + transfer_request = do_read ? + &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request : + &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + transfer_request -> ux_transfer_request_data_pointer = data; + transfer_request -> ux_transfer_request_requested_length = size; + + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_wait_csw_EX(int __line__) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + stepinfo(">>>>> %d.%d: CSW_Ex\n", __LINE__, __line__); + + /* Get the pointer to the transfer request, on the bulk in endpoint. */ + transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + /* Fill in the transfer_request parameters. */ + transfer_request -> ux_transfer_request_data_pointer = (UCHAR *) &storage -> ux_host_class_storage_csw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CSW_LENGTH; + + /* Get the CSW on the bulk in endpoint. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + return(status); + + /* Wait for the completion of the transfer request. */ + status = _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* If OK, we are done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static VOID _test_clear_stall(UCHAR clear_read_stall) +{ + +UX_ENDPOINT *endpoint; + + + endpoint = clear_read_stall ? + storage -> ux_host_class_storage_bulk_in_endpoint : + storage -> ux_host_class_storage_bulk_out_endpoint; + _ux_host_stack_endpoint_reset(endpoint); +} + +static UINT _test_wait_csw(int __line__) +{ +UINT status; + + stepinfo(">>>>> %d.%d: CSW\n", __LINE__, __line__); + status = _test_wait_csw_EX(__LINE__); + if (status == UX_TRANSFER_STALLED) + { + _test_clear_stall(UX_TRUE); + status = _test_wait_csw_EX(__LINE__); + } + return(status); +} + +static UINT _test_request_sense(void) +{ + +UINT status; +UX_TRANSFER *transfer_request; +UCHAR *cbw; +UCHAR *request_sense_response; +ULONG sense_code; +UINT command_length = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_COMMAND_LENGTH_SBC; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + _ux_utility_memory_copy(storage -> ux_host_class_storage_saved_cbw, storage -> ux_host_class_storage_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + _ux_host_class_storage_cbw_initialize(storage, UX_HOST_CLASS_STORAGE_DATA_IN, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_REQUEST_SENSE; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_ALLOCATION_LENGTH) = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH; + request_sense_response = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH); + if (request_sense_response == UX_NULL) + return(UX_MEMORY_INSUFFICIENT); + status = _test_send_cbw(__LINE__); + if (status == UX_SUCCESS) + { + status = _test_transfer_data(__LINE__, request_sense_response, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, UX_TRUE); + if (status == UX_SUCCESS) + { + status = _test_wait_csw(__LINE__); + if (status == UX_SUCCESS) + { + + sense_code = (((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_SENSE_KEY)) & 0x0f) << 16; + sense_code |= ((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE)) << 8; + sense_code |= (ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE_QUALIFIER); + + storage -> ux_host_class_storage_sense_code = sense_code; + } + } + } + _ux_utility_memory_free(request_sense_response); + _ux_utility_memory_copy(storage -> ux_host_class_storage_cbw, storage -> ux_host_class_storage_saved_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + return(status); +} + +typedef struct cbw_read_struct +{ + UCHAR flags_pos; + UCHAR lba_pos; + UCHAR lba_size; + UCHAR len_pos; + UCHAR len_size; +} cbw_read_struct_t; +static cbw_read_struct_t cbw_READ_info[] = +{ + { 1, 2, 2, 4, 1}, + { 1, 2, 4, 7, 2}, + { 1, 2, 4, 6, 4}, + { 1, 2, 8, 10, 4}, + {10, 12, 8, 28, 4} +}; +static UCHAR _read_op(UCHAR op_code) +{ + switch(op_code) + { + case 0x28: return 1; + case 0xA8: return 2; + case 0x88: return 3; + case 0x7F: return 4; + case 0x08: return 0; + default: return 0xFF; + } +} +static void _test_init_cbw_READ_EX( + UCHAR flags, ULONG data_length, + UCHAR op6_10_12_16_32, ULONG lba, ULONG len) +{ +UCHAR *cbw; +UINT command_length; +UCHAR op = _read_op(op6_10_12_16_32); +UINT i; + + + if (op >= 5) + return; + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, flags, data_length, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = op6_10_12_16_32; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + cbw_READ_info[op].flags_pos) = 0; + for (i = cbw_READ_info[op].lba_pos + cbw_READ_info[op].lba_size - 1; i >= cbw_READ_info[op].lba_pos; i --) + { + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + i) = (UCHAR)lba; + lba >>= 8; + } + for (i = cbw_READ_info[op].len_pos + cbw_READ_info[op].len_size - 1; i >= cbw_READ_info[op].len_size; i --) + { + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + i) = (UCHAR)len; + len >>= 8; + } +} +static void _test_init_cbw_READ(UCHAR op6_10_12_16_32, ULONG lba, ULONG len) +{ + _test_init_cbw_READ_EX(0x80, len * 512, op6_10_12_16_32, lba, len); +} + +typedef struct cbw_write_struct +{ + UCHAR flags_pos; + UCHAR lba_pos; + UCHAR lba_size; + UCHAR len_pos; + UCHAR len_size; +} cbw_write_struct_t; +static cbw_write_struct_t cbw_WRITE_info[] = +{ + { 1, 2, 2, 4, 1}, + { 1, 2, 4, 7, 2}, + { 1, 2, 4, 6, 4}, + { 1, 2, 8, 10, 4}, + {10, 12, 8, 28, 4} +}; +static UCHAR _write_op(UCHAR op_code) +{ + switch(op_code) + { + case 0x2A: return 1; + case 0xAA: return 2; + case 0x8A: return 3; + case 0x7F: return 4; + case 0x0A: return 0; + default: return 0xFF; + } +} +static void _test_init_cbw_WRITE_EX(UCHAR flags, ULONG data_length, + UCHAR op6_10_12_16_32, ULONG lba, ULONG len) +{ + +UCHAR *cbw; +UINT command_length; +UCHAR op = _write_op(op6_10_12_16_32); +UINT i; + + + if (op >= 5) + return; + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, flags, data_length, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = op6_10_12_16_32; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + cbw_WRITE_info[op].flags_pos) = 0; + for (i = cbw_WRITE_info[op].lba_pos + cbw_WRITE_info[op].lba_size - 1; i >= cbw_WRITE_info[op].lba_pos; i --) + { + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + i) = (UCHAR)lba; + lba >>= 8; + } + for (i = cbw_WRITE_info[op].len_pos + cbw_WRITE_info[op].len_size - 1; i >= cbw_WRITE_info[op].len_size; i --) + { + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + i) = (UCHAR)len; + len >>= 8; + } +} +static void _test_init_cbw_WRITE(UCHAR op6_10_12_16_32, ULONG lba, ULONG len) +{ + _test_init_cbw_WRITE_EX(0x00, len * 512, op6_10_12_16_32, lba, len); +} + +static void _test_init_cbw_REQUEST_SENSE(ULONG data_length) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0x80, data_length, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_REQUEST_SENSE; +} + +static void _test_init_cbw_TEST_READY(ULONG data_length) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0x00, data_length, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_TEST_READY; +} + +static void _test_init_cbw_FORMAT_UNIT(void) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, 0, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_FORMAT; +} + +static void _test_init_cbw_START_STOP(void) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, 0, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_START_STOP; +} + +static void _test_init_cbw_VERIFY(void) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, 0, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_VERIFY; +} + +static void _test_init_cbw_MODE_SELECT(ULONG data_length) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, data_length, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SELECT; +} + +static void _test_init_cbw_MODE_SENSE(UCHAR op6, UCHAR page_code, ULONG buffer_length) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0x80, buffer_length, command_length); + if (op6) + { + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE_SHORT; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PARAMETER_LIST_LENGTH_6) = (UCHAR)buffer_length; + } + else + { + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE; + _ux_utility_short_put_big_endian(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PARAMETER_LIST_LENGTH_10, (USHORT)buffer_length); + } + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PC_PAGE_CODE) = page_code; +} + +static void _test_init_cbw_SYNCHRONIZE_CACHE(UCHAR op16, UCHAR immed, ULONG lba, ULONG nb_blocks) +{ + +UCHAR *cbw; +UINT command_length; + + + (void)op16; + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, 0, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_SYNCHRONIZE_CACHE_FLAGS) = immed ? UX_SLAVE_CLASS_STORAGE_SYNCHRONIZE_CACHE_FLAGS_IMMED : 0; + _ux_utility_long_put_big_endian(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_SYNCHRONIZE_CACHE_LBA, lba); + _ux_utility_short_put_big_endian(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_SYNCHRONIZE_CACHE_NUMBER_OF_BLOCKS, (USHORT)nb_blocks); +} + +static void _test_init_cbw_PREVENT_ALLOW_MEDIA_REMOVAL(void) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, 0, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_PREVENT_ALLOW_MEDIA_REMOVAL; +} + + +static void _msc_cbw_fail_cases_test(const char* __file__, int __line__) +{ +UINT status; +UCHAR *cbw; + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + stepinfo("\n%s:%d:MSC CBW fail tests\n", __file__, __line__); + + stepinfo(">>>>>>>>>>>>>>>> Test VERIFY CBW length error\n"); + _test_init_cbw_VERIFY(); + status = _test_send_cbw_EX(__LINE__, UX_HOST_CLASS_STORAGE_CBW_LENGTH - 1); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + stepinfo(">>>>>>>>>>>>>>>> Test VERIFY CBW LUN error\n"); + _test_init_cbw_VERIFY(); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_LUN + 0) = 0xFF; + status = _test_send_cbw_EX(__LINE__, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + stepinfo(">>>>>>>>>>>>>>>> Test VERIFY CBW Signature error\n"); + _test_init_cbw_VERIFY(); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_SIGNATURE + 0) = 0xFF; + status = _test_send_cbw_EX(__LINE__, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + stepinfo(">>>>>>>>>>>>>>>> Test VERIFY CBW CBW_CB length error\n"); + _test_init_cbw_VERIFY(); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB_LENGTH + 0) = 0; + status = _test_send_cbw_EX(__LINE__, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + _test_clear_stall(UX_TRUE); + _test_init_cbw_VERIFY(); + status = _test_send_cbw_EX(__LINE__, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + stepinfo(">>>>>>>>>>>>>>>> Test CBW CMD unknown error\n"); + _test_init_cbw_VERIFY(); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = 0xFF; + status = _test_send_cbw_EX(__LINE__, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); +} + + +static void _msc_get_max_lun_cases_test(const char* __file__, int __line__) +{ +UINT status; +UX_DEVICE *device; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; + + stepinfo("\n%s:%d:MSC GET_MAX_LUN tests\n", __file__, __line__); + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: device_get fail\n", __LINE__, __line__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Send transfer request - GetMaxLun. */ + transfer_request -> ux_transfer_request_data_pointer = UX_NULL; + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_SLAVE_CLASS_STORAGE_GET_MAX_LUN; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceNumber; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS && status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Invalid wValue. */ + transfer_request -> ux_transfer_request_value = 1; + transfer_request -> ux_transfer_request_index = storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceNumber; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Invalid wIndex. */ + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceNumber + 1; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Send transfer request - UX_SLAVE_CLASS_STORAGE_RESET. */ + transfer_request -> ux_transfer_request_function = UX_SLAVE_CLASS_STORAGE_RESET; + + /* Invalid wValue. */ + transfer_request -> ux_transfer_request_value = 1; + transfer_request -> ux_transfer_request_index = storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceNumber; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Invalid wIndex. */ + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceNumber + 1; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Invalid wLength. */ + transfer_request -> ux_transfer_request_data_pointer = (UCHAR*)&status; + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceNumber; + transfer_request -> ux_transfer_request_requested_length = 1; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void _msc_inquiry_cases_test(const char* __file__, int __line__) +{ +UINT status; +UX_SLAVE_DEVICE *slave_device; +UX_SLAVE_CLASS *slave_class; +UX_SLAVE_CLASS_STORAGE *slave_storage; + + stepinfo("\n%s:%d:MSC INQUIRY tests\n", __file__, __line__); + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(standard)\n"); + status = test_host_class_storage_inquiry(storage, 0x00, buffer, 64); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(standard, UX_SLAVE_CLASS_STORAGE_MEDIA_CDROM)\n"); + slave_device = &_ux_system_slave->ux_system_slave_device; + slave_class = _ux_system_slave->ux_system_slave_interface_class_array[0]; + slave_storage = (UX_SLAVE_CLASS_STORAGE *)slave_class->ux_slave_class_instance; + slave_storage -> ux_slave_class_storage_lun[0].ux_slave_class_storage_media_type = UX_SLAVE_CLASS_STORAGE_MEDIA_CDROM; + status = test_host_class_storage_inquiry(storage, 0x00, buffer, 64); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(unknown page code)\n"); + status = test_host_class_storage_inquiry(storage, 0xEF, buffer, 64); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(big buffer)\n"); + status = _test_host_class_storage_inquiry(storage, 0x80, + 64, + UX_HOST_CLASS_STORAGE_INQUIRY_COMMAND_LENGTH_SBC, + 0x00, buffer, 64); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(Hi <> Do)\n"); + status = _test_host_class_storage_inquiry(storage, 0x00, + UX_HOST_CLASS_STORAGE_INQUIRY_RESPONSE_LENGTH, + UX_HOST_CLASS_STORAGE_INQUIRY_COMMAND_LENGTH_SBC, + 0x00, buffer, UX_HOST_CLASS_STORAGE_INQUIRY_RESPONSE_LENGTH); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(Hi <> Do)\n"); + status = _test_host_class_storage_inquiry(storage, 0x00, + 0, + UX_HOST_CLASS_STORAGE_INQUIRY_COMMAND_LENGTH_SBC, + 0x00, buffer, UX_HOST_CLASS_STORAGE_INQUIRY_RESPONSE_LENGTH); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } +} + +static void _msc_read_cases_test(const char* __file__, int __line__) +{ +UINT status; + + stepinfo("\n%s:%d:MSC READ tests\n", __file__, __line__); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_READ32 - success\n"); + _test_init_cbw_READ(UX_SLAVE_CLASS_STORAGE_SCSI_READ32, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 512, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_READ16 - status fail\n"); + ram_disk_status = UX_ERROR; + _test_init_cbw_READ(UX_SLAVE_CLASS_STORAGE_SCSI_READ16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 512, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + ram_disk_status = UX_SUCCESS; + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_READ16 - transfer fail\n"); + _test_init_cbw_READ(UX_SLAVE_CLASS_STORAGE_SCSI_READ16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + ux_test_dcd_sim_slave_set_actions(fail_on_bulkin); + status = _test_transfer_data(__LINE__, buffer, 512, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_READ16 - Case(7) Hi < Di\n"); + _test_init_cbw_READ_EX(0x80, 0, UX_SLAVE_CLASS_STORAGE_SCSI_READ16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 512, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_READ16 - Case(8) Hi <> Do\n"); + _test_init_cbw_READ_EX(0x00, 512, UX_SLAVE_CLASS_STORAGE_SCSI_READ16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 512, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_READ16 - Case(5) Hi > Di\n"); + _test_init_cbw_READ_EX(0x80, 1024, UX_SLAVE_CLASS_STORAGE_SCSI_READ16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 1024, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); +} + +static void _msc_write_cases_test(const char* __file__, int __line__) +{ +UINT status; +UX_SLAVE_DEVICE *slave_device; +UX_SLAVE_CLASS *slave_class; +UX_SLAVE_CLASS_STORAGE *slave_storage; + + stepinfo("\n%s:%d:MSC WRITE tests\n", __file__, __line__); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_WRITE32 - success\n"); + _test_init_cbw_WRITE(UX_SLAVE_CLASS_STORAGE_SCSI_WRITE32, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 512, UX_FALSE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16 - status fail\n"); + ram_disk_status = UX_ERROR; + _test_init_cbw_WRITE(UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 512, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + ram_disk_status = UX_SUCCESS; + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16 - transfer fail\n"); + _test_init_cbw_WRITE(UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + ux_test_dcd_sim_slave_set_actions(fail_on_bulkout); + status = _test_transfer_data(__LINE__, buffer, 512, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16 - WP fail\n"); + slave_device = &_ux_system_slave->ux_system_slave_device; + slave_class = _ux_system_slave->ux_system_slave_interface_class_array[0]; + slave_storage = (UX_SLAVE_CLASS_STORAGE *)slave_class->ux_slave_class_instance; + slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_read_only_flag = UX_TRUE; + _test_init_cbw_WRITE(UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 512, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_read_only_flag = UX_FALSE; + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16 - Case (3) Hn < Do\n"); + _test_init_cbw_WRITE_EX(0x00, 0, UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + #if 0 /* Host expect no data. */ + status = _test_transfer_data(__LINE__, buffer, 512, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + #endif + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16 - Case (8) Hi <> Do\n"); + _test_init_cbw_WRITE_EX(0x80, 512, UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 512, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16 - Case (9) Ho > Do\n"); + _test_init_cbw_WRITE_EX(0x00, 1024, UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 1024, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); +} + +static void _msc_request_sense_cases_test(const char* __file__, int __line__) +{ +UINT status; + + stepinfo("\n%s:%d:MSC REQUEST_SENSE tests\n", __file__, __line__); + + _test_init_cbw_REQUEST_SENSE(64); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 64, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); +} + +static void _msc_test_ready_cases_test(const char* __file__, int __line__) +{ +UINT status; + + stepinfo("\n%s:%d:MSC UNIT_READY tests\n", __file__, __line__); + + _test_init_cbw_TEST_READY(64); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 64, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: code 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); +} + +static void _msc_format_unit_cases_test(const char* __file__, int __line__) +{ +UINT status; + + stepinfo("\n%s:%d:MSC FORMAT_UNIT tests\n", __file__, __line__); + + _test_init_cbw_FORMAT_UNIT(); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + #if 0 /* Host expects no data. */ + status = _test_transfer_data(__LINE__, "test dead beef", 15, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + #endif + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_request_sense(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void _msc_start_stop_cases_test(const char* __file__, int __line__) +{ +UINT status; + + stepinfo("\n%s:%d:MSC START_STOP tests\n", __file__, __line__); + + _test_init_cbw_START_STOP(); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void _msc_verify_cases_test(const char* __file__, int __line__) +{ +UINT status; + + stepinfo("\n%s:%d:MSC VERIFY tests\n", __file__, __line__); + + _test_init_cbw_VERIFY(); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void _msc_mode_sense_cases_test(const char* __file__, int __line__) +{ +UINT status; +UX_SLAVE_DEVICE *slave_device; +UX_SLAVE_CLASS *slave_class; +UX_SLAVE_CLASS_STORAGE *slave_storage; + + stepinfo("\n%s:%d:MSC MODE_SENSE tests\n", __file__, __line__); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(PAGE_CODE_CDROM):\n"); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(PAGE_CODE_CDROM) - 128B\n"); + _test_init_cbw_MODE_SENSE(UX_FALSE, UX_SLAVE_CLASS_STORAGE_MMC2_PAGE_CODE_CDROM, 128); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(PAGE_CODE_CDROM) - 74B\n"); + _test_init_cbw_MODE_SENSE(UX_TRUE, UX_SLAVE_CLASS_STORAGE_MMC2_PAGE_CODE_CDROM, 74); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 74, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Change read_only_flag */ + slave_device = &_ux_system_slave->ux_system_slave_device; + slave_class = _ux_system_slave->ux_system_slave_interface_class_array[0]; + slave_storage = (UX_SLAVE_CLASS_STORAGE *)slave_class->ux_slave_class_instance; + slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_read_only_flag = UX_TRUE; + + /************ UX_SLAVE_CLASS_STORAGE_PAGE_CODE_CACHE ****************/ + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(PAGE_CODE_CACHE):\n"); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(PAGE_CODE_CACHE) - 128B\n"); + _test_init_cbw_MODE_SENSE(UX_FALSE, UX_SLAVE_CLASS_STORAGE_PAGE_CODE_CACHE, 128); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(PAGE_CODE_CACHE) - 24B\n"); + _test_init_cbw_MODE_SENSE(UX_TRUE, UX_SLAVE_CLASS_STORAGE_PAGE_CODE_CACHE, 24); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 24, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(PAGE_CODE_CACHE) - 24B\n"); + slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_flush = demo_media_flush; + _test_init_cbw_MODE_SENSE(UX_TRUE, UX_SLAVE_CLASS_STORAGE_PAGE_CODE_CACHE, 24); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 24, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /************ UX_SLAVE_CLASS_STORAGE_PAGE_CODE_IEC ****************/ + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(PAGE_CODE_IEC) - 128B\n"); + _test_init_cbw_MODE_SENSE(UX_FALSE, UX_SLAVE_CLASS_STORAGE_PAGE_CODE_IEC, 128); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(PAGE_CODE_IEC) - 16B\n"); + _test_init_cbw_MODE_SENSE(UX_TRUE, UX_SLAVE_CLASS_STORAGE_PAGE_CODE_IEC, 16); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 16, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /************ 0x3F ****************/ + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(0x3F) - 128B\n"); + _test_init_cbw_MODE_SENSE(UX_FALSE, 0x3F, 128); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /************ 0x3F ****************/ + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE(0x3F) - %dB\n", + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE + 8); + _test_init_cbw_MODE_SENSE(UX_FALSE, 0x3F, UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE + 8); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, buffer, 128, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void _msc_mode_select_cases_test(const char* __file__, int __line__) +{ +UINT status; + + stepinfo("\n%s:%d:MSC MODE_SELECT tests\n", __file__, __line__); + + _test_init_cbw_MODE_SELECT(15); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(__LINE__, "test dead beef", 15, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_request_sense(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void _msc_synchronous_cache_cases_test(const char* __file__, int __line__) +{ +UINT status; +UX_SLAVE_DEVICE *slave_device; +UX_SLAVE_CLASS *slave_class; +UX_SLAVE_CLASS_STORAGE *slave_storage; + + stepinfo("\n%s:%d:MSC SYNCHRONOUS_CACHE tests\n", __file__, __line__); + + slave_device = &_ux_system_slave->ux_system_slave_device; + slave_class = _ux_system_slave->ux_system_slave_interface_class_array[0]; + slave_storage = (UX_SLAVE_CLASS_STORAGE *)slave_class->ux_slave_class_instance; + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE no CB - success\n"); + slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_flush = UX_NULL; + slave_storage->ux_slave_class_storage_lun[1].ux_slave_class_storage_media_flush = UX_NULL; + _test_init_cbw_SYNCHRONIZE_CACHE(UX_FALSE, UX_FALSE, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE - success\n"); + slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_flush = demo_media_flush; + slave_storage->ux_slave_class_storage_lun[1].ux_slave_class_storage_media_flush = demo_media_flush; + _test_init_cbw_SYNCHRONIZE_CACHE(UX_FALSE, UX_FALSE, 0, 1); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE - status fail\n"); + _test_init_cbw_SYNCHRONIZE_CACHE(UX_FALSE, UX_FALSE, 0, 1); + ram_disk_status = UX_ERROR; + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw_EX(__LINE__); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw_EX(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_request_sense(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + ram_disk_status = UX_SUCCESS; + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE - flush fail\n"); + _test_init_cbw_SYNCHRONIZE_CACHE(UX_FALSE, UX_FALSE, 0, 1); + ram_disk_flush_status = UX_STATE_ERROR; + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw_EX(__LINE__); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw_EX(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + ram_disk_flush_status = UX_STATE_NEXT; +} + +static void _msc_prevent_allow_removal_cases_test(const char* __file__, int __line__) +{ +UINT status; + + stepinfo("\n%s:%d:MSC PREVENT_ALLOW_MEDIA_REMOVAL tests\n", __file__, __line__); + + _test_init_cbw_PREVENT_ALLOW_MEDIA_REMOVAL(); + status = _test_send_cbw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(__LINE__); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + + +static void _msc_media_read_test(const char* __file__, int __line__) +{ +UINT status; +ULONG test_n; +ULONG test_size[] = { + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 2 / 512, + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 3 / 512, + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 2 / 512 + 1}; + + stepinfo("\n%s:%d:MSC Media Read tests\n", __file__, __line__); + + if (media == UX_NULL || media -> fx_media_id == 0) + { + printf("ERROR %d: media error\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Disk read(1) test\n"); + { + status = fx_media_read(media, 48, buffer); + if (status != FX_SUCCESS) + { + printf("ERROR %d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + } + + /* Disk read multiple test. */ + for (test_n = 0; test_n < sizeof(test_size)/sizeof(test_size[0]); test_n ++) + { + + stepinfo(">>>>>>>>>>>> Disk read(%d) test\n", test_size[test_n]); + status = _media_driver_read(media, _ux_host_class_storage_driver_entry, + buffer, 0, test_size[test_n]); + if (status != UX_SUCCESS) + { + printf("ERROR %d.%ld: 0x%x\n", __LINE__, test_n, status); + test_control_return(1); + } + } +} + +static void _msc_media_write_read_test(const char* __file__, int __line__) +{ +UINT status; +ULONG test_n; +INT i; +ULONG test_size[] = { + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 2 / 512, + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 3 / 512, + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 2 / 512 + 1}; + + stepinfo("\n%s:%d:MSC Media Write & Read tests\n", __file__, __line__); + + /* Check if media still available. */ + if (media == UX_NULL || media -> fx_media_id == 0) + { + printf("ERROR %d: media error\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Disk write(1)/read(1) test\n"); + { + for(i = 0; i < 512; i ++) + buffer[i] = i; + status = fx_media_write(media, 48, buffer); + if (status != FX_SUCCESS) + { + printf("ERROR %d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_utility_memory_set(buffer, 0x00, 512); + status = fx_media_read(media, 48, buffer); + if (status != FX_SUCCESS) + { + printf("ERROR %d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + for (i = 0; i < 512; i ++) + { + if (buffer[i] != (UCHAR)i) + { + printf("ERROR %d: %d <> %d\n", __LINE__, i, buffer[i]); + test_control_return(1); + } + } + } + + /* Disk write/read multiple test. */ + for (test_n = 0; test_n < sizeof(test_size)/sizeof(test_size[0]); test_n ++) + { + stepinfo(">>>>>>>>>>>> Disk write(%ld)/read(%ld) test\n", + test_size[test_n], test_size[test_n]); + + for(i = 0; i < test_size[test_n] * 512; i ++) + buffer[i] = (UCHAR)(i + (i >> 8)); + status = _media_driver_write(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size[test_n]); + if (status != FX_SUCCESS) + { + printf("ERROR %d.%ld: 0x%x\n", __LINE__, test_n, status); + test_control_return(1); + } + _ux_utility_memory_set(buffer, 0x00, test_size[test_n] * 512); + status = _media_driver_read(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size[test_n]); + if (status != FX_SUCCESS) + { + printf("ERROR %d.%ld: 0x%x\n", __LINE__, test_n, status); + test_control_return(1); + } + for (i = 0; i < 512; i ++) + { + if (buffer[i] != (UCHAR)(i + (i >> 8))) + { + printf("ERROR %d: %d <> %d\n", __LINE__, i, buffer[i]); + test_control_return(1); + } + } + } +} + +static void _msc_enumeration_test(const char* __file__, int __line__, unsigned option) +{ +UINT status; +ULONG mem_free; +ULONG test_n; + + stepinfo("\n%s:%d:MSC Enumeration tests\n", __file__, __line__); + + stepinfo(">>>>>>>>>>>> Enumeration information collection\n"); + { + + /* Test disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check connection. */ + status = host_storage_instance_get(0); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_count_reset(); + ux_test_utility_sim_mutex_create_count_reset(); + ux_test_utility_sim_sem_create_count_reset(); + ux_test_utility_sim_sem_get_count_reset(); + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + + /* Save free memory usage. */ + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Check connection. */ + status = host_storage_instance_get(50); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Log create counts for further tests. */ + rsc_enum_mutex_usage = rsc_mutex_on_set_cfg; + rsc_enum_sem_usage = rsc_sem_on_set_cfg; + rsc_enum_mem_alloc_count = rsc_mem_alloc_cnt_on_set_cfg; + /* Log create counts when instances active for further tests. */ + rsc_storage_mutex_usage = ux_test_utility_sim_mutex_create_count() - rsc_enum_mutex_usage; + rsc_storage_sem_usage = ux_test_utility_sim_sem_create_count() - rsc_enum_sem_usage; + rsc_storage_mem_alloc_count = ux_test_utility_sim_mem_alloc_count() - rsc_enum_mem_alloc_count; + + /* Lock log base for tests. */ + ux_test_utility_sim_mem_alloc_log_lock(); + + stepinfo("enum mem: %ld\n", rsc_enum_mem_alloc_count); + stepinfo("storage mem : %ld\n", rsc_storage_mem_alloc_count); + stepinfo("mem free: %ld, %ld\n", _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); + } + + /* Simulate detach and attach for FS enumeration, + and check if there is memory error in normal enumeration. + */ + if (option & (1u)) + { + stepinfo(">>>>>>>>>>>> Enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < 3; test_n++) + { + stepinfo("%4ld / 2\n", test_n); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check */ + if (host_storage_instance_get(0) == UX_SUCCESS) + { + + printf("ERROR #%d.%ld: Disconnect fail\n", __LINE__, test_n); + test_control_return(1); + } + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Wait and break on error. */ + error_callback_counter = 0; + ux_test_breakable_sleep( + (UX_MS_TO_TICK_NON_ZERO(UX_RH_ENUMERATION_RETRY_DELAY) + + UX_MS_TO_TICK_NON_ZERO(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY)) * + 3, + sleep_break_on_connect); + + /* Check */ + if (host_storage_instance_get(0) != UX_SUCCESS) + { + + printf("ERROR #%d.%ld: Enumeration fail\n", __LINE__, test_n); + test_control_return(1); + } + } + stepinfo("\n"); + } + + /* Simulate detach and attach for FS enumeration, + and test possible memory allocation error handlings. + */ + if (option & (2u)) + { + if (rsc_storage_mem_alloc_count) stepinfo(">>>>>>>>>>>> Memory errors enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_storage_mem_alloc_count; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_storage_mem_alloc_count - 1); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check */ + if (host_storage_instance_get(0) == UX_SUCCESS) + { + + printf("ERROR #%d.%ld: Disconnect fail\n", __LINE__, test_n); + test_control_return(1); + } + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Set memory error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n + rsc_enum_mem_alloc_count); + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on errors. */ + ux_test_breakable_sleep(100, sleep_break_on_error); + + /* Check error */ + if (host_storage_instance_get(0) == UX_SUCCESS) + { + + /* Could be media errors, + in this case instance is ready, + check error trap. */ + if (error_callback_counter == 0) + { + printf("ERROR #%d.%ld: device detected when there is memory error\n", __LINE__, test_n); + test_control_return(1); + } + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + } + ux_test_utility_sim_mem_alloc_error_generation_stop(); + if (rsc_storage_mem_alloc_count) stepinfo("\n"); + } +} + +static void _msc_media_write_read_misc_test(const char* __file__, int __line__) +{ +UINT status; +UINT test_size = UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 3 / 512; +UINT test_n; +ULONG test_start; +ULONG test_ticks; +INT i; + + stepinfo("\n%s:%d:MSC Media Read tests\n", __file__, __line__); + + if (media == UX_NULL || media -> fx_media_id == 0) + { + printf("ERROR %d.%d: media error\n", __LINE__, __line__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Disk read(%d) test - tick obtain\n", test_size); + test_start = tx_time_get(); + status = _media_driver_read(media, _ux_host_class_storage_driver_entry, + buffer, 0, test_size); + test_ticks = _test_dw_minus(tx_time_get(), test_start); + if (status != UX_SUCCESS) + { + printf("ERROR %d.%d: 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + test_ticks /= 3; + stepinfo(" :: Buffer XFR time: %ld ticks\n", test_ticks); + + stepinfo(">>>>>>>>>>>> Disk write/read(%d) test - slow disk write/read\n", test_size); + ram_disk_rw_wait_delay = ((test_ticks + 1) >> 1) + 1; + for(test_n = 0; test_n < 4; test_n ++) + { + stepinfo(">>>>>>>>>>>> Disk write/read(%d) test - disk write/read wait %ld\n", + test_size, ram_disk_rw_wait_delay); + for(i = 0; i < test_size * 512; i ++) + buffer[i] = (UCHAR)(i + (i >> 8)); + ram_disk_rw_wait_start = tx_time_get(); + status = _media_driver_write(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size); + if (status != FX_SUCCESS) + { + printf("ERROR %d.%d.%d: 0x%x\n", __LINE__, __line__, test_n, status); + test_control_return(1); + } + _ux_utility_memory_set(buffer, 0x00, test_size * 512); + ram_disk_rw_wait_start = tx_time_get(); + status = _media_driver_read(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size); + if (status != FX_SUCCESS) + { + printf("ERROR %d.%d.%d: 0x%x\n", __LINE__, __line__, test_n, status); + test_control_return(1); + } + for (i = 0; i < 512; i ++) + { + if (buffer[i] != (UCHAR)(i + (i >> 8))) + { + printf("ERROR %d.%d.%d: %d <> %d\n", __LINE__, __line__, test_n, i, buffer[i]); + test_control_return(1); + } + } + ram_disk_rw_wait_delay <<= 1; + } + + stepinfo(">>>>>>>>>>>> Disk read(%d) test - USB fail while disk waiting\n", test_size); + ram_disk_rw_wait_start = tx_time_get(); + ram_disk_rw_count = 0; + ram_disk_rw_fail_mode = 0x81; + ram_disk_rw_fail_after = 1; + status = _media_driver_read(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size); + if (status == UX_SUCCESS) + { + printf("ERROR %d.%d: 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Disk write(%d) test - USB fail while disk waiting\n", test_size); + ram_disk_rw_wait_start = tx_time_get(); + ram_disk_rw_count = 0; + ram_disk_rw_fail_mode = 0x82; + ram_disk_rw_fail_after = 0; + status = _media_driver_write(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size); + if (0 /*status == UX_SUCCESS*/) + { + printf("ERROR %d.%d: 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + + /* Restore: no disk wait delay. */ + ram_disk_rw_fail_after = 0xFFFFFFFF; + ram_disk_rw_wait_delay = 0; +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; + + + /* Find the storage class. */ + status = host_storage_instance_get(800); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> MSC Read Write test\n"); + + _msc_media_write_read_test(__FILE__, __LINE__); + _msc_media_write_read_misc_test(__FILE__, __LINE__); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +static UCHAR lun_init_done[2] = {0, 0}; +UINT status; +ULONG mstatus = UX_SLAVE_CLASS_STORAGE_SENSE_KEY_NO_SENSE; + + + (void)storage; + (void)media_id; + + if (ram_disk_status) + { + status = ram_disk_status; + if (media_status) + *media_status = ram_disk_media_status; + ram_disk_status = UX_SUCCESS; + ram_disk_status_sent = UX_TRUE; + return(status); + } + + if (lun > 1) + status = (UX_ERROR); + else if (lun_init_done[lun] > 0) + status = (UX_SUCCESS); + else + { + lun_init_done[lun] ++; + mstatus = UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8); + status = (UX_ERROR); + } + + if (media_status) + *media_status = mstatus; + + return status; +} + +static UINT demo_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + +UINT status = 0; + + /* Abort. */ + if (data_pointer == UX_NULL) + { + ram_disk_rw_wait_state = 0; + return(UX_STATE_NEXT); + } + + /* Media RW fail simulation. */ + if (ram_disk_rw_fail_after < 0xFFFFFFFF) + { + ram_disk_rw_count ++; + if (ram_disk_rw_count >= ram_disk_rw_fail_after) + { + if (ram_disk_rw_fail_mode_one_shot()) + { + ram_disk_rw_fail_after = 0xFFFFFFFF; + ram_disk_rw_count = 0; + } + if (ram_disk_rw_fail_mode_bulk_in()) + ux_test_dcd_sim_slave_set_actions(fail_on_bulkin); + else if (ram_disk_rw_fail_mode_bulk_out()) + ux_test_dcd_sim_slave_set_actions(fail_on_bulkout); + else if (ram_disk_rw_fail_mode_disk()) + { + *media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x02,0x54,0x00); + return(UX_STATE_ERROR); + } + } + } + + /* Media RW wait simulation. */ + if (ram_disk_rw_wait_delay) + { + if (_test_dw_minus(tx_time_get(), ram_disk_rw_wait_start) < ram_disk_rw_wait_delay) + { + ram_disk_rw_wait_state = 1; + return(UX_STATE_WAIT); + } + ram_disk_rw_wait_state = 0; + ram_disk_rw_wait_start = tx_time_get(); + } + + status = _media_driver_read(ram_disks[lun], _fx_ram_driver, data_pointer, lba, number_blocks); + if (status != UX_SUCCESS) + { + *media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x02,0x54,0x00); + return(UX_STATE_ERROR); + } + return(UX_STATE_NEXT); +} + +static UINT demo_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + +UINT status = 0; + + /* Abort. */ + if (data_pointer == UX_NULL) + { + ram_disk_rw_wait_state = 0; + return(UX_STATE_NEXT); + } + + /* Media RW fail simulation. */ + if (ram_disk_rw_fail_after < 0xFFFFFFFF) + { + ram_disk_rw_count ++; + if (ram_disk_rw_count >= ram_disk_rw_fail_after) + { + if (ram_disk_rw_fail_mode_one_shot()) + { + ram_disk_rw_fail_after = 0xFFFFFFFF; + ram_disk_rw_count = 0; + } + if (ram_disk_rw_fail_mode_bulk_in()) + ux_test_dcd_sim_slave_set_actions(fail_on_bulkin); + else if (ram_disk_rw_fail_mode_bulk_out()) + ux_test_dcd_sim_slave_set_actions(fail_on_bulkout); + else if (ram_disk_rw_fail_mode_disk()) + { + *media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x02,0x54,0x00); + return(UX_STATE_ERROR); + } + } + } + /* Media RW wait simulation. */ + if (ram_disk_rw_wait_delay) + { + if (_test_dw_minus(tx_time_get(), ram_disk_rw_wait_start) < ram_disk_rw_wait_delay) + { + ram_disk_rw_wait_state = 1; + return(UX_STATE_WAIT); + } + ram_disk_rw_wait_state = 0; + ram_disk_rw_wait_start = tx_time_get(); + } + + status = _media_driver_write(ram_disks[lun], _fx_ram_driver, data_pointer, lba, number_blocks); + if (status != UX_SUCCESS) + { + *media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x02,0x54,0x00); + return(UX_STATE_ERROR); + } + return(UX_STATE_NEXT); +} + +static UINT demo_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)number_blocks; + (void)lba; + (void)media_status; + + if (lun > 1) + return UX_STATE_ERROR; + + ram_disk_flush = UX_TRUE; + return ram_disk_flush_status; +} + +static UINT ux_test_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + + switch(event) + { + + case UX_DEVICE_INSERTION: + break; + + case UX_DEVICE_REMOVAL: + break; + +#if defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + case UX_STORAGE_MEDIA_INSERTION: + /* keep using first media. */ + if (_ux_host_class_storage_media_index((UX_HOST_CLASS_STORAGE_MEDIA*)inst) == 0) + { + _ux_host_class_storage_media_insert((UX_HOST_CLASS_STORAGE_MEDIA*)inst, 1); + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA*)inst; + media = _ux_host_class_storage_media_fx_media((UX_HOST_CLASS_STORAGE_MEDIA*)inst); + } + break; + + case UX_STORAGE_MEDIA_REMOVAL: + if (_ux_host_class_storage_media_index((UX_HOST_CLASS_STORAGE_MEDIA*)inst) == 0) + { + _ux_host_class_storage_media_remove((UX_HOST_CLASS_STORAGE_MEDIA*)inst); + storage_media = UX_NULL; + media = UX_NULL; + } + break; +#endif + + default: + break; + } + + return 0; +} + diff --git a/test/regression/usbx_standalone_host_storage_basic_test.c b/test/regression/usbx_standalone_host_storage_basic_test.c new file mode 100644 index 00000000..d2a318f9 --- /dev/null +++ b/test/regression/usbx_standalone_host_storage_basic_test.c @@ -0,0 +1,1410 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_stack.h" +#include "ux_device_class_storage.h" + +#include "ux_host_stack.h" +#include "ux_host_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +FX_MEDIA *_ux_host_class_storage_driver_media(INT i); +VOID _ux_host_class_storage_driver_entry(FX_MEDIA *media); +VOID _ux_host_class_storage_media_insert(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG format_open); +VOID _ux_host_class_storage_media_remove(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +INT _ux_host_class_storage_media_index(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +FX_MEDIA *_ux_host_class_storage_media_fx_media(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +UCHAR *_ux_host_class_storage_media_fx_media_memory(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +VOID _ux_host_class_storage_driver_read_write_notify( + VOID (*func)(UINT, UINT, UX_HOST_CLASS_STORAGE *, ULONG, ULONG, UCHAR*)); + +static VOID demo_host_media_read_write_notify(UINT fx_req, UINT fx_rc, + UX_HOST_CLASS_STORAGE *storage, + ULONG sec_start, ULONG sec_count, UCHAR* buf); + +/* Define constants. */ +#define UX_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 3) + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ +VOID _fx_ram_driver(FX_MEDIA *media_ptr); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_device_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); +static void tx_demo_thread_device_simulation_entry(ULONG); + +static UINT ux_test_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst); + +static UINT demo_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_HOST_CLASS_STORAGE_MEDIA *storage_media = UX_NULL; +static FX_MEDIA *media = UX_NULL; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static ULONG host_event; +static UX_HOST_CLASS *host_event_cls; +static VOID *host_event_inst; + +static FX_MEDIA ram_disk1; +static FX_MEDIA ram_disk2; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static UCHAR buffer1[512]; +static UCHAR buffer2[512]; + +static FX_MEDIA *ram_disks[] = {&ram_disk1, &ram_disk2}; +static UCHAR *buffers[] = {buffer1, buffer2}; +static CHAR *ram_disk_memory[] = { ram_disk_memory1, ram_disk_memory2 }; + +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_attention = 0; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static ULONG ram_disk_rw_wait_delay = 0; +static ULONG ram_disk_rw_wait_start = 0; +static UCHAR ram_disk_rw_wait_state = 0;/* 0: idle, 1: wait */ + +static CHAR ram_disk_flush = 0; +static UINT ram_disk_flush_status = UX_STATE_NEXT; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00 + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x02, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x02, 0x00 + + }; + + +/* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + + +static UX_TEST_HCD_SIM_ACTION fail_on_bulkin[] = { +/* 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_DCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x81, UX_NULL, 0, UX_ERROR, + UX_STATE_ERROR, UX_NULL, + UX_FALSE}, /* Invoke callback & no continue */ +{ 0 } +}; + + +static UX_TEST_HCD_SIM_ACTION fail_on_bulkout[] = { +/* 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_DCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_ERROR, + UX_STATE_ERROR, UX_NULL, + UX_FALSE}, /* Invoke callback & no continue */ +{ 0 } +}; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *tmp_media; + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + /* Run host tasks. */ + ux_system_tasks_run(); + + if (timeout_x10ms) + { + tx_thread_sleep(UX_MS_TO_TICK_NON_ZERO(10)); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + /* Always use first storage media. */ + status = ux_host_class_storage_media_get(storage, 0, &tmp_media); + if (status == UX_SUCCESS && storage_media == UX_NULL) + { + stepinfo("%s:%d >>>>>>>>>>>>>>> Mount media %p\n", __FILE__, __LINE__, (void*)tmp_media); + /* Use callback to check read/write. */ + _ux_host_class_storage_driver_read_write_notify(demo_host_media_read_write_notify); + /* Media must not be associated inside callback. Do it now. */ + storage_media = tmp_media; + _ux_host_class_storage_media_insert(storage_media, 1); + media = _ux_host_class_storage_media_fx_media(storage_media); + return(UX_SUCCESS); + } + if (status == UX_SUCCESS && tmp_media == storage_media) + return(UX_SUCCESS); + } + + if (status != UX_SUCCESS && storage_media != UX_NULL) + { + stepinfo("%s:%d >>>>>>>>>>>>>>> Remove media %p\n", __FILE__, __LINE__, (void*)storage_media); + _ux_host_class_storage_media_remove(storage_media); + storage_media = UX_NULL; + media = UX_NULL; + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + +static UINT sleep_break_on_connect(VOID) +{ + if (host_storage_instance_get(0) == UX_SUCCESS) + return(1); + if (error_callback_counter >= 3) + return(1); + return(0); +} + +static UINT sleep_break_on_disconnect(VOID) +{ + if (host_storage_instance_get(0) == UX_SUCCESS) + return(0); + return(1); +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *_params) +{ + + set_cfg_counter ++; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_sem_get_on_set_cfg = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_standalone_host_storage_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +ULONG mem_free; +ULONG test_n; + + + /* Inform user. */ + printf("Running STANDALONE Host Storage Basic Test.......................... "); +#ifndef UX_HOST_STANDALONE + printf("Skip\n"); + test_control_return(0); +#endif + + stepinfo("\n"); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Format the ram drive. */ + status = fx_media_format(&ram_disk1, _fx_ram_driver, ram_disk_memory1, buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + status |= fx_media_format(&ram_disk2, _fx_ram_driver, ram_disk_memory2, buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + if (status != FX_SUCCESS) + { + + /* Storage basic test error. */ + printf("ERROR #8\n"); + test_control_return(1); + } + + /* Open the ram_disk. */ + status = fx_media_open(&ram_disk1, "RAM DISK1", _fx_ram_driver, ram_disk_memory1, buffer1, 512); + status |= fx_media_open(&ram_disk2, "RAM DISK2", _fx_ram_driver, ram_disk_memory2, buffer2, 512); + if (status != FX_SUCCESS) + { + + /* Storage basic test error. */ + printf("ERROR %d\n", __LINE__); + test_control_return(1); + } + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* 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 #%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 device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 2; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_media_flush; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_flush = demo_media_flush; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_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(); + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(ux_test_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main device simulation thread. */ + status = tx_thread_create(&tx_demo_thread_device_simulation, "tx demo device simulation", tx_demo_thread_device_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 21, 21, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + stack_pointer += UX_DEMO_STACK_SIZE; + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static void tx_demo_thread_device_simulation_entry(ULONG arg) +{ + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + /* Run device tasks. */ + ux_system_tasks_run(); +#endif + /* Relinquish to other thread. */ + tx_thread_relinquish(); + } +} + +static ULONG _test_dw_minus(ULONG d0, ULONG d1) +{ + if (d0 >= d1) + return(d0 - d1); + return(d0 + (0xFFFFFFFF - d1)); +} + +static UINT _media_driver_read(FX_MEDIA *media, + VOID (*_media_driver)(FX_MEDIA *), + UCHAR *buffer, ULONG lba, ULONG n_lb) +{ +UINT status; + + if (lba == 0) + { + media->fx_media_driver_logical_sector = lba; + media->fx_media_driver_sectors = n_lb; + media->fx_media_driver_request = FX_DRIVER_BOOT_READ; + media->fx_media_driver_buffer = buffer; + _media_driver(media); + *(buffer) = 0xeb; + *(buffer+1) = 0x3c; + *(buffer+2) = 0x90; + *(buffer+21) = 0xF8; + + *(buffer+24) = 0x01; + *(buffer+26) = 0x10; + *(buffer+28) = 0x01; + + *(buffer+510) = 0x55; + *(buffer+511) = 0xaa; + ux_utility_memory_copy(buffer+0x36,"FAT12",5); + + if (media->fx_media_driver_status != FX_SUCCESS) + { + printf("%s:%d: FX error 0x%x\n", __FILE__, __LINE__, media->fx_media_driver_status); + return(UX_ERROR); + } + + lba++; + n_lb --; + buffer += 512; + } + media->fx_media_driver_logical_sector = lba; + media->fx_media_driver_sectors = n_lb; + media->fx_media_driver_request = FX_DRIVER_READ; + media->fx_media_driver_buffer = buffer; + _media_driver(media); + if (media->fx_media_driver_status != FX_SUCCESS) + { + stepinfo("%s:%d: FX error 0x%x\n", __FILE__, __LINE__, media->fx_media_driver_status); + return(UX_ERROR); + } + return(UX_SUCCESS); +} + +static UINT _media_driver_write(FX_MEDIA *media, + VOID (*_media_driver)(FX_MEDIA *), + UCHAR *buffer, ULONG lba, ULONG n_lb) +{ +UINT status; + + if (lba == 0) + { + media -> fx_media_driver_logical_sector = 0; + media -> fx_media_driver_sectors = 1; + media -> fx_media_driver_request = FX_DRIVER_BOOT_WRITE; + media -> fx_media_driver_buffer = buffer; + _media_driver(media); + + if (media->fx_media_driver_status != FX_SUCCESS) + { + printf("%s:%d: FX error 0x%x\n", __FILE__, __LINE__, media->fx_media_driver_status); + return(UX_ERROR); + } + + lba ++; + n_lb --; + buffer += 512; + } + if (n_lb) + { + media -> fx_media_driver_logical_sector = lba; + media -> fx_media_driver_sectors = n_lb; + media -> fx_media_driver_request = FX_DRIVER_WRITE; + media -> fx_media_driver_buffer = buffer; + _media_driver(media); + + if (media->fx_media_driver_status != FX_SUCCESS) + { + printf("%s:%d: FX error 0x%x\n", __FILE__, __LINE__, media->fx_media_driver_status); + return(UX_ERROR); + } + } + return(UX_SUCCESS); +} + + +static void _msc_media_read_test(const char* __file__, int __line__) +{ +UINT status; +ULONG test_n; +ULONG test_size[] = { + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 2 / 512, + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 3 / 512, + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 2 / 512 + 1}; + + stepinfo("\n%s:%d:MSC Media Read tests\n", __file__, __line__); + + if (media == UX_NULL || media -> fx_media_id == 0) + { + printf("ERROR %d: media error\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Disk read(1) test\n"); + { + status = fx_media_read(media, 48, buffer); + if (status != FX_SUCCESS) + { + printf("ERROR %d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + } + + /* Disk read multiple test. */ + for (test_n = 0; test_n < sizeof(test_size)/sizeof(test_size[0]); test_n ++) + { + + stepinfo(">>>>>>>>>>>> Disk read(%d) test\n", test_size[test_n]); + status = _media_driver_read(media, _ux_host_class_storage_driver_entry, + buffer, 0, test_size[test_n]); + if (status != UX_SUCCESS) + { + printf("ERROR %d.%ld: 0x%x\n", __LINE__, test_n, status); + test_control_return(1); + } + } +} + +static void _msc_media_write_read_test(const char* __file__, int __line__) +{ +UINT status; +ULONG test_n; +INT i; +ULONG test_size[] = { + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 2 / 512, + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 3 / 512, + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 2 / 512 + 1}; + + stepinfo("\n%s:%d:MSC Media Write & Read tests\n", __file__, __line__); + + /* Check if media still available. */ + if (media == UX_NULL || media -> fx_media_id == 0) + { + printf("ERROR %d: media error\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Disk write(1)/read(1) test\n"); + { + for(i = 0; i < 512; i ++) + buffer[i] = i; + status = fx_media_write(media, 48, buffer); + if (status != FX_SUCCESS) + { + printf("ERROR %d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_utility_memory_set(buffer, 0x00, 512); + status = fx_media_read(media, 48, buffer); + if (status != FX_SUCCESS) + { + printf("ERROR %d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + for (i = 0; i < 512; i ++) + { + if (buffer[i] != (UCHAR)i) + { + printf("ERROR %d: %d <> %d\n", __LINE__, i, buffer[i]); + test_control_return(1); + } + } + } + + /* Disk write/read multiple test. */ + for (test_n = 0; test_n < sizeof(test_size)/sizeof(test_size[0]); test_n ++) + { + stepinfo(">>>>>>>>>>>> Disk write(%ld)/read(%ld) test\n", + test_size[test_n], test_size[test_n]); + + for(i = 0; i < test_size[test_n] * 512; i ++) + buffer[i] = (UCHAR)(i + (i >> 8)); + status = _media_driver_write(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size[test_n]); + if (status != FX_SUCCESS) + { + printf("ERROR %d.%ld: 0x%x\n", __LINE__, test_n, status); + test_control_return(1); + } + _ux_utility_memory_set(buffer, 0x00, test_size[test_n] * 512); + status = _media_driver_read(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size[test_n]); + if (status != FX_SUCCESS) + { + printf("ERROR %d.%ld: 0x%x\n", __LINE__, test_n, status); + test_control_return(1); + } + for (i = 0; i < 512; i ++) + { + if (buffer[i] != (UCHAR)(i + (i >> 8))) + { + printf("ERROR %d: %d <> %d\n", __LINE__, i, buffer[i]); + test_control_return(1); + } + } + } +} + +static void _msc_enumeration_test(const char* __file__, int __line__, unsigned option) +{ +UINT status; +ULONG mem_free; +ULONG test_n; + + stepinfo("\n%s:%d:MSC Enumeration tests\n", __file__, __line__); + + stepinfo(">>>>>>>>>>>> Enumeration information collection\n"); + { + + /* Test disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check connection. */ + status = host_storage_instance_get(0); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_count_reset(); + ux_test_utility_sim_mutex_create_count_reset(); + ux_test_utility_sim_sem_create_count_reset(); + ux_test_utility_sim_sem_get_count_reset(); + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + + /* Save free memory usage. */ + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Check connection. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Log create counts for further tests. */ + rsc_enum_mutex_usage = rsc_mutex_on_set_cfg; + rsc_enum_sem_usage = rsc_sem_on_set_cfg; + rsc_enum_mem_alloc_count = rsc_mem_alloc_cnt_on_set_cfg; + /* Log create counts when instances active for further tests. */ + rsc_storage_mutex_usage = ux_test_utility_sim_mutex_create_count() - rsc_enum_mutex_usage; + rsc_storage_sem_usage = ux_test_utility_sim_sem_create_count() - rsc_enum_sem_usage; + rsc_storage_mem_alloc_count = ux_test_utility_sim_mem_alloc_count() - rsc_enum_mem_alloc_count; + + /* Lock log base for tests. */ + ux_test_utility_sim_mem_alloc_log_lock(); + + stepinfo("enum mem: %ld\n", rsc_enum_mem_alloc_count); + stepinfo("storage mem : %ld\n", rsc_storage_mem_alloc_count); + stepinfo("mem free: %ld, %ld\n", _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); + } + + /* Simulate detach and attach for FS enumeration, + and check if there is memory error in normal enumeration. + */ + if (option & (1u)) + { + stepinfo(">>>>>>>>>>>> Enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < 3; test_n++) + { + stepinfo("%4ld / 2\n", test_n); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check */ + if (host_storage_instance_get(0) == UX_SUCCESS) + { + + printf("ERROR #%d.%ld: Disconnect fail\n", __LINE__, test_n); + test_control_return(1); + } + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Wait and break on error. */ + error_callback_counter = 0; + ux_test_breakable_sleep( + (UX_MS_TO_TICK_NON_ZERO(UX_RH_ENUMERATION_RETRY_DELAY) + + UX_MS_TO_TICK_NON_ZERO(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY)) * + 50, + sleep_break_on_connect); + + /* Check */ + if (host_storage_instance_get(0) != UX_SUCCESS) + { + + printf("ERROR #%d.%ld: Enumeration fail\n", __LINE__, test_n); + test_control_return(1); + } + } + stepinfo("\n"); + } + + /* Simulate detach and attach for FS enumeration, + and test possible memory allocation error handlings. + */ + if (option & (2u)) + { + if (rsc_storage_mem_alloc_count) stepinfo(">>>>>>>>>>>> Memory errors enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_storage_mem_alloc_count; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_storage_mem_alloc_count - 1); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check */ + if (host_storage_instance_get(0) == UX_SUCCESS) + { + + stepinfo("ERROR #%d.%ld: Disconnect fail\n", __LINE__, test_n); + test_control_return(1); + } + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + stepinfo("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Set memory error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n + rsc_enum_mem_alloc_count); + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on errors. */ + ux_test_breakable_sleep(100, sleep_break_on_error); + + /* Check error */ + if (host_storage_instance_get(0) == UX_SUCCESS) + { + + /* Could be media errors, + in this case instance is ready, + check error trap. */ + if (error_callback_counter == 0) + { + stepinfo("ERROR #%d.%ld: device detected when there is memory error\n", __LINE__, test_n); + test_control_return(1); + } + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + } + ux_test_utility_sim_mem_alloc_error_generation_stop(); + if (rsc_storage_mem_alloc_count) stepinfo("\n"); + } + + /* If storage disconnected, re-connect. */ + if (host_storage_instance_get(0) != UX_SUCCESS) + { + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + ux_test_breakable_sleep( + (UX_MS_TO_TICK_NON_ZERO(UX_RH_ENUMERATION_RETRY_DELAY) + + UX_MS_TO_TICK_NON_ZERO(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY)) * + 50, + sleep_break_on_connect); + + /* Check */ + if (host_storage_instance_get(0) != UX_SUCCESS) + { + + printf("ERROR #%d: Enumeration fail\n", __LINE__); + test_control_return(1); + } + } +} + +static void _msc_media_write_read_misc_test(const char* __file__, int __line__) +{ +UINT status; +UINT test_size = UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 3 / 512; +UINT test_n; +ULONG test_start; +ULONG test_ticks; +INT i; + + stepinfo("\n%s:%d:MSC Media Read tests\n", __file__, __line__); + + if (media == UX_NULL || media -> fx_media_id == 0) + { + printf("ERROR %d.%d: media error\n", __LINE__, __line__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Disk read(%d) test - tick obtain\n", test_size); + test_start = tx_time_get(); + status = _media_driver_read(media, _ux_host_class_storage_driver_entry, + buffer, 0, test_size); + test_ticks = _test_dw_minus(tx_time_get(), test_start); + if (status != UX_SUCCESS) + { + printf("ERROR %d.%d: 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + test_ticks /= 3; + stepinfo(" :: Buffer XFR time: %ld ticks\n", test_ticks); + + stepinfo(">>>>>>>>>>>> Disk write/read(%d) test - slow disk write/read\n", test_size); + for(test_n = 0; test_n < 1; test_n ++) + { + stepinfo(">>>>>>>>>>>> Disk write/read(%d) test - disk write/read\n", test_size); + for(i = 0; i < test_size * 512; i ++) + buffer[i] = (UCHAR)(i + (i >> 8)); + ram_disk_rw_wait_start = tx_time_get(); + status = _media_driver_write(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size); + if (status != FX_SUCCESS) + { + printf("ERROR %d.%d.%d: 0x%x\n", __LINE__, __line__, test_n, status); + test_control_return(1); + } + _ux_utility_memory_set(buffer, 0x00, test_size * 512); + ram_disk_rw_wait_start = tx_time_get(); + status = _media_driver_read(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size); + if (status != FX_SUCCESS) + { + printf("ERROR %d.%d.%d: 0x%x\n", __LINE__, __line__, test_n, status); + test_control_return(1); + } + for (i = 0; i < 512; i ++) + { + if (buffer[i] != (UCHAR)(i + (i >> 8))) + { + printf("ERROR %d.%d.%d: %d <> %d\n", __LINE__, __line__, test_n, i, buffer[i]); + test_control_return(1); + } + } + } +} + +static void _msc_media_insert_eject_test(const char* __file__, int __line__) +{ +UINT test_n; +UINT connected; +UINT status; + + stepinfo("\n%s:%d:MSC Media Insert/Eject tests\n", __file__, __line__); + + if (media == UX_NULL || media -> fx_media_id == 0) + { + printf("ERROR %d.%d: media error\n", __LINE__, __line__); + test_control_return(1); + } + + /* LUN Eject/Insert detection with host stack tasks run and storage media get. */ + connected = UX_TRUE; + error_counter = 0; + for (test_n = 0; test_n < 3; test_n ++) + { + + if (connected) + { + stepinfo(">>>>>>>>>>>> Disk Eject test #%d\n", __LINE__); + ram_disk_status = UX_ERROR; + ram_disk_media_attention = 0; + ram_disk_media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x02, 0x3A, 0x00); + ux_test_breakable_sleep(UX_MS_TO_TICK(UX_HOST_CLASS_STORAGE_THREAD_SLEEP_TIME) * 3 / 2, + sleep_break_on_disconnect); + connected = host_storage_instance_get(0) == UX_SUCCESS; + if (connected) + { + + printf("ERROR #%d: LUN eject fail\n", __LINE__); + error_counter ++; + continue; + } + } + + if (!connected) + { + stepinfo(">>>>>>>>>>>> Disk Insert test #%d\n", __LINE__); + ram_disk_status = UX_SUCCESS; + ram_disk_media_attention = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x06, 0x28, 0x00); + ram_disk_media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x00, 0x00, 0x00); + error_callback_counter = 0; + ux_test_breakable_sleep(UX_MS_TO_TICK(UX_HOST_CLASS_STORAGE_THREAD_SLEEP_TIME) * 3 / 2, + sleep_break_on_connect); + connected = host_storage_instance_get(0) == UX_SUCCESS; + if (!connected) + { + + printf("ERROR #%d: LUN insert fail\n", __LINE__); + error_counter ++; + continue; + } + } + } + if (error_counter > 0) + { + printf("ERROR #%d.%d: LUN change detection fail\n", __LINE__, __line__); + test_control_return(1); + } + + /* LUN Eject/Insert detection with media check (blocking). */ + error_counter = 0; + for (test_n = 0; test_n < 3; test_n ++) + { + + stepinfo(">>>>>>>>>>>> Disk Eject test #%d\n", __LINE__); + ram_disk_status = UX_ERROR; + ram_disk_media_attention = 0; + ram_disk_media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x02, 0x3A, 0x00); + status = ux_host_class_storage_media_lock(storage_media, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: LUN lock fail 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + status = ux_host_class_storage_media_check(storage_media->ux_host_class_storage_media_storage); + if (status == UX_SUCCESS) + { + printf("ERROR #%d.%d: LUN Eject fail\n", __LINE__, __line__); + test_control_return(1); + } + ux_host_class_storage_media_unlock(storage_media); + /* Unmount media. */ + _ux_host_class_storage_media_remove(storage_media); + + stepinfo(">>>>>>>>>>>> Disk Insert test #%d\n", __LINE__); + ram_disk_status = UX_SUCCESS; + ram_disk_media_attention = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x06, 0x28, 0x00); + ram_disk_media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x00, 0x00, 0x00); + status = ux_host_class_storage_media_lock(storage_media, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: LUN lock fail 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + status = ux_host_class_storage_media_check(storage_media->ux_host_class_storage_media_storage); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: LUN Insert fail 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + ux_host_class_storage_media_unlock(storage_media); + /* Mount media. */ + _ux_host_class_storage_media_insert(storage_media, 1); + media = _ux_host_class_storage_media_fx_media(storage_media); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; + + + /* Find the storage class. */ + status = host_storage_instance_get(500); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> MSC Basic test\n"); + + _msc_media_read_test(__FILE__, __LINE__); + _msc_enumeration_test(__FILE__, __LINE__, 3); +#if 0 /* Moved to read write test. */ + _msc_media_write_read_test(__FILE__, __LINE__); + _msc_media_write_read_misc_test(__FILE__, __LINE__); +#endif +#if 0 /* Moved to insert eject test. */ + _msc_media_insert_eject_test(__FILE__, __LINE__); +#endif + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +static UCHAR lun_init_done[2] = {0, 0}; +UINT status; +ULONG mstatus = UX_SLAVE_CLASS_STORAGE_SENSE_KEY_NO_SENSE; + + + (void)storage; + (void)media_id; + + if (lun == 0 && ram_disk_media_attention) + { + if (media_status) + *media_status = ram_disk_media_attention; + ram_disk_media_attention = 0; + return(UX_ERROR); + } + if (lun == 0 && ram_disk_status) + { + status = ram_disk_status; + if (media_status) + *media_status = ram_disk_media_status; + ram_disk_status_sent = UX_TRUE; + return(status); + } + + if (lun > 1) + status = (UX_ERROR); + else if (lun_init_done[lun] > 0) + status = (UX_SUCCESS); + else + { + lun_init_done[lun] ++; + mstatus = UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8); + status = (UX_ERROR); + } + + if (media_status) + *media_status = mstatus; + + return status; +} + +static UINT demo_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + +UINT status = 0; + + + status = _media_driver_read(ram_disks[lun], _fx_ram_driver, data_pointer, lba, number_blocks); + if (status != UX_SUCCESS) + { + *media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x02,0x54,0x00); + return(UX_ERROR); + } + return(UX_SUCCESS); +} + +static UINT demo_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + +UINT status = 0; + + + status = _media_driver_write(ram_disks[lun], _fx_ram_driver, data_pointer, lba, number_blocks); + if (status != UX_SUCCESS) + { + *media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x02,0x54,0x00); + return(UX_ERROR); + } + return(UX_SUCCESS); +} + +static UINT demo_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)number_blocks; + (void)lba; + (void)media_status; + + if (lun > 1) + return UX_STATE_ERROR; + + ram_disk_flush = UX_TRUE; + return ram_disk_flush_status; +} + +static UINT ux_test_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + + switch(event) + { + + case UX_DEVICE_INSERTION: + stepinfo("Function insert: %p, %p\n", (void*)cls, inst); + break; + + case UX_DEVICE_REMOVAL: + stepinfo("Function removal: %p, %p\n", (void*)cls, inst); + break; + + case UX_DEVICE_CONNECTION: + stepinfo("Device connect: %p, %p\n", (void*)cls, inst); + break; + + case UX_DEVICE_DISCONNECTION: + stepinfo("Device disconnect: %p, %p\n", (void*)cls, inst); + break; + + case UX_STORAGE_MEDIA_INSERTION: + stepinfo("Media insert: %p\n", inst); + break; + + case UX_STORAGE_MEDIA_REMOVAL: + stepinfo("Media removal: %p\n", inst); + break; + + case UX_STANDALONE_WAIT_BACKGROUND_TASK: + tx_thread_relinquish(); + + default: + break; + } + + return 0; +} + +static void dump_data(UCHAR *buf, ULONG len) +{ +ULONG l; + for(l = 0; l < len; l ++) + { + if ((l % 32) == 0) printf("\n[%4ld]", l); + printf(" %02X", buf[l]); + } + printf("\n"); +} +static VOID demo_host_media_read_write_notify(UINT fx_req, UINT fx_rc, + UX_HOST_CLASS_STORAGE *storage, + ULONG sec_start, ULONG sec_count, UCHAR* buf) +{ + UX_PARAMETER_NOT_USED(fx_req); + UX_PARAMETER_NOT_USED(fx_rc); + UX_PARAMETER_NOT_USED(storage); + UX_PARAMETER_NOT_USED(sec_start); + UX_PARAMETER_NOT_USED(sec_count); + UX_PARAMETER_NOT_USED(buf); +#if 0 + if (fx_req == FX_DRIVER_READ) + { + printf("Read(%ld,%ld) : 0x%x\n", sec_start, sec_count, fx_rc); + } + if (fx_req == FX_DRIVER_WRITE) + { + printf("Write(%ld,%ld) : 0x%x\n", sec_start, sec_count, fx_rc); + } + dump_data(buf, 1 * 512); + + printf("Ref data:"); + dump_data(ram_disk_memory1 + sec_start * 512, 1 * 512); +#endif +} diff --git a/test/regression/usbx_standalone_host_storage_insert_eject_test.c b/test/regression/usbx_standalone_host_storage_insert_eject_test.c new file mode 100644 index 00000000..d25ce9ea --- /dev/null +++ b/test/regression/usbx_standalone_host_storage_insert_eject_test.c @@ -0,0 +1,1402 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_stack.h" +#include "ux_device_class_storage.h" + +#include "ux_host_stack.h" +#include "ux_host_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +FX_MEDIA *_ux_host_class_storage_driver_media(INT i); +VOID _ux_host_class_storage_driver_entry(FX_MEDIA *media); +VOID _ux_host_class_storage_media_insert(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG format_open); +VOID _ux_host_class_storage_media_remove(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +INT _ux_host_class_storage_media_index(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +FX_MEDIA *_ux_host_class_storage_media_fx_media(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +UCHAR *_ux_host_class_storage_media_fx_media_memory(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +VOID _ux_host_class_storage_driver_read_write_notify( + VOID (*func)(UINT, UINT, UX_HOST_CLASS_STORAGE *, ULONG, ULONG, UCHAR*)); + +static VOID demo_host_media_read_write_notify(UINT fx_req, UINT fx_rc, + UX_HOST_CLASS_STORAGE *storage, + ULONG sec_start, ULONG sec_count, UCHAR* buf); + +/* Define constants. */ +#define UX_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 3) + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ +VOID _fx_ram_driver(FX_MEDIA *media_ptr); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_device_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); +static void tx_demo_thread_device_simulation_entry(ULONG); + +static UINT ux_test_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst); + +static UINT demo_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_HOST_CLASS_STORAGE_MEDIA *storage_media = UX_NULL; +static FX_MEDIA *media = UX_NULL; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static ULONG host_event; +static UX_HOST_CLASS *host_event_cls; +static VOID *host_event_inst; + +static FX_MEDIA ram_disk1; +static FX_MEDIA ram_disk2; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static UCHAR buffer1[512]; +static UCHAR buffer2[512]; + +static FX_MEDIA *ram_disks[] = {&ram_disk1, &ram_disk2}; +static UCHAR *buffers[] = {buffer1, buffer2}; +static CHAR *ram_disk_memory[] = { ram_disk_memory1, ram_disk_memory2 }; + +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_attention = 0; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static ULONG ram_disk_rw_wait_delay = 0; +static ULONG ram_disk_rw_wait_start = 0; +static UCHAR ram_disk_rw_wait_state = 0;/* 0: idle, 1: wait */ + +static CHAR ram_disk_flush = 0; +static UINT ram_disk_flush_status = UX_STATE_NEXT; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00 + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x02, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x02, 0x00 + + }; + + +/* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + + +static UX_TEST_HCD_SIM_ACTION fail_on_bulkin[] = { +/* 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_DCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x81, UX_NULL, 0, UX_ERROR, + UX_STATE_ERROR, UX_NULL, + UX_FALSE}, /* Invoke callback & no continue */ +{ 0 } +}; + + +static UX_TEST_HCD_SIM_ACTION fail_on_bulkout[] = { +/* 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_DCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_ERROR, + UX_STATE_ERROR, UX_NULL, + UX_FALSE}, /* Invoke callback & no continue */ +{ 0 } +}; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *tmp_media; + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + /* Run host tasks. */ + ux_system_tasks_run(); + + if (timeout_x10ms) + { + tx_thread_sleep(UX_MS_TO_TICK_NON_ZERO(10)); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + /* Always use first storage media. */ + status = ux_host_class_storage_media_get(storage, 0, &tmp_media); + if (status == UX_SUCCESS && storage_media == UX_NULL) + { + stepinfo("%s:%d >>>>>>>>>>>>>>> Mount media %p\n", __FILE__, __LINE__, (void*)tmp_media); + /* Use callback to check read/write. */ + _ux_host_class_storage_driver_read_write_notify(demo_host_media_read_write_notify); + /* Media must not be associated inside callback. Do it now. */ + storage_media = tmp_media; + _ux_host_class_storage_media_insert(storage_media, 1); + media = _ux_host_class_storage_media_fx_media(storage_media); + return(UX_SUCCESS); + } + if (status == UX_SUCCESS && tmp_media == storage_media) + return(UX_SUCCESS); + } + + if (status != UX_SUCCESS && storage_media != UX_NULL) + { + stepinfo("%s:%d >>>>>>>>>>>>>>> Remove media %p\n", __FILE__, __LINE__, (void*)storage_media); + _ux_host_class_storage_media_remove(storage_media); + storage_media = UX_NULL; + media = UX_NULL; + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + +static UINT sleep_break_on_connect(VOID) +{ + if (host_storage_instance_get(0) == UX_SUCCESS) + return(1); + if (error_callback_counter >= 3) + return(1); + return(0); +} + +static UINT sleep_break_on_disconnect(VOID) +{ + if (host_storage_instance_get(0) == UX_SUCCESS) + return(0); + return(1); +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *_params) +{ + + set_cfg_counter ++; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_sem_get_on_set_cfg = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_standalone_host_storage_insert_eject_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +ULONG mem_free; +ULONG test_n; + + + /* Inform user. */ + printf("Running STANDALONE Host Storage Insert Eject Test................... "); +#ifndef UX_HOST_STANDALONE + printf("Skip\n"); + test_control_return(0); +#endif + + stepinfo("\n"); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Format the ram drive. */ + status = fx_media_format(&ram_disk1, _fx_ram_driver, ram_disk_memory1, buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + status |= fx_media_format(&ram_disk2, _fx_ram_driver, ram_disk_memory2, buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + if (status != FX_SUCCESS) + { + + /* Storage basic test error. */ + printf("ERROR #8\n"); + test_control_return(1); + } + + /* Open the ram_disk. */ + status = fx_media_open(&ram_disk1, "RAM DISK1", _fx_ram_driver, ram_disk_memory1, buffer1, 512); + status |= fx_media_open(&ram_disk2, "RAM DISK2", _fx_ram_driver, ram_disk_memory2, buffer2, 512); + if (status != FX_SUCCESS) + { + + /* Storage basic test error. */ + printf("ERROR %d\n", __LINE__); + test_control_return(1); + } + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* 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 #%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 device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 2; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_media_flush; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_flush = demo_media_flush; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_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(); + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(ux_test_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main device simulation thread. */ + status = tx_thread_create(&tx_demo_thread_device_simulation, "tx demo device simulation", tx_demo_thread_device_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 21, 21, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + stack_pointer += UX_DEMO_STACK_SIZE; + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static void tx_demo_thread_device_simulation_entry(ULONG arg) +{ + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + /* Run device tasks. */ + ux_system_tasks_run(); +#endif + /* Relinquish to other thread. */ + tx_thread_relinquish(); + } +} + +static ULONG _test_dw_minus(ULONG d0, ULONG d1) +{ + if (d0 >= d1) + return(d0 - d1); + return(d0 + (0xFFFFFFFF - d1)); +} + +static UINT _media_driver_read(FX_MEDIA *media, + VOID (*_media_driver)(FX_MEDIA *), + UCHAR *buffer, ULONG lba, ULONG n_lb) +{ +UINT status; + + if (lba == 0) + { + media->fx_media_driver_logical_sector = lba; + media->fx_media_driver_sectors = n_lb; + media->fx_media_driver_request = FX_DRIVER_BOOT_READ; + media->fx_media_driver_buffer = buffer; + _media_driver(media); + *(buffer) = 0xeb; + *(buffer+1) = 0x3c; + *(buffer+2) = 0x90; + *(buffer+21) = 0xF8; + + *(buffer+24) = 0x01; + *(buffer+26) = 0x10; + *(buffer+28) = 0x01; + + *(buffer+510) = 0x55; + *(buffer+511) = 0xaa; + ux_utility_memory_copy(buffer+0x36,"FAT12",5); + + if (media->fx_media_driver_status != FX_SUCCESS) + { + printf("%s:%d: FX error 0x%x\n", __FILE__, __LINE__, media->fx_media_driver_status); + return(UX_ERROR); + } + + lba++; + n_lb --; + buffer += 512; + } + media->fx_media_driver_logical_sector = lba; + media->fx_media_driver_sectors = n_lb; + media->fx_media_driver_request = FX_DRIVER_READ; + media->fx_media_driver_buffer = buffer; + _media_driver(media); + if (media->fx_media_driver_status != FX_SUCCESS) + { + stepinfo("%s:%d: FX error 0x%x\n", __FILE__, __LINE__, media->fx_media_driver_status); + return(UX_ERROR); + } + return(UX_SUCCESS); +} + +static UINT _media_driver_write(FX_MEDIA *media, + VOID (*_media_driver)(FX_MEDIA *), + UCHAR *buffer, ULONG lba, ULONG n_lb) +{ +UINT status; + + if (lba == 0) + { + media -> fx_media_driver_logical_sector = 0; + media -> fx_media_driver_sectors = 1; + media -> fx_media_driver_request = FX_DRIVER_BOOT_WRITE; + media -> fx_media_driver_buffer = buffer; + _media_driver(media); + + if (media->fx_media_driver_status != FX_SUCCESS) + { + printf("%s:%d: FX error 0x%x\n", __FILE__, __LINE__, media->fx_media_driver_status); + return(UX_ERROR); + } + + lba ++; + n_lb --; + buffer += 512; + } + if (n_lb) + { + media -> fx_media_driver_logical_sector = lba; + media -> fx_media_driver_sectors = n_lb; + media -> fx_media_driver_request = FX_DRIVER_WRITE; + media -> fx_media_driver_buffer = buffer; + _media_driver(media); + + if (media->fx_media_driver_status != FX_SUCCESS) + { + printf("%s:%d: FX error 0x%x\n", __FILE__, __LINE__, media->fx_media_driver_status); + return(UX_ERROR); + } + } + return(UX_SUCCESS); +} + + +static void _msc_media_read_test(const char* __file__, int __line__) +{ +UINT status; +ULONG test_n; +ULONG test_size[] = { + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 2 / 512, + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 3 / 512, + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 2 / 512 + 1}; + + stepinfo("\n%s:%d:MSC Media Read tests\n", __file__, __line__); + + if (media == UX_NULL || media -> fx_media_id == 0) + { + printf("ERROR %d: media error\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Disk read(1) test\n"); + { + status = fx_media_read(media, 48, buffer); + if (status != FX_SUCCESS) + { + printf("ERROR %d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + } + + /* Disk read multiple test. */ + for (test_n = 0; test_n < sizeof(test_size)/sizeof(test_size[0]); test_n ++) + { + + stepinfo(">>>>>>>>>>>> Disk read(%d) test\n", test_size[test_n]); + status = _media_driver_read(media, _ux_host_class_storage_driver_entry, + buffer, 0, test_size[test_n]); + if (status != UX_SUCCESS) + { + printf("ERROR %d.%ld: 0x%x\n", __LINE__, test_n, status); + test_control_return(1); + } + } +} + +static void _msc_media_write_read_test(const char* __file__, int __line__) +{ +UINT status; +ULONG test_n; +INT i; +ULONG test_size[] = { + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 2 / 512, + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 3 / 512, + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 2 / 512 + 1}; + + stepinfo("\n%s:%d:MSC Media Write & Read tests\n", __file__, __line__); + + /* Check if media still available. */ + if (media == UX_NULL || media -> fx_media_id == 0) + { + printf("ERROR %d: media error\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Disk write(1)/read(1) test\n"); + { + for(i = 0; i < 512; i ++) + buffer[i] = i; + status = fx_media_write(media, 48, buffer); + if (status != FX_SUCCESS) + { + printf("ERROR %d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_utility_memory_set(buffer, 0x00, 512); + status = fx_media_read(media, 48, buffer); + if (status != FX_SUCCESS) + { + printf("ERROR %d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + for (i = 0; i < 512; i ++) + { + if (buffer[i] != (UCHAR)i) + { + printf("ERROR %d: %d <> %d\n", __LINE__, i, buffer[i]); + test_control_return(1); + } + } + } + + /* Disk write/read multiple test. */ + for (test_n = 0; test_n < sizeof(test_size)/sizeof(test_size[0]); test_n ++) + { + stepinfo(">>>>>>>>>>>> Disk write(%ld)/read(%ld) test\n", + test_size[test_n], test_size[test_n]); + + for(i = 0; i < test_size[test_n] * 512; i ++) + buffer[i] = (UCHAR)(i + (i >> 8)); + status = _media_driver_write(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size[test_n]); + if (status != FX_SUCCESS) + { + printf("ERROR %d.%ld: 0x%x\n", __LINE__, test_n, status); + test_control_return(1); + } + _ux_utility_memory_set(buffer, 0x00, test_size[test_n] * 512); + status = _media_driver_read(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size[test_n]); + if (status != FX_SUCCESS) + { + printf("ERROR %d.%ld: 0x%x\n", __LINE__, test_n, status); + test_control_return(1); + } + for (i = 0; i < 512; i ++) + { + if (buffer[i] != (UCHAR)(i + (i >> 8))) + { + printf("ERROR %d: %d <> %d\n", __LINE__, i, buffer[i]); + test_control_return(1); + } + } + } +} + +static void _msc_enumeration_test(const char* __file__, int __line__, unsigned option) +{ +UINT status; +ULONG mem_free; +ULONG test_n; + + stepinfo("\n%s:%d:MSC Enumeration tests\n", __file__, __line__); + + stepinfo(">>>>>>>>>>>> Enumeration information collection\n"); + { + + /* Test disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check connection. */ + status = host_storage_instance_get(0); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_count_reset(); + ux_test_utility_sim_mutex_create_count_reset(); + ux_test_utility_sim_sem_create_count_reset(); + ux_test_utility_sim_sem_get_count_reset(); + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + + /* Save free memory usage. */ + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Check connection. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Log create counts for further tests. */ + rsc_enum_mutex_usage = rsc_mutex_on_set_cfg; + rsc_enum_sem_usage = rsc_sem_on_set_cfg; + rsc_enum_mem_alloc_count = rsc_mem_alloc_cnt_on_set_cfg; + /* Log create counts when instances active for further tests. */ + rsc_storage_mutex_usage = ux_test_utility_sim_mutex_create_count() - rsc_enum_mutex_usage; + rsc_storage_sem_usage = ux_test_utility_sim_sem_create_count() - rsc_enum_sem_usage; + rsc_storage_mem_alloc_count = ux_test_utility_sim_mem_alloc_count() - rsc_enum_mem_alloc_count; + + /* Lock log base for tests. */ + ux_test_utility_sim_mem_alloc_log_lock(); + + stepinfo("enum mem: %ld\n", rsc_enum_mem_alloc_count); + stepinfo("storage mem : %ld\n", rsc_storage_mem_alloc_count); + stepinfo("mem free: %ld, %ld\n", _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); + } + + /* Simulate detach and attach for FS enumeration, + and check if there is memory error in normal enumeration. + */ + if (option & (1u)) + { + stepinfo(">>>>>>>>>>>> Enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < 3; test_n++) + { + stepinfo("%4ld / 2\n", test_n); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check */ + if (host_storage_instance_get(0) == UX_SUCCESS) + { + + printf("ERROR #%d.%ld: Disconnect fail\n", __LINE__, test_n); + test_control_return(1); + } + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Wait and break on error. */ + error_callback_counter = 0; + ux_test_breakable_sleep( + (UX_MS_TO_TICK_NON_ZERO(UX_RH_ENUMERATION_RETRY_DELAY) + + UX_MS_TO_TICK_NON_ZERO(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY)) * + 50, + sleep_break_on_connect); + + /* Check */ + if (host_storage_instance_get(0) != UX_SUCCESS) + { + + printf("ERROR #%d.%ld: Enumeration fail\n", __LINE__, test_n); + test_control_return(1); + } + } + stepinfo("\n"); + } + + /* Simulate detach and attach for FS enumeration, + and test possible memory allocation error handlings. + */ + if (option & (2u)) + { + if (rsc_storage_mem_alloc_count) stepinfo(">>>>>>>>>>>> Memory errors enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_storage_mem_alloc_count; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_storage_mem_alloc_count - 1); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check */ + if (host_storage_instance_get(0) == UX_SUCCESS) + { + + stepinfo("ERROR #%d.%ld: Disconnect fail\n", __LINE__, test_n); + test_control_return(1); + } + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + stepinfo("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Set memory error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n + rsc_enum_mem_alloc_count); + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on errors. */ + ux_test_breakable_sleep(100, sleep_break_on_error); + + /* Check error */ + if (host_storage_instance_get(0) == UX_SUCCESS) + { + + /* Could be media errors, + in this case instance is ready, + check error trap. */ + if (error_callback_counter == 0) + { + stepinfo("ERROR #%d.%ld: device detected when there is memory error\n", __LINE__, test_n); + test_control_return(1); + } + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + } + ux_test_utility_sim_mem_alloc_error_generation_stop(); + if (rsc_storage_mem_alloc_count) stepinfo("\n"); + } + + /* If storage disconnected, re-connect. */ + if (host_storage_instance_get(0) != UX_SUCCESS) + { + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + ux_test_breakable_sleep( + (UX_MS_TO_TICK_NON_ZERO(UX_RH_ENUMERATION_RETRY_DELAY) + + UX_MS_TO_TICK_NON_ZERO(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY)) * + 50, + sleep_break_on_connect); + + /* Check */ + if (host_storage_instance_get(0) != UX_SUCCESS) + { + + printf("ERROR #%d: Enumeration fail\n", __LINE__); + test_control_return(1); + } + } +} + +static void _msc_media_write_read_misc_test(const char* __file__, int __line__) +{ +UINT status; +UINT test_size = UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 3 / 512; +UINT test_n; +ULONG test_start; +ULONG test_ticks; +INT i; + + stepinfo("\n%s:%d:MSC Media Read tests\n", __file__, __line__); + + if (media == UX_NULL || media -> fx_media_id == 0) + { + printf("ERROR %d.%d: media error\n", __LINE__, __line__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Disk read(%d) test - tick obtain\n", test_size); + test_start = tx_time_get(); + status = _media_driver_read(media, _ux_host_class_storage_driver_entry, + buffer, 0, test_size); + test_ticks = _test_dw_minus(tx_time_get(), test_start); + if (status != UX_SUCCESS) + { + printf("ERROR %d.%d: 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + test_ticks /= 3; + stepinfo(" :: Buffer XFR time: %ld ticks\n", test_ticks); + + stepinfo(">>>>>>>>>>>> Disk write/read(%d) test - slow disk write/read\n", test_size); + for(test_n = 0; test_n < 1; test_n ++) + { + stepinfo(">>>>>>>>>>>> Disk write/read(%d) test - disk write/read\n", test_size); + for(i = 0; i < test_size * 512; i ++) + buffer[i] = (UCHAR)(i + (i >> 8)); + ram_disk_rw_wait_start = tx_time_get(); + status = _media_driver_write(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size); + if (status != FX_SUCCESS) + { + printf("ERROR %d.%d.%d: 0x%x\n", __LINE__, __line__, test_n, status); + test_control_return(1); + } + _ux_utility_memory_set(buffer, 0x00, test_size * 512); + ram_disk_rw_wait_start = tx_time_get(); + status = _media_driver_read(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size); + if (status != FX_SUCCESS) + { + printf("ERROR %d.%d.%d: 0x%x\n", __LINE__, __line__, test_n, status); + test_control_return(1); + } + for (i = 0; i < 512; i ++) + { + if (buffer[i] != (UCHAR)(i + (i >> 8))) + { + printf("ERROR %d.%d.%d: %d <> %d\n", __LINE__, __line__, test_n, i, buffer[i]); + test_control_return(1); + } + } + } +} + +static void _msc_media_insert_eject_test(const char* __file__, int __line__) +{ +UINT test_n; +UINT connected; +UINT status; + + stepinfo("\n%s:%d:MSC Media Insert/Eject tests\n", __file__, __line__); + + if (media == UX_NULL || media -> fx_media_id == 0) + { + printf("ERROR %d.%d: media error\n", __LINE__, __line__); + test_control_return(1); + } + + /* LUN Eject/Insert detection with host stack tasks run and storage media get. */ + connected = UX_TRUE; + error_counter = 0; + for (test_n = 0; test_n < 3; test_n ++) + { + + if (connected) + { + stepinfo(">>>>>>>>>>>> Disk Eject test #%d\n", __LINE__); + ram_disk_status = UX_ERROR; + ram_disk_media_attention = 0; + ram_disk_media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x02, 0x3A, 0x00); + ux_test_breakable_sleep(UX_MS_TO_TICK(UX_HOST_CLASS_STORAGE_THREAD_SLEEP_TIME) * 3 / 2, + sleep_break_on_disconnect); + connected = host_storage_instance_get(0) == UX_SUCCESS; + if (connected) + { + + printf("ERROR #%d: LUN eject fail\n", __LINE__); + error_counter ++; + continue; + } + } + + if (!connected) + { + stepinfo(">>>>>>>>>>>> Disk Insert test #%d\n", __LINE__); + ram_disk_status = UX_SUCCESS; + ram_disk_media_attention = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x06, 0x28, 0x00); + ram_disk_media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x00, 0x00, 0x00); + error_callback_counter = 0; + ux_test_breakable_sleep(UX_MS_TO_TICK(UX_HOST_CLASS_STORAGE_THREAD_SLEEP_TIME) * 3 / 2, + sleep_break_on_connect); + connected = host_storage_instance_get(0) == UX_SUCCESS; + if (!connected) + { + + printf("ERROR #%d: LUN insert fail\n", __LINE__); + error_counter ++; + continue; + } + } + } + if (error_counter > 0) + { + printf("ERROR #%d.%d: LUN change detection fail\n", __LINE__, __line__); + test_control_return(1); + } + + /* LUN Eject/Insert detection with media check (blocking). */ + error_counter = 0; + for (test_n = 0; test_n < 3; test_n ++) + { + + stepinfo(">>>>>>>>>>>> Disk Eject test #%d\n", __LINE__); + ram_disk_status = UX_ERROR; + ram_disk_media_attention = 0; + ram_disk_media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x02, 0x3A, 0x00); + status = ux_host_class_storage_media_lock(storage_media, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: LUN lock fail 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + status = ux_host_class_storage_media_check(storage_media->ux_host_class_storage_media_storage); + if (status == UX_SUCCESS) + { + printf("ERROR #%d.%d: LUN Eject fail\n", __LINE__, __line__); + test_control_return(1); + } + ux_host_class_storage_media_unlock(storage_media); + /* Unmount media. */ + _ux_host_class_storage_media_remove(storage_media); + + stepinfo(">>>>>>>>>>>> Disk Insert test #%d\n", __LINE__); + ram_disk_status = UX_SUCCESS; + ram_disk_media_attention = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x06, 0x28, 0x00); + ram_disk_media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x00, 0x00, 0x00); + status = ux_host_class_storage_media_lock(storage_media, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: LUN lock fail 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + status = ux_host_class_storage_media_check(storage_media->ux_host_class_storage_media_storage); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: LUN Insert fail 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + ux_host_class_storage_media_unlock(storage_media); + /* Mount media. */ + _ux_host_class_storage_media_insert(storage_media, 1); + media = _ux_host_class_storage_media_fx_media(storage_media); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; + + + /* Find the storage class. */ + status = host_storage_instance_get(500); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> MSC Insert Eject test\n"); + + _msc_media_insert_eject_test(__FILE__, __LINE__); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +static UCHAR lun_init_done[2] = {0, 0}; +UINT status; +ULONG mstatus = UX_SLAVE_CLASS_STORAGE_SENSE_KEY_NO_SENSE; + + + (void)storage; + (void)media_id; + + if (lun == 0 && ram_disk_media_attention) + { + if (media_status) + *media_status = ram_disk_media_attention; + ram_disk_media_attention = 0; + return(UX_ERROR); + } + if (lun == 0 && ram_disk_status) + { + status = ram_disk_status; + if (media_status) + *media_status = ram_disk_media_status; + ram_disk_status_sent = UX_TRUE; + return(status); + } + + if (lun > 1) + status = (UX_ERROR); + else if (lun_init_done[lun] > 0) + status = (UX_SUCCESS); + else + { + lun_init_done[lun] ++; + mstatus = UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8); + status = (UX_ERROR); + } + + if (media_status) + *media_status = mstatus; + + return status; +} + +static UINT demo_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + +UINT status = 0; + + + status = _media_driver_read(ram_disks[lun], _fx_ram_driver, data_pointer, lba, number_blocks); + if (status != UX_SUCCESS) + { + *media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x02,0x54,0x00); + return(UX_ERROR); + } + return(UX_SUCCESS); +} + +static UINT demo_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + +UINT status = 0; + + + status = _media_driver_write(ram_disks[lun], _fx_ram_driver, data_pointer, lba, number_blocks); + if (status != UX_SUCCESS) + { + *media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x02,0x54,0x00); + return(UX_ERROR); + } + return(UX_SUCCESS); +} + +static UINT demo_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)number_blocks; + (void)lba; + (void)media_status; + + if (lun > 1) + return UX_STATE_ERROR; + + ram_disk_flush = UX_TRUE; + return ram_disk_flush_status; +} + +static UINT ux_test_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + + switch(event) + { + + case UX_DEVICE_INSERTION: + stepinfo("Function insert: %p, %p\n", (void*)cls, inst); + break; + + case UX_DEVICE_REMOVAL: + stepinfo("Function removal: %p, %p\n", (void*)cls, inst); + break; + + case UX_DEVICE_CONNECTION: + stepinfo("Device connect: %p, %p\n", (void*)cls, inst); + break; + + case UX_DEVICE_DISCONNECTION: + stepinfo("Device disconnect: %p, %p\n", (void*)cls, inst); + break; + + case UX_STORAGE_MEDIA_INSERTION: + stepinfo("Media insert: %p\n", inst); + break; + + case UX_STORAGE_MEDIA_REMOVAL: + stepinfo("Media removal: %p\n", inst); + break; + + case UX_STANDALONE_WAIT_BACKGROUND_TASK: + tx_thread_relinquish(); + + default: + break; + } + + return 0; +} + +static void dump_data(UCHAR *buf, ULONG len) +{ +ULONG l; + for(l = 0; l < len; l ++) + { + if ((l % 32) == 0) printf("\n[%4ld]", l); + printf(" %02X", buf[l]); + } + printf("\n"); +} +static VOID demo_host_media_read_write_notify(UINT fx_req, UINT fx_rc, + UX_HOST_CLASS_STORAGE *storage, + ULONG sec_start, ULONG sec_count, UCHAR* buf) +{ + UX_PARAMETER_NOT_USED(fx_req); + UX_PARAMETER_NOT_USED(fx_rc); + UX_PARAMETER_NOT_USED(storage); + UX_PARAMETER_NOT_USED(sec_start); + UX_PARAMETER_NOT_USED(sec_count); + UX_PARAMETER_NOT_USED(buf); +#if 0 + if (fx_req == FX_DRIVER_READ) + { + printf("Read(%ld,%ld) : 0x%x\n", sec_start, sec_count, fx_rc); + } + if (fx_req == FX_DRIVER_WRITE) + { + printf("Write(%ld,%ld) : 0x%x\n", sec_start, sec_count, fx_rc); + } + dump_data(buf, 1 * 512); + + printf("Ref data:"); + dump_data(ram_disk_memory1 + sec_start * 512, 1 * 512); +#endif +} diff --git a/test/regression/usbx_standalone_host_storage_read_write_test.c b/test/regression/usbx_standalone_host_storage_read_write_test.c new file mode 100644 index 00000000..a8ad6481 --- /dev/null +++ b/test/regression/usbx_standalone_host_storage_read_write_test.c @@ -0,0 +1,1517 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_stack.h" +#include "ux_device_class_storage.h" + +#include "ux_host_stack.h" +#include "ux_host_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +FX_MEDIA *_ux_host_class_storage_driver_media(INT i); +VOID _ux_host_class_storage_driver_entry(FX_MEDIA *media); +VOID _ux_host_class_storage_media_insert(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG format_open); +VOID _ux_host_class_storage_media_remove(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +INT _ux_host_class_storage_media_index(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +FX_MEDIA *_ux_host_class_storage_media_fx_media(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +UCHAR *_ux_host_class_storage_media_fx_media_memory(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +VOID _ux_host_class_storage_driver_read_write_notify( + VOID (*func)(UINT, UINT, UX_HOST_CLASS_STORAGE *, ULONG, ULONG, UCHAR*)); + +static VOID demo_host_media_read_write_notify(UINT fx_req, UINT fx_rc, + UX_HOST_CLASS_STORAGE *storage, + ULONG sec_start, ULONG sec_count, UCHAR* buf); + +/* Define constants. */ +#define UX_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 3) + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ +VOID _fx_ram_driver(FX_MEDIA *media_ptr); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_device_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); +static void tx_demo_thread_device_simulation_entry(ULONG); + +static UINT ux_test_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst); + +static UINT demo_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_HOST_CLASS_STORAGE_MEDIA *storage_media = UX_NULL; +static FX_MEDIA *media = UX_NULL; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static ULONG host_event; +static UX_HOST_CLASS *host_event_cls; +static VOID *host_event_inst; + +static FX_MEDIA ram_disk1; +static FX_MEDIA ram_disk2; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static UCHAR buffer1[512]; +static UCHAR buffer2[512]; + +static FX_MEDIA *ram_disks[] = {&ram_disk1, &ram_disk2}; +static UCHAR *buffers[] = {buffer1, buffer2}; +static CHAR *ram_disk_memory[] = { ram_disk_memory1, ram_disk_memory2 }; + +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_attention = 0; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static ULONG ram_disk_rw_wait_delay = 0; +static ULONG ram_disk_rw_wait_start = 0; +static UCHAR ram_disk_rw_wait_state = 0;/* 0: idle, 1: wait */ + +static UCHAR ram_disk_rw_disconnect = 0;/* device disconnect while read/write in progress */ +static ULONG ram_disk_rw_disconnect_count = 0; + +static CHAR ram_disk_flush = 0; +static UINT ram_disk_flush_status = UX_STATE_NEXT; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00 + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x02, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x02, 0x00 + + }; + + +/* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + + +static UX_TEST_HCD_SIM_ACTION fail_on_bulkin[] = { +/* 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_DCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x81, UX_NULL, 0, UX_ERROR, + UX_STATE_ERROR, UX_NULL, + UX_FALSE}, /* Invoke callback & no continue */ +{ 0 } +}; + + +static UX_TEST_HCD_SIM_ACTION fail_on_bulkout[] = { +/* 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_DCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_ERROR, + UX_STATE_ERROR, UX_NULL, + UX_FALSE}, /* Invoke callback & no continue */ +{ 0 } +}; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *tmp_media; + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + /* Run host tasks. */ + ux_system_tasks_run(); + + if (timeout_x10ms) + { + tx_thread_sleep(UX_MS_TO_TICK_NON_ZERO(10)); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + /* Always use first storage media. */ + status = ux_host_class_storage_media_get(storage, 0, &tmp_media); + if (status == UX_SUCCESS && storage_media == UX_NULL) + { + stepinfo("%s:%d >>>>>>>>>>>>>>> Mount media %p\n", __FILE__, __LINE__, (void*)tmp_media); + /* Use callback to check read/write. */ + _ux_host_class_storage_driver_read_write_notify(demo_host_media_read_write_notify); + /* Media must not be associated inside callback. Do it now. */ + storage_media = tmp_media; + _ux_host_class_storage_media_insert(storage_media, 1); + media = _ux_host_class_storage_media_fx_media(storage_media); + return(UX_SUCCESS); + } + if (status == UX_SUCCESS && tmp_media == storage_media) + return(UX_SUCCESS); + } + + if (status != UX_SUCCESS && storage_media != UX_NULL) + { + stepinfo("%s:%d >>>>>>>>>>>>>>> Remove media %p\n", __FILE__, __LINE__, (void*)storage_media); + _ux_host_class_storage_media_remove(storage_media); + storage_media = UX_NULL; + media = UX_NULL; + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + +static UINT sleep_break_on_connect(VOID) +{ + if (host_storage_instance_get(0) == UX_SUCCESS) + return(1); + if (error_callback_counter >= 3) + return(1); + return(0); +} + +static UINT sleep_break_on_disconnect(VOID) +{ + if (host_storage_instance_get(0) == UX_SUCCESS) + return(0); + return(1); +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *_params) +{ + + set_cfg_counter ++; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_sem_get_on_set_cfg = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_standalone_host_storage_read_write_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +ULONG mem_free; +ULONG test_n; + + + /* Inform user. */ + printf("Running STANDALONE Host Storage Read Write Test..................... "); +#ifndef UX_HOST_STANDALONE + printf("Skip\n"); + test_control_return(0); +#endif + + stepinfo("\n"); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Format the ram drive. */ + status = fx_media_format(&ram_disk1, _fx_ram_driver, ram_disk_memory1, buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + status |= fx_media_format(&ram_disk2, _fx_ram_driver, ram_disk_memory2, buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + if (status != FX_SUCCESS) + { + + /* Storage basic test error. */ + printf("ERROR #8\n"); + test_control_return(1); + } + + /* Open the ram_disk. */ + status = fx_media_open(&ram_disk1, "RAM DISK1", _fx_ram_driver, ram_disk_memory1, buffer1, 512); + status |= fx_media_open(&ram_disk2, "RAM DISK2", _fx_ram_driver, ram_disk_memory2, buffer2, 512); + if (status != FX_SUCCESS) + { + + /* Storage basic test error. */ + printf("ERROR %d\n", __LINE__); + test_control_return(1); + } + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* 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 #%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 device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 2; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_media_flush; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_flush = demo_media_flush; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_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(); + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(ux_test_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main device simulation thread. */ + status = tx_thread_create(&tx_demo_thread_device_simulation, "tx demo device simulation", tx_demo_thread_device_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 21, 21, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + stack_pointer += UX_DEMO_STACK_SIZE; + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static void tx_demo_thread_device_simulation_entry(ULONG arg) +{ + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + /* Run device tasks. */ + ux_system_tasks_run(); +#endif + /* Relinquish to other thread. */ + tx_thread_relinquish(); + } +} + +static ULONG _test_dw_minus(ULONG d0, ULONG d1) +{ + if (d0 >= d1) + return(d0 - d1); + return(d0 + (0xFFFFFFFF - d1)); +} + +static UINT _media_driver_read(FX_MEDIA *media, + VOID (*_media_driver)(FX_MEDIA *), + UCHAR *buffer, ULONG lba, ULONG n_lb) +{ +UINT status; + + if (lba == 0) + { + media->fx_media_driver_logical_sector = lba; + media->fx_media_driver_sectors = n_lb; + media->fx_media_driver_request = FX_DRIVER_BOOT_READ; + media->fx_media_driver_buffer = buffer; + _media_driver(media); + *(buffer) = 0xeb; + *(buffer+1) = 0x3c; + *(buffer+2) = 0x90; + *(buffer+21) = 0xF8; + + *(buffer+24) = 0x01; + *(buffer+26) = 0x10; + *(buffer+28) = 0x01; + + *(buffer+510) = 0x55; + *(buffer+511) = 0xaa; + ux_utility_memory_copy(buffer+0x36,"FAT12",5); + + if (media->fx_media_driver_status != FX_SUCCESS) + { + printf("%s:%d: FX error 0x%x\n", __FILE__, __LINE__, media->fx_media_driver_status); + return(UX_ERROR); + } + + lba++; + n_lb --; + buffer += 512; + } + media->fx_media_driver_logical_sector = lba; + media->fx_media_driver_sectors = n_lb; + media->fx_media_driver_request = FX_DRIVER_READ; + media->fx_media_driver_buffer = buffer; + _media_driver(media); + if (media->fx_media_driver_status != FX_SUCCESS) + { + stepinfo("%s:%d: FX error 0x%x\n", __FILE__, __LINE__, media->fx_media_driver_status); + return(UX_ERROR); + } + return(UX_SUCCESS); +} + +static UINT _media_driver_write(FX_MEDIA *media, + VOID (*_media_driver)(FX_MEDIA *), + UCHAR *buffer, ULONG lba, ULONG n_lb) +{ +UINT status; + + if (lba == 0) + { + media -> fx_media_driver_logical_sector = 0; + media -> fx_media_driver_sectors = 1; + media -> fx_media_driver_request = FX_DRIVER_BOOT_WRITE; + media -> fx_media_driver_buffer = buffer; + _media_driver(media); + + if (media->fx_media_driver_status != FX_SUCCESS) + { + printf("%s:%d: FX error 0x%x\n", __FILE__, __LINE__, media->fx_media_driver_status); + return(UX_ERROR); + } + + lba ++; + n_lb --; + buffer += 512; + } + if (n_lb) + { + media -> fx_media_driver_logical_sector = lba; + media -> fx_media_driver_sectors = n_lb; + media -> fx_media_driver_request = FX_DRIVER_WRITE; + media -> fx_media_driver_buffer = buffer; + _media_driver(media); + + if (media->fx_media_driver_status != FX_SUCCESS) + { + stepinfo("%s:%d: FX error 0x%x\n", __FILE__, __LINE__, media->fx_media_driver_status); + return(UX_ERROR); + } + } + return(UX_SUCCESS); +} + + +static void _msc_media_read_test(const char* __file__, int __line__) +{ +UINT status; +ULONG test_n; +ULONG test_size[] = { + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 2 / 512, + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 3 / 512, + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 2 / 512 + 1}; + + stepinfo("\n%s:%d:MSC Media Read tests\n", __file__, __line__); + + if (media == UX_NULL || media -> fx_media_id == 0) + { + printf("ERROR %d: media error\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Disk read(1) test\n"); + { + status = fx_media_read(media, 48, buffer); + if (status != FX_SUCCESS) + { + printf("ERROR %d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + } + + /* Disk read multiple test. */ + for (test_n = 0; test_n < sizeof(test_size)/sizeof(test_size[0]); test_n ++) + { + + stepinfo(">>>>>>>>>>>> Disk read(%ld) test\n", test_size[test_n]); + status = _media_driver_read(media, _ux_host_class_storage_driver_entry, + buffer, 0, test_size[test_n]); + if (status != UX_SUCCESS) + { + printf("ERROR %d.%ld: 0x%x\n", __LINE__, test_n, status); + test_control_return(1); + } + } +} + +static void _msc_media_write_read_test(const char* __file__, int __line__) +{ +UINT status; +ULONG test_n; +INT i; +ULONG test_size[] = { + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 2 / 512, + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 3 / 512, + UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 2 / 512 + 1}; + + stepinfo("\n%s:%d:MSC Media Write & Read tests\n", __file__, __line__); + + /* Check if media still available. */ + if (media == UX_NULL || media -> fx_media_id == 0) + { + printf("ERROR %d: media error\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Disk write(1)/read(1) test\n"); + { + for(i = 0; i < 512; i ++) + buffer[i] = i; + status = fx_media_write(media, 48, buffer); + if (status != FX_SUCCESS) + { + printf("ERROR %d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_utility_memory_set(buffer, 0x00, 512); + status = fx_media_read(media, 48, buffer); + if (status != FX_SUCCESS) + { + printf("ERROR %d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + for (i = 0; i < 512; i ++) + { + if (buffer[i] != (UCHAR)i) + { + printf("ERROR %d: %d <> %d\n", __LINE__, i, buffer[i]); + test_control_return(1); + } + } + } + + /* Disk write/read multiple test. */ + for (test_n = 0; test_n < sizeof(test_size)/sizeof(test_size[0]); test_n ++) + { + stepinfo(">>>>>>>>>>>> Disk write(%ld)/read(%ld) test\n", + test_size[test_n], test_size[test_n]); + + for(i = 0; i < test_size[test_n] * 512; i ++) + buffer[i] = (UCHAR)(i + (i >> 8)); + status = _media_driver_write(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size[test_n]); + if (status != FX_SUCCESS) + { + printf("ERROR %d.%ld: 0x%x\n", __LINE__, test_n, status); + test_control_return(1); + } + _ux_utility_memory_set(buffer, 0x00, test_size[test_n] * 512); + status = _media_driver_read(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size[test_n]); + if (status != FX_SUCCESS) + { + printf("ERROR %d.%ld: 0x%x\n", __LINE__, test_n, status); + test_control_return(1); + } + for (i = 0; i < 512; i ++) + { + if (buffer[i] != (UCHAR)(i + (i >> 8))) + { + printf("ERROR %d: %d <> %d\n", __LINE__, i, buffer[i]); + test_control_return(1); + } + } + } +} + +static void _msc_enumeration_test(const char* __file__, int __line__, unsigned option) +{ +UINT status; +ULONG mem_free; +ULONG test_n; + + stepinfo("\n%s:%d:MSC Enumeration tests\n", __file__, __line__); + + stepinfo(">>>>>>>>>>>> Enumeration information collection\n"); + { + + /* Test disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check connection. */ + status = host_storage_instance_get(0); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_count_reset(); + ux_test_utility_sim_mutex_create_count_reset(); + ux_test_utility_sim_sem_create_count_reset(); + ux_test_utility_sim_sem_get_count_reset(); + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + + /* Save free memory usage. */ + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Check connection. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Log create counts for further tests. */ + rsc_enum_mutex_usage = rsc_mutex_on_set_cfg; + rsc_enum_sem_usage = rsc_sem_on_set_cfg; + rsc_enum_mem_alloc_count = rsc_mem_alloc_cnt_on_set_cfg; + /* Log create counts when instances active for further tests. */ + rsc_storage_mutex_usage = ux_test_utility_sim_mutex_create_count() - rsc_enum_mutex_usage; + rsc_storage_sem_usage = ux_test_utility_sim_sem_create_count() - rsc_enum_sem_usage; + rsc_storage_mem_alloc_count = ux_test_utility_sim_mem_alloc_count() - rsc_enum_mem_alloc_count; + + /* Lock log base for tests. */ + ux_test_utility_sim_mem_alloc_log_lock(); + + stepinfo("enum mem: %ld\n", rsc_enum_mem_alloc_count); + stepinfo("storage mem : %ld\n", rsc_storage_mem_alloc_count); + stepinfo("mem free: %ld, %ld\n", _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); + } + + /* Simulate detach and attach for FS enumeration, + and check if there is memory error in normal enumeration. + */ + if (option & (1u)) + { + stepinfo(">>>>>>>>>>>> Enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < 3; test_n++) + { + stepinfo("%4ld / 2\n", test_n); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check */ + if (host_storage_instance_get(0) == UX_SUCCESS) + { + + printf("ERROR #%d.%ld: Disconnect fail\n", __LINE__, test_n); + test_control_return(1); + } + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Wait and break on error. */ + error_callback_counter = 0; + ux_test_breakable_sleep( + (UX_MS_TO_TICK_NON_ZERO(UX_RH_ENUMERATION_RETRY_DELAY) + + UX_MS_TO_TICK_NON_ZERO(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY)) * + 50, + sleep_break_on_connect); + + /* Check */ + if (host_storage_instance_get(0) != UX_SUCCESS) + { + + printf("ERROR #%d.%ld: Enumeration fail\n", __LINE__, test_n); + test_control_return(1); + } + } + stepinfo("\n"); + } + + /* Simulate detach and attach for FS enumeration, + and test possible memory allocation error handlings. + */ + if (option & (2u)) + { + if (rsc_storage_mem_alloc_count) stepinfo(">>>>>>>>>>>> Memory errors enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_storage_mem_alloc_count; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_storage_mem_alloc_count - 1); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check */ + if (host_storage_instance_get(0) == UX_SUCCESS) + { + + stepinfo("ERROR #%d.%ld: Disconnect fail\n", __LINE__, test_n); + test_control_return(1); + } + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + stepinfo("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Set memory error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n + rsc_enum_mem_alloc_count); + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on errors. */ + ux_test_breakable_sleep(100, sleep_break_on_error); + + /* Check error */ + if (host_storage_instance_get(0) == UX_SUCCESS) + { + + /* Could be media errors, + in this case instance is ready, + check error trap. */ + if (error_callback_counter == 0) + { + stepinfo("ERROR #%d.%ld: device detected when there is memory error\n", __LINE__, test_n); + test_control_return(1); + } + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + } + ux_test_utility_sim_mem_alloc_error_generation_stop(); + if (rsc_storage_mem_alloc_count) stepinfo("\n"); + } + + /* If storage disconnected, re-connect. */ + if (host_storage_instance_get(0) != UX_SUCCESS) + { + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + ux_test_breakable_sleep( + (UX_MS_TO_TICK_NON_ZERO(UX_RH_ENUMERATION_RETRY_DELAY) + + UX_MS_TO_TICK_NON_ZERO(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY)) * + 50, + sleep_break_on_connect); + + /* Check */ + if (host_storage_instance_get(0) != UX_SUCCESS) + { + + printf("ERROR #%d: Enumeration fail\n", __LINE__); + test_control_return(1); + } + } +} + +static void _msc_media_write_read_misc_test(const char* __file__, int __line__) +{ +UINT status; +UINT test_size = UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 3 / 512; +UINT test_n; +ULONG test_start; +ULONG test_ticks; +INT i; + + stepinfo("\n%s:%d:MSC Media Read tests\n", __file__, __line__); + + if (media == UX_NULL || media -> fx_media_id == 0) + { + printf("ERROR %d.%d: media error\n", __LINE__, __line__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Disk read(%d) test - tick obtain\n", test_size); + test_start = tx_time_get(); + status = _media_driver_read(media, _ux_host_class_storage_driver_entry, + buffer, 0, test_size); + test_ticks = _test_dw_minus(tx_time_get(), test_start); + if (status != UX_SUCCESS) + { + printf("ERROR %d.%d: 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + test_ticks /= 3; + stepinfo(" :: Buffer XFR time: %ld ticks\n", test_ticks); + + stepinfo(">>>>>>>>>>>> Disk write/read(%d) test - slow disk write/read\n", test_size); + for(test_n = 0; test_n < 1; test_n ++) + { + stepinfo(">>>>>>>>>>>> Disk write/read(%d) test - disk write/read\n", test_size); + for(i = 0; i < test_size * 512; i ++) + buffer[i] = (UCHAR)(i + (i >> 8)); + ram_disk_rw_wait_start = tx_time_get(); + status = _media_driver_write(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size); + if (status != FX_SUCCESS) + { + printf("ERROR %d.%d.%d: 0x%x\n", __LINE__, __line__, test_n, status); + test_control_return(1); + } + _ux_utility_memory_set(buffer, 0x00, test_size * 512); + ram_disk_rw_wait_start = tx_time_get(); + status = _media_driver_read(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size); + if (status != FX_SUCCESS) + { + printf("ERROR %d.%d.%d: 0x%x\n", __LINE__, __line__, test_n, status); + test_control_return(1); + } + for (i = 0; i < 512; i ++) + { + if (buffer[i] != (UCHAR)(i + (i >> 8))) + { + printf("ERROR %d.%d.%d: %d <> %d\n", __LINE__, __line__, test_n, i, buffer[i]); + test_control_return(1); + } + } + } +} + +static void _msc_media_write_read_disconnect_test(const char* __file__, int __line__) +{ +UINT status; +ULONG test_size = 1; +UINT i; + + stepinfo("\n%s:%d:MSC Device Disconnect on Media Writing & Reading tests\n", __file__, __line__); + + /* Check if media still available. */ + if (media == UX_NULL || media -> fx_media_id == 0) + { + printf("ERROR %d: media error\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Device disconnect on writing test\n"); + ram_disk_rw_disconnect = 1; + ram_disk_rw_disconnect_count = 0; + for(i = 0; i < test_size * 512; i ++) + buffer[i] = (UCHAR)(i + (i >> 8)); + status = _media_driver_write(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size); + ux_test_breakable_sleep(100, sleep_break_on_error); + if (status == FX_SUCCESS) + { + printf("%s:%d:%d expect write fail\n", __file__, __line__, __LINE__); + test_control_return(1); + } + if (ram_disk_rw_disconnect_count != 1) + { + printf("%s:%d:%d expect write once\n", __file__, __line__, __LINE__); + test_control_return(1); + } + if (host_storage_instance_get(0) == UX_SUCCESS) + { + printf("%s:%d:%d expect device disconnect\n", __file__, __line__, __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Device connect after disconnect on writing check\n"); + error_callback_counter = 0; + ram_disk_rw_disconnect = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on errors. */ + ux_test_breakable_sleep(1000, sleep_break_on_connect); + + /* Check error */ + if (host_storage_instance_get(0) != UX_SUCCESS) + { + printf("%s:%d:%d device re-connect fail\n", __file__, __line__, __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Disk disconnect on reading test\n"); + ram_disk_rw_disconnect = 1; + ram_disk_rw_disconnect_count = 0; + _ux_utility_memory_set(buffer, 0x00, test_size * 512); + ram_disk_rw_wait_start = tx_time_get(); + status = _media_driver_read(media, _ux_host_class_storage_driver_entry, + buffer, 48, test_size); + ux_test_breakable_sleep(100, sleep_break_on_error); + if (status == FX_SUCCESS) + { + printf("%s:%d:%d expect read fail\n", __file__, __line__, __LINE__); + test_control_return(1); + } + if (ram_disk_rw_disconnect_count != 1) + { + printf("%s:%d:%d expect write once\n", __file__, __line__, __LINE__); + test_control_return(1); + } + if (host_storage_instance_get(0) == UX_SUCCESS) + { + printf("%s:%d:%d expect device disconnect\n", __file__, __line__, __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> Device connect after disconnect on reading check\n"); + error_callback_counter = 0; + ram_disk_rw_disconnect = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on errors. */ + ux_test_breakable_sleep(1000, sleep_break_on_connect); + + /* Check error */ + if (host_storage_instance_get(0) != UX_SUCCESS) + { + stepinfo("%s:%d:%d device re-connect fail\n", __file__, __line__, __LINE__); + test_control_return(1); + } +} + +static void _msc_media_insert_eject_test(const char* __file__, int __line__) +{ +UINT test_n; +UINT connected; +UINT status; + + stepinfo("\n%s:%d:MSC Media Insert/Eject tests\n", __file__, __line__); + + if (media == UX_NULL || media -> fx_media_id == 0) + { + printf("ERROR %d.%d: media error\n", __LINE__, __line__); + test_control_return(1); + } + + /* LUN Eject/Insert detection with host stack tasks run and storage media get. */ + connected = UX_TRUE; + error_counter = 0; + for (test_n = 0; test_n < 3; test_n ++) + { + + if (connected) + { + stepinfo(">>>>>>>>>>>> Disk Eject test #%d\n", __LINE__); + ram_disk_status = UX_ERROR; + ram_disk_media_attention = 0; + ram_disk_media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x02, 0x3A, 0x00); + ux_test_breakable_sleep(UX_MS_TO_TICK(UX_HOST_CLASS_STORAGE_THREAD_SLEEP_TIME) * 3 / 2, + sleep_break_on_disconnect); + connected = host_storage_instance_get(0) == UX_SUCCESS; + if (connected) + { + + printf("ERROR #%d: LUN eject fail\n", __LINE__); + error_counter ++; + continue; + } + } + + if (!connected) + { + stepinfo(">>>>>>>>>>>> Disk Insert test #%d\n", __LINE__); + ram_disk_status = UX_SUCCESS; + ram_disk_media_attention = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x06, 0x28, 0x00); + ram_disk_media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x00, 0x00, 0x00); + error_callback_counter = 0; + ux_test_breakable_sleep(UX_MS_TO_TICK(UX_HOST_CLASS_STORAGE_THREAD_SLEEP_TIME) * 3 / 2, + sleep_break_on_connect); + connected = host_storage_instance_get(0) == UX_SUCCESS; + if (!connected) + { + + printf("ERROR #%d: LUN insert fail\n", __LINE__); + error_counter ++; + continue; + } + } + } + if (error_counter > 0) + { + printf("ERROR #%d.%d: LUN change detection fail\n", __LINE__, __line__); + test_control_return(1); + } + + /* LUN Eject/Insert detection with media check (blocking). */ + error_counter = 0; + for (test_n = 0; test_n < 3; test_n ++) + { + + stepinfo(">>>>>>>>>>>> Disk Eject test #%d\n", __LINE__); + ram_disk_status = UX_ERROR; + ram_disk_media_attention = 0; + ram_disk_media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x02, 0x3A, 0x00); + status = ux_host_class_storage_media_lock(storage_media, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: LUN lock fail 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + status = ux_host_class_storage_media_check(storage_media->ux_host_class_storage_media_storage); + if (status == UX_SUCCESS) + { + printf("ERROR #%d.%d: LUN Eject fail\n", __LINE__, __line__); + test_control_return(1); + } + ux_host_class_storage_media_unlock(storage_media); + /* Unmount media. */ + _ux_host_class_storage_media_remove(storage_media); + + stepinfo(">>>>>>>>>>>> Disk Insert test #%d\n", __LINE__); + ram_disk_status = UX_SUCCESS; + ram_disk_media_attention = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x06, 0x28, 0x00); + ram_disk_media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x00, 0x00, 0x00); + status = ux_host_class_storage_media_lock(storage_media, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: LUN lock fail 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + status = ux_host_class_storage_media_check(storage_media->ux_host_class_storage_media_storage); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: LUN Insert fail 0x%x\n", __LINE__, __line__, status); + test_control_return(1); + } + ux_host_class_storage_media_unlock(storage_media); + /* Mount media. */ + _ux_host_class_storage_media_insert(storage_media, 1); + media = _ux_host_class_storage_media_fx_media(storage_media); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; + + + /* Find the storage class. */ + status = host_storage_instance_get(500); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>> MSC Read Write test\n"); + + _msc_media_write_read_disconnect_test(__FILE__, __LINE__); + _msc_media_write_read_test(__FILE__, __LINE__); + _msc_media_write_read_misc_test(__FILE__, __LINE__); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +static UCHAR lun_init_done[2] = {0, 0}; +UINT status; +ULONG mstatus = UX_SLAVE_CLASS_STORAGE_SENSE_KEY_NO_SENSE; + + + (void)storage; + (void)media_id; + + if (lun == 0 && ram_disk_media_attention) + { + if (media_status) + *media_status = ram_disk_media_attention; + ram_disk_media_attention = 0; + return(UX_ERROR); + } + if (lun == 0 && ram_disk_status) + { + status = ram_disk_status; + if (media_status) + *media_status = ram_disk_media_status; + ram_disk_status_sent = UX_TRUE; + return(status); + } + + if (lun > 1) + status = (UX_ERROR); + else if (lun_init_done[lun] > 0) + status = (UX_SUCCESS); + else + { + lun_init_done[lun] ++; + mstatus = UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8); + status = (UX_ERROR); + } + + if (media_status) + *media_status = mstatus; + + return status; +} + +static UINT demo_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + +UINT status = 0; + + if (ram_disk_rw_disconnect) + { + ram_disk_rw_disconnect_count ++; + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + return(UX_ERROR); + } + + status = _media_driver_read(ram_disks[lun], _fx_ram_driver, data_pointer, lba, number_blocks); + if (status != UX_SUCCESS) + { + *media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x02,0x54,0x00); + return(UX_ERROR); + } + return(UX_SUCCESS); +} + +static UINT demo_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + +UINT status = 0; + + if (ram_disk_rw_disconnect) + { + ram_disk_rw_disconnect_count ++; + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + return(UX_ERROR); + } + + status = _media_driver_write(ram_disks[lun], _fx_ram_driver, data_pointer, lba, number_blocks); + if (status != UX_SUCCESS) + { + *media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x02,0x54,0x00); + return(UX_ERROR); + } + return(UX_SUCCESS); +} + +static UINT demo_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)number_blocks; + (void)lba; + (void)media_status; + + if (lun > 1) + return UX_STATE_ERROR; + + ram_disk_flush = UX_TRUE; + return ram_disk_flush_status; +} + +static UINT ux_test_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + + switch(event) + { + + case UX_DEVICE_INSERTION: + stepinfo("Function insert: %p, %p\n", (void*)cls, inst); + break; + + case UX_DEVICE_REMOVAL: + stepinfo("Function removal: %p, %p\n", (void*)cls, inst); + break; + + case UX_DEVICE_CONNECTION: + stepinfo("Device connect: %p, %p\n", (void*)cls, inst); + break; + + case UX_DEVICE_DISCONNECTION: + stepinfo("Device disconnect: %p, %p\n", (void*)cls, inst); + break; + + case UX_STORAGE_MEDIA_INSERTION: + stepinfo("Media insert: %p\n", inst); + break; + + case UX_STORAGE_MEDIA_REMOVAL: + stepinfo("Media removal: %p\n", inst); + break; + + case UX_STANDALONE_WAIT_BACKGROUND_TASK: + tx_thread_relinquish(); + + default: + break; + } + + return 0; +} + +static void dump_data(UCHAR *buf, ULONG len) +{ +ULONG l; + for(l = 0; l < len; l ++) + { + if ((l % 32) == 0) printf("\n[%4ld]", l); + printf(" %02X", buf[l]); + } + printf("\n"); +} +static VOID demo_host_media_read_write_notify(UINT fx_req, UINT fx_rc, + UX_HOST_CLASS_STORAGE *storage, + ULONG sec_start, ULONG sec_count, UCHAR* buf) +{ + UX_PARAMETER_NOT_USED(fx_req); + UX_PARAMETER_NOT_USED(fx_rc); + UX_PARAMETER_NOT_USED(storage); + UX_PARAMETER_NOT_USED(sec_start); + UX_PARAMETER_NOT_USED(sec_count); + UX_PARAMETER_NOT_USED(buf); +#if 0 + if (fx_req == FX_DRIVER_READ) + { + printf("Read(%ld,%ld) : 0x%x\n", sec_start, sec_count, fx_rc); + } + if (fx_req == FX_DRIVER_WRITE) + { + printf("Write(%ld,%ld) : 0x%x\n", sec_start, sec_count, fx_rc); + } + dump_data(buf, 1 * 512); + + printf("Ref data:"); + dump_data(ram_disk_memory1 + sec_start * 512, 1 * 512); +#endif +} diff --git a/test/regression/usbx_storage_basic_memory_test.c b/test/regression/usbx_storage_basic_memory_test.c new file mode 100644 index 00000000..170fdefb --- /dev/null +++ b/test/regression/usbx_storage_basic_memory_test.c @@ -0,0 +1,812 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ +VOID _fx_ram_driver(FX_MEDIA *media_ptr); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk1; +static FX_MEDIA ram_disk2; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static UCHAR buffer1[512]; +static UCHAR buffer2[512]; + +static FX_MEDIA *ram_disks[] = {&ram_disk1, &ram_disk2}; +static UCHAR *buffers[] = {buffer1, buffer2}; +static CHAR *ram_disk_memory[] = { ram_disk_memory1, ram_disk_memory2 }; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00 + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00 + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_ext != UX_NULL && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *_params) +{ + + set_cfg_counter ++; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_sem_get_on_set_cfg = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_storage_basic_memory_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +ULONG mem_free; +ULONG test_n; + + + /* Inform user. */ + printf("Running Storage Basic Memory Test................................... "); + stepinfo("\n"); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* 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 #%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 device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 2; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_count_reset(); + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_parameter); + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + rsc_storage_mem_alloc_count = ux_test_utility_sim_mem_alloc_count(); + + /* Lock log base for tests. */ + ux_test_utility_sim_mem_alloc_log_lock(); + + stepinfo("init mem : %ld\n", rsc_storage_mem_alloc_count); + + if (rsc_storage_mem_alloc_count) stepinfo(">>>>>>>>>>>> Memory errors class register test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_storage_mem_alloc_count; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_storage_mem_alloc_count - 1); + + /* Unregister. */ + ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_entry); + + /* Update memory free level (unregister). */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d.%ld: Memory level different after re-register %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Set memory error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n); + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_parameter); + if (status == UX_SUCCESS) + { + printf("ERROR #%d.%ld: Class registered when there is memory error\n", __LINE__, test_n); + test_control_return(1); + } + } + ux_test_utility_sim_mem_alloc_error_generation_stop(); + if (rsc_storage_mem_alloc_count) stepinfo("\n"); + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_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(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG mem_free; +ULONG test_n; + + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Format the ram drive. */ + status = fx_media_format(&ram_disk1, _fx_ram_driver, ram_disk_memory1, buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + status |= fx_media_format(&ram_disk2, _fx_ram_driver, ram_disk_memory2, buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + if (status != FX_SUCCESS) + { + + /* Storage basic test error. */ + printf("ERROR #8\n"); + test_control_return(1); + } + + /* Open the ram_disk. */ + status = fx_media_open(&ram_disk1, "RAM DISK1", _fx_ram_driver, ram_disk_memory1, buffer1, 512); + status |= fx_media_open(&ram_disk2, "RAM DISK2", _fx_ram_driver, ram_disk_memory2, buffer2, 512); + if (status != FX_SUCCESS) + { + + /* Storage basic test error. */ + printf("ERROR %d\n", __LINE__); + test_control_return(1); + } + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Test disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check connection. */ + status = host_storage_instance_get(0); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_count_reset(); + ux_test_utility_sim_mutex_create_count_reset(); + ux_test_utility_sim_sem_create_count_reset(); + ux_test_utility_sim_sem_get_count_reset(); + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + + /* Save free memory usage. */ + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Check connection. */ + status = host_storage_instance_get(50); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Log create counts for further tests. */ + rsc_enum_mutex_usage = rsc_mutex_on_set_cfg; + rsc_enum_sem_usage = rsc_sem_on_set_cfg; + rsc_enum_mem_alloc_count = rsc_mem_alloc_cnt_on_set_cfg; + /* Log create counts when instances active for further tests. */ + rsc_storage_mutex_usage = ux_test_utility_sim_mutex_create_count() - rsc_enum_mutex_usage; + rsc_storage_sem_usage = ux_test_utility_sim_sem_create_count() - rsc_enum_sem_usage; + rsc_storage_mem_alloc_count = ux_test_utility_sim_mem_alloc_count() - rsc_enum_mem_alloc_count; + + /* Lock log base for tests. */ + ux_test_utility_sim_mem_alloc_log_lock(); + + stepinfo("enum mem: %ld\n", rsc_enum_mem_alloc_count); + stepinfo("storage mem : %ld\n", rsc_storage_mem_alloc_count); + stepinfo("mem free: %ld, %ld\n", _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); + + /* Simulate detach and attach for FS enumeration, + and check if there is memory error in normal enumeration. + */ + stepinfo(">>>>>>>>>>>> Enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < 3; test_n++) + { + stepinfo("%4ld / 2\n", test_n); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check */ + if (host_storage_instance_get(0) == UX_SUCCESS) + { + + printf("ERROR #%d.%ld: Disconnect fail\n", __LINE__, test_n); + test_control_return(1); + } + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on error. */ + ux_test_breakable_sleep(100, sleep_break_on_error); + + /* Check */ + if (host_storage_instance_get(0) != UX_SUCCESS) + { + + printf("ERROR #%d.%ld: Enumeration fail\n", __LINE__, test_n); + test_control_return(1); + } + } + stepinfo("\n"); + + /* Simulate detach and attach for FS enumeration, + and test possible memory allocation error handlings. + */ + if (rsc_storage_mem_alloc_count) stepinfo(">>>>>>>>>>>> Memory errors enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_storage_mem_alloc_count; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_storage_mem_alloc_count - 1); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check */ + if (host_storage_instance_get(0) == UX_SUCCESS) + { + + printf("ERROR #%d.%ld: Disconnect fail\n", __LINE__, test_n); + test_control_return(1); + } + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Set memory error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n + rsc_enum_mem_alloc_count); + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on errors. */ + ux_test_breakable_sleep(100, sleep_break_on_error); + + /* Check error */ + if (host_storage_instance_get(0) == UX_SUCCESS) + { + + /* Could be media errors, + in this case instance is ready, + check error trap. */ + if (error_callback_counter == 0) + { + printf("ERROR #%d.%ld: device detected when there is memory error\n", __LINE__, test_n); + test_control_return(1); + } + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + } + ux_test_utility_sim_mem_alloc_error_generation_stop(); + if (rsc_storage_mem_alloc_count) stepinfo("\n"); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +static UCHAR lun_init_done[2] = {0, 0}; +UINT status; +ULONG mstatus = UX_SLAVE_CLASS_STORAGE_SENSE_KEY_NO_SENSE; + + + (void)storage; + (void)media_id; + + + if (lun > 1) + status = (UX_ERROR); + else if (lun_init_done[lun] > 0) + status = (UX_SUCCESS); + else + { + lun_init_done[lun] ++; + mstatus = UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8); + status = (UX_ERROR); + } + + if (media_status) + *media_status = mstatus; + + return status; +} + +UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + +UINT status = 0; + + if(lba == 0) + { + ram_disks[lun]->fx_media_driver_logical_sector = 0; + ram_disks[lun]->fx_media_driver_sectors = 1; + ram_disks[lun]->fx_media_driver_request = FX_DRIVER_BOOT_READ; + ram_disks[lun]->fx_media_driver_buffer = data_pointer; + _fx_ram_driver(ram_disks[lun]); + *(data_pointer) = 0xeb; + *(data_pointer+1) = 0x3c; + *(data_pointer+2) = 0x90; + *(data_pointer+21) = 0xF8; + + *(data_pointer+24) = 0x01; + *(data_pointer+26) = 0x10; + *(data_pointer+28) = 0x01; + + *(data_pointer+510) = 0x55; + *(data_pointer+511) = 0xaa; + ux_utility_memory_copy(data_pointer+0x36,"FAT12",5); + + + status = ram_disks[lun]->fx_media_driver_status; + } + else + { + while(number_blocks--) + { + status = fx_media_read(ram_disks[lun],lba,data_pointer); + data_pointer+=512; + lba++; + } + } + return(status); +} + +UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + +UINT status = 0; + + if(lba == 0) + { + ram_disks[lun]->fx_media_driver_logical_sector = 0; + ram_disks[lun]->fx_media_driver_sectors = 1; + ram_disks[lun]->fx_media_driver_request = FX_DRIVER_BOOT_WRITE; + ram_disks[lun]->fx_media_driver_buffer = data_pointer; + _fx_ram_driver(ram_disks[lun]); + + status = ram_disks[lun]->fx_media_driver_status; + + } + else + { + + while(number_blocks--) + { + status = fx_media_write(ram_disks[lun],lba,data_pointer); + data_pointer+=512; + lba++; + } + return(status); + } + return(1); +} \ No newline at end of file diff --git a/test/regression/usbx_storage_direct_calls_test.c b/test/regression/usbx_storage_direct_calls_test.c new file mode 100644 index 00000000..8a45d9c9 --- /dev/null +++ b/test/regression/usbx_storage_direct_calls_test.c @@ -0,0 +1,1694 @@ +#include "usbx_test_common_storage.h" + +#include "tx_thread.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00 + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00 + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + //printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); +} + +static UINT demo_system_host_change_function(ULONG event_code, UX_HOST_CLASS *class, VOID *instance) +{ + +UINT status; + + + if (event_code == UX_DEVICE_INSERTION) + { + + status = ux_utility_semaphore_put(&storage_instance_live_semaphore); + if (status) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + } + + return 0; +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_storage_direct_calls_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + printf("Running Storage Direct Calls Test............................ "); + + status = ux_utility_semaphore_create(&storage_instance_live_semaphore, "storage_instance_live_semaphore", 0); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Initialize the free memory pointer */ + stack_pointer = (CHAR *) usbx_memory; + memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 2); + + /* Initialize USBX. Memory */ + ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL,0); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(demo_system_host_change_function); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Reset ram disk memory. */ + ux_utility_memory_set(global_ram_disk_memory, 0, UX_RAM_DISK_SIZE); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + /* Initialize the storage class parameters for reading/writing to the Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = default_device_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = default_device_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = default_device_media_status; + + /* Initilize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_parameter); + if(status!=UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + +} + + +static UINT ux_hcd_sim_host_entry_filter_transfer_request_failed_test1(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; +UX_TRANSFER *transfer_request; +UINT is_csw = UX_ERROR; +UX_MEMORY_BLOCK *dummy_memory_block_first = (UX_MEMORY_BLOCK *)dummy_usbx_memory; + + + if (function == UX_HCD_TRANSFER_REQUEST) + { + + transfer_request = parameter; + + if (transfer_request->ux_transfer_request_data_pointer != UX_NULL) + is_csw = ux_utility_memory_compare("IS_CSW", transfer_request -> ux_transfer_request_data_pointer, 6); + } + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + + /* Get Port Status requests don't return UX_SUCCESS. */ + if (status != UX_SUCCESS && function != UX_HCD_GET_PORT_STATUS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + if (function == UX_HCD_TRANSFER_REQUEST) + { + + transfer_request = parameter; + + /* Is it bulk? */ + if ((transfer_request->ux_transfer_request_endpoint->ux_endpoint_descriptor.bmAttributes & 3) == 2) + { + + status = ux_utility_semaphore_get(&transfer_request->ux_transfer_request_semaphore, UX_WAIT_FOREVER); + if (status) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + if (transfer_request->ux_transfer_request_completion_code != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + } + + /* Is this the CSW? */ + if (is_csw == UX_SUCCESS && + transfer_request -> ux_transfer_request_requested_length == 0x0d && + transfer_request -> ux_transfer_request_function == 0 && + transfer_request -> ux_transfer_request_type == 0x80 && + transfer_request -> ux_transfer_request_value == 0 && + transfer_request -> ux_transfer_request_index == 0) + { + + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + dummy_memory_block_first -> ux_memory_block_size = 0; + _ux_system -> ux_system_regular_memory_pool_start = dummy_memory_block_first; + _ux_system -> ux_system_cache_safe_memory_pool_start = dummy_memory_block_first; + } + + /* Is it bulk? */ + if ((transfer_request->ux_transfer_request_endpoint->ux_endpoint_descriptor.bmAttributes & 3) == 2) + { + + status = ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); + if (status) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + } + } + + return status; +} + +static UINT ux_hcd_sim_host_entry_filter_transfer_request_failed_test2(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; +UX_TRANSFER *transfer_request; + + + if (function == UX_HCD_TRANSFER_REQUEST) + { + + transfer_request = parameter; + + if (ux_utility_memory_compare("IS_CBW", transfer_request -> ux_transfer_request_data_pointer, 6) == UX_SUCCESS) + { + + transfer_request -> ux_transfer_request_semaphore.tx_semaphore_id++; + + return UX_SUCCESS; + } + } + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + + /* Get Port Status requests don't return UX_SUCCESS. */ + if (status != UX_SUCCESS && function != UX_HCD_GET_PORT_STATUS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + return status; +} + +static UINT ux_hcd_sim_host_entry_filter_transfer_request_failed_test3(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; +UX_TRANSFER *transfer_request; + + + if (function == UX_HCD_TRANSFER_REQUEST) + { + + transfer_request = parameter; + + if (ux_utility_memory_compare("IS_CBW", transfer_request -> ux_transfer_request_data_pointer, 6) == UX_SUCCESS) + { + + status = ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + transfer_request -> ux_transfer_request_completion_code = UX_SUCCESS; + + return UX_SUCCESS; + } + + if (ux_utility_memory_compare("IS_DATA", transfer_request -> ux_transfer_request_data_pointer, 7) == UX_SUCCESS) + { + + transfer_request -> ux_transfer_request_completion_code = UX_SUCCESS; + + transfer_request -> ux_transfer_request_semaphore.tx_semaphore_id++; + + return UX_SUCCESS; + } + } + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + + /* Get Port Status requests don't return UX_SUCCESS. */ + if (status != UX_SUCCESS && function != UX_HCD_GET_PORT_STATUS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + return status; +} + +static UINT ux_hcd_sim_host_entry_filter_transfer_request_failed_test4(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; +UX_TRANSFER *transfer_request; +static UINT csw_retries = 0; + + + if (function == UX_HCD_TRANSFER_REQUEST) + { + + transfer_request = parameter; + + if (transfer_request -> ux_transfer_request_data_pointer != UX_NULL) + { + + if (ux_utility_memory_compare("IS_CBW", transfer_request->ux_transfer_request_data_pointer, 6) == UX_SUCCESS || + ux_utility_memory_compare("IS_DATA", transfer_request->ux_transfer_request_data_pointer, 7) == UX_SUCCESS) + { + + /* Release the semaphore because sim_host_entry() won't (doesn't get invoked). */ + status = ux_utility_semaphore_put(&transfer_request->ux_transfer_request_semaphore); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + transfer_request->ux_transfer_request_completion_code = UX_SUCCESS; + + return UX_SUCCESS; + } + + if (ux_utility_memory_compare("IS_CSW", transfer_request->ux_transfer_request_data_pointer, 6) == UX_SUCCESS) + { + + if (csw_retries++ == 0) + { + + transfer_request->ux_transfer_request_semaphore.tx_semaphore_id++; + } + + transfer_request->ux_transfer_request_completion_code = UX_ERROR; + + return UX_SUCCESS; + } + } + else + { + + /* Is this a port reset? */ + if (transfer_request->ux_transfer_request_data_pointer == UX_NULL && + transfer_request->ux_transfer_request_requested_length == 0 && + transfer_request->ux_transfer_request_function == UX_CLEAR_FEATURE && + (transfer_request->ux_transfer_request_type == (UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_ENDPOINT)) && + transfer_request->ux_transfer_request_value == UX_ENDPOINT_HALT) + { + + transfer_request->ux_transfer_request_completion_code = UX_SUCCESS; + + return UX_SUCCESS; + } + } + } + else if (function == UX_HCD_RESET_ENDPOINT) + { + + return UX_SUCCESS; + } + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + + /* Get Port Status requests don't return UX_SUCCESS. */ + if (status != UX_SUCCESS && function != UX_HCD_GET_PORT_STATUS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + return status; +} + +static UINT ux_hcd_sim_host_entry_filter_transfer_request_failed_test5(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; +UX_TRANSFER *transfer_request; + + + if (function == UX_HCD_TRANSFER_REQUEST) + { + + transfer_request = parameter; + + if (ux_utility_memory_compare("IS_UFI", transfer_request -> ux_transfer_request_data_pointer, 6) == UX_SUCCESS) + { + + status = ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + transfer_request -> ux_transfer_request_completion_code = UX_SUCCESS; + + return UX_SUCCESS; + } + + if (ux_utility_memory_compare("IS_DATA", transfer_request -> ux_transfer_request_data_pointer, 7) == UX_SUCCESS) + { + + transfer_request -> ux_transfer_request_completion_code = UX_SUCCESS; + + transfer_request -> ux_transfer_request_semaphore.tx_semaphore_id++; + + return UX_SUCCESS; + } + } + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + + /* Get Port Status requests don't return UX_SUCCESS. */ + if (status != UX_SUCCESS && function != UX_HCD_GET_PORT_STATUS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + return status; +} + +static UINT ux_hcd_sim_host_entry_filter_transfer_request_failed_test6(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; +UX_TRANSFER *transfer_request; + + + if (function == UX_HCD_TRANSFER_REQUEST) + { + + transfer_request = parameter; + + if (ux_utility_memory_compare("IS_UFI", transfer_request -> ux_transfer_request_data_pointer, 6) == UX_SUCCESS) + { + + status = ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + transfer_request -> ux_transfer_request_completion_code = UX_SUCCESS; + + return UX_SUCCESS; + } + + if (ux_utility_memory_compare("IS_DATA", transfer_request -> ux_transfer_request_data_pointer, 7) == UX_SUCCESS) + { + + transfer_request -> ux_transfer_request_completion_code = UX_SUCCESS; + + transfer_request -> ux_transfer_request_semaphore.tx_semaphore_id++; + + return UX_SUCCESS; + } + } + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + + /* Get Port Status requests don't return UX_SUCCESS. */ + if (status != UX_SUCCESS && function != UX_HCD_GET_PORT_STATUS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + return status; +} + +static UINT ux_hcd_sim_host_entry_filter_transfer_request_failed_test7(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; +UX_TRANSFER *transfer_request; + + + if (function == UX_HCD_TRANSFER_REQUEST) + { + + transfer_request = parameter; + + if (transfer_request -> ux_transfer_request_data_pointer != UX_NULL) + { + + if (ux_utility_memory_compare("IS_UFI", transfer_request->ux_transfer_request_data_pointer, 6) == UX_SUCCESS || + ux_utility_memory_compare("IS_DATA", transfer_request->ux_transfer_request_data_pointer, 7) == UX_SUCCESS) + { + + /* Release the semaphore because sim_host_entry() won't (doesn't get invoked). */ + status = ux_utility_semaphore_put(&transfer_request->ux_transfer_request_semaphore); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + transfer_request->ux_transfer_request_completion_code = UX_SUCCESS; + + return UX_SUCCESS; + } + + /* Is this the status request via interrupt endpoint? */ + if (ux_utility_memory_compare("IS_INTERRUPT", transfer_request->ux_transfer_request_data_pointer, 12) == UX_SUCCESS) + { + + /* We never created the interrupt endpoint's semaphore, so it will fail without having to do this. */ + //transfer_request->ux_transfer_request_semaphore.tx_semaphore_id++; + + transfer_request->ux_transfer_request_completion_code = UX_SUCCESS; + + return UX_SUCCESS; + } + } + } + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + + /* Get Port Status requests don't return UX_SUCCESS. */ + if (status != UX_SUCCESS && function != UX_HCD_GET_PORT_STATUS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + return status; +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS host_class; +UX_DEVICE device; +UX_CONFIGURATION configuration; +UX_MEMORY_BLOCK *dummy_memory_block_first = (UX_MEMORY_BLOCK *)dummy_usbx_memory; +UX_MEMORY_BLOCK *original_regular_memory_block = _ux_system -> ux_system_regular_memory_pool_start; +UX_MEMORY_BLOCK *original_cache_safe_memory_block = _ux_system -> ux_system_cache_safe_memory_pool_start; +UX_INTERFACE interface; +UX_HOST_CLASS_COMMAND command; +UX_HOST_CLASS_STORAGE *storage_instance; +TX_SEMAPHORE storage_instance_semaphore_copy; +ALIGN_TYPE tmp; +UCHAR thread_stack[UX_HOST_CLASS_STORAGE_THREAD_STACK_SIZE]; +UX_HCD *hcd; +UCHAR data_pointer[128]; +UX_ENDPOINT interrupt_endpoint; +UCHAR interrupt_endopint_data_pointer[128]; +UX_TRANSFER *transfer_request_ptr; + + + /* Format the ram drive. */ + status = fx_media_format(&global_ram_disk, _fx_ram_driver, global_ram_disk_memory, global_ram_disk_working_buffer, 512, "RAM DISK", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* Check the media format status. */ + if (status != FX_SUCCESS) + { + + /* Storage basic test error. */ + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Open the ram_disk. */ + status = fx_media_open(&global_ram_disk, "RAM DISK", _fx_ram_driver, global_ram_disk_memory, global_ram_disk_working_buffer, 512); + + /* Check the media open status. */ + if (status != FX_SUCCESS) + { + + /* Storage basic test error. */ + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Find the storage class */ + status = host_storage_instance_get(); + if (status != UX_SUCCESS) + { + + /* Storage basic test error. */ + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } +#ifdef UX_HOST_CLASS_STORAGE_INCLUDE_LEGACY_PROTOCOL_SUPPORT + /**************************************************/ + /**************************************************/ + /** Testing _ux_host_class_storage_transport_cbi() **/ + /**************************************************/ + /**************************************************/ + + /**************************************************/ + /** Test case: status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT); (first one) fails **/ + /**************************************************/ + + /* Swap the hcd entry function. */ + hcd = UX_DEVICE_HCD_GET(global_storage -> ux_host_class_storage_device); + tmp = (ULONG)hcd -> ux_hcd_entry_function; + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter_transfer_request_failed_test6; + + /* Make sure we use the bulk out endpoint. */ + global_storage -> ux_host_class_storage_cbw[UX_HOST_CLASS_STORAGE_CBW_FLAGS] = UX_HOST_CLASS_STORAGE_DATA_OUT; + + /* Make the UFI portion easily detectable from filter function. */ + ux_utility_memory_copy(global_storage -> ux_host_class_storage_cbw + UX_HOST_CLASS_STORAGE_CBW_CB, "IS_UFI", 6); + + /* Make the data something easily detectable from filter function. */ + ux_utility_memory_copy(data_pointer, "IS_DATA", 7); + + /* Make sure storage_thread_entry() doesn't send a request at the same time. */ + status = _ux_utility_semaphore_get(&global_storage -> ux_host_class_storage_semaphore, UX_WAIT_FOREVER); + if(status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + status = _ux_host_class_storage_transport_cbi(global_storage, data_pointer); + if(status != UX_TRANSFER_TIMEOUT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + status = _ux_utility_semaphore_put(&global_storage -> ux_host_class_storage_semaphore); + if(status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + hcd -> ux_hcd_entry_function = (UINT (*) (struct UX_HCD_STRUCT *, UINT, VOID *))tmp; + global_storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_semaphore.tx_semaphore_id--; + + /**************************************************/ + /** Test case: status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT); (second one) fails **/ + /**************************************************/ + + /* Swap the hcd entry function. */ + hcd = UX_DEVICE_HCD_GET(global_storage -> ux_host_class_storage_device); + tmp = (ULONG)hcd -> ux_hcd_entry_function; + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter_transfer_request_failed_test7; + + /* The framework doesn't describe an interrupt endpoint, so give it one. */ + transfer_request_ptr = &interrupt_endpoint.ux_endpoint_transfer_request; + transfer_request_ptr->ux_transfer_request_data_pointer = interrupt_endopint_data_pointer; + transfer_request_ptr->ux_transfer_request_endpoint = &interrupt_endpoint; + interrupt_endpoint.ux_endpoint_device = global_storage -> ux_host_class_storage_device; + interrupt_endpoint.ux_endpoint_descriptor.bmAttributes = UX_INTERRUPT_ENDPOINT_IN; + global_storage -> ux_host_class_storage_interrupt_endpoint = &interrupt_endpoint; + ux_utility_memory_copy(transfer_request_ptr -> ux_transfer_request_data_pointer, "IS_INTERRUPT", 12); + + /* Make sure we use the bulk out endpoint. */ + global_storage -> ux_host_class_storage_cbw[UX_HOST_CLASS_STORAGE_CBW_FLAGS] = UX_HOST_CLASS_STORAGE_DATA_OUT; + + /* Make the UFI portion easily detectable from filter function. */ + ux_utility_memory_copy(global_storage -> ux_host_class_storage_cbw + UX_HOST_CLASS_STORAGE_CBW_CB, "IS_UFI", 6); + + /* Make the data something easily detectable from filter function. */ + ux_utility_memory_copy(data_pointer, "IS_DATA", 7); + + /* Make sure storage_thread_entry() doesn't send a request at the same time. */ + status = _ux_utility_semaphore_get(&global_storage -> ux_host_class_storage_semaphore, UX_WAIT_FOREVER); + if(status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + status = _ux_host_class_storage_transport_cbi(global_storage, data_pointer); + if(status != TX_SEMAPHORE_ERROR) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + status = _ux_utility_semaphore_put(&global_storage -> ux_host_class_storage_semaphore); + if(status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + hcd -> ux_hcd_entry_function = (UINT (*) (struct UX_HCD_STRUCT *, UINT, VOID *))tmp; + global_storage -> ux_host_class_storage_interrupt_endpoint = UX_NULL; + + /**************************************************/ + /**************************************************/ + /** Testing _ux_host_class_storage_transport_cb() **/ + /**************************************************/ + /**************************************************/ + + /**************************************************/ + /** Test case: status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT); fails **/ + /**************************************************/ + + /* Swap the hcd entry function. */ + hcd = UX_DEVICE_HCD_GET(global_storage -> ux_host_class_storage_device); + tmp = (ULONG)hcd -> ux_hcd_entry_function; + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter_transfer_request_failed_test5; + + /* Make sure we use the bulk out endpoint. */ + global_storage -> ux_host_class_storage_cbw[UX_HOST_CLASS_STORAGE_CBW_FLAGS] = UX_HOST_CLASS_STORAGE_DATA_OUT; + + /* Make the UFI portion easily detectable from filter function. */ + ux_utility_memory_copy(global_storage -> ux_host_class_storage_cbw + UX_HOST_CLASS_STORAGE_CBW_CB, "IS_UFI", 6); + + /* Make the data something easily detectable from filter function. */ + ux_utility_memory_copy(data_pointer, "IS_DATA", 7); + + /* Make sure storage_thread_entry() doesn't send a request at the same time. */ + status = _ux_utility_semaphore_get(&global_storage -> ux_host_class_storage_semaphore, UX_WAIT_FOREVER); + if(status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + status = _ux_host_class_storage_transport_cb(global_storage, data_pointer); + if(status != UX_TRANSFER_TIMEOUT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + status = _ux_utility_semaphore_put(&global_storage -> ux_host_class_storage_semaphore); + if(status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + hcd -> ux_hcd_entry_function = (UINT (*) (struct UX_HCD_STRUCT *, UINT, VOID *))tmp; + global_storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_semaphore.tx_semaphore_id--; +#endif + /**************************************************/ + /**************************************************/ + /** Testing _ux_host_class_storage_transport_bo() **/ + /**************************************************/ + /**************************************************/ + + /**************************************************/ + /** Test case: status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT); (first one) fails **/ + /**************************************************/ + + /* Swap the hcd entry function. */ + hcd = UX_DEVICE_HCD_GET(global_storage -> ux_host_class_storage_device); + tmp = (ALIGN_TYPE)hcd -> ux_hcd_entry_function; + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter_transfer_request_failed_test2; + + /* Make the CBW something easily detectable from filter function. */ + ux_utility_memory_copy(global_storage -> ux_host_class_storage_cbw, "IS_CBW", 6); + + /* Make sure storage_thread_entry() doesn't send a request at the same time. */ + status = _ux_utility_semaphore_get(&global_storage -> ux_host_class_storage_semaphore, UX_WAIT_FOREVER); + if(status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + status = _ux_host_class_storage_transport_bo(global_storage, UX_NULL); + if(status != UX_TRANSFER_TIMEOUT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + status = _ux_utility_semaphore_put(&global_storage -> ux_host_class_storage_semaphore); + if(status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + hcd -> ux_hcd_entry_function = (UINT (*) (struct UX_HCD_STRUCT *, UINT, VOID *))tmp; + global_storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_semaphore.tx_semaphore_id--; + + /**************************************************/ + /** Test case: status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT); (second one) fails **/ + /**************************************************/ + + /* Swap the hcd entry function. */ + hcd = UX_DEVICE_HCD_GET(global_storage -> ux_host_class_storage_device); + tmp = (ALIGN_TYPE)hcd -> ux_hcd_entry_function; + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter_transfer_request_failed_test3; + + /* Make the CBW something easily detectable from filter function. */ + ux_utility_memory_copy(global_storage -> ux_host_class_storage_cbw, "IS_CBW", 6); + + /* Make sure we use the bulk out endpoint. */ + global_storage -> ux_host_class_storage_cbw[UX_HOST_CLASS_STORAGE_CBW_FLAGS] = UX_HOST_CLASS_STORAGE_DATA_OUT; + + /* Make the data something easily detectable from filter function. */ + ux_utility_memory_copy(data_pointer, "IS_DATA", 7); + + _ux_utility_long_put(global_storage -> ux_host_class_storage_cbw + UX_HOST_CLASS_STORAGE_CBW_DATA_LENGTH, 10); + + /* Make sure storage_thread_entry() doesn't send a request at the same time. */ + status = _ux_utility_semaphore_get(&global_storage -> ux_host_class_storage_semaphore, UX_WAIT_FOREVER); + if(status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + status = _ux_host_class_storage_transport_bo(global_storage, data_pointer); + if(status != UX_TRANSFER_TIMEOUT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + status = _ux_utility_semaphore_put(&global_storage -> ux_host_class_storage_semaphore); + if(status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + hcd -> ux_hcd_entry_function = (UINT (*) (struct UX_HCD_STRUCT *, UINT, VOID *))tmp; + global_storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_semaphore.tx_semaphore_id--; + + /**************************************************/ + /** Test case: status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT); (third one) fails **/ + /**************************************************/ + + /* Swap the hcd entry function. */ + hcd = UX_DEVICE_HCD_GET(global_storage -> ux_host_class_storage_device); + tmp = (ALIGN_TYPE)hcd -> ux_hcd_entry_function; + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter_transfer_request_failed_test4; + + /* Make the CBW something easily detectable from filter function. */ + ux_utility_memory_copy(global_storage -> ux_host_class_storage_cbw, "IS_CBW", 6); + + /* Make the data something easily detectable from filter function. */ + ux_utility_memory_copy(data_pointer, "IS_DATA", 7); + + /* Make sure we use the bulk out endpoint. */ + global_storage -> ux_host_class_storage_cbw[UX_HOST_CLASS_STORAGE_CBW_FLAGS] = UX_HOST_CLASS_STORAGE_DATA_OUT; + + /* Make the CSW something easily detectable from filter function. */ + ux_utility_memory_copy(global_storage -> ux_host_class_storage_csw, "IS_CSW", 6); + + _ux_utility_long_put(global_storage -> ux_host_class_storage_cbw + UX_HOST_CLASS_STORAGE_CBW_DATA_LENGTH, 10); + + /* Make sure storage_thread_entry() doesn't send a request at the same time. */ + status = _ux_utility_semaphore_get(&global_storage -> ux_host_class_storage_semaphore, UX_WAIT_FOREVER); + if(status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + status = _ux_host_class_storage_transport_bo(global_storage, data_pointer); + if(status != UX_ERROR) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + status = _ux_utility_semaphore_put(&global_storage -> ux_host_class_storage_semaphore); + if(status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + hcd -> ux_hcd_entry_function = (UINT (*) (struct UX_HCD_STRUCT *, UINT, VOID *))tmp; + global_storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_semaphore.tx_semaphore_id--; + + /**************************************************/ + /**************************************************/ + /** Testing _ux_host_class_storage_media_capacity_get() **/ + /**************************************************/ + /**************************************************/ + + /**************************************************/ + /** Test case: capacity_response = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_STORAGE_READ_FORMAT_RESPONSE_LENGTH); fails **/ + /**************************************************/ + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + dummy_memory_block_first -> ux_memory_block_size = 0; + _ux_system -> ux_system_regular_memory_pool_start = dummy_memory_block_first; + _ux_system -> ux_system_cache_safe_memory_pool_start = dummy_memory_block_first; + + status = _ux_host_class_storage_media_capacity_get(global_storage); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + _ux_system -> ux_system_regular_memory_pool_start = original_regular_memory_block; + _ux_system -> ux_system_cache_safe_memory_pool_start = original_cache_safe_memory_block; + + /**************************************************/ + /** Test case: capacity_response = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_STORAGE_READ_CAPACITY_RESPONSE_LENGTH); fails **/ + /** How: "But Nick, that's impossible! It's simply too dangerous! You'll die!" Modify the memory blocks _after_ the first memory allocate via transfer request. **/ + /**************************************************/ + + ux_utility_memory_copy(global_storage -> ux_host_class_storage_csw, "IS_CSW", 6); + + /* Swap the hcd entry function. */ + hcd = UX_DEVICE_HCD_GET(global_storage -> ux_host_class_storage_device); + tmp = (ALIGN_TYPE)hcd -> ux_hcd_entry_function; + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter_transfer_request_failed_test1; + + /* Make sure storage_thread_entry() doesn't send a request at the same time. */ + status = _ux_utility_semaphore_get(&global_storage -> ux_host_class_storage_semaphore, UX_WAIT_FOREVER); + if(status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + status = _ux_host_class_storage_media_capacity_get(global_storage); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + status = _ux_utility_semaphore_put(&global_storage -> ux_host_class_storage_semaphore); + if(status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + _ux_system -> ux_system_regular_memory_pool_start = original_regular_memory_block; + _ux_system -> ux_system_cache_safe_memory_pool_start = original_cache_safe_memory_block; + hcd -> ux_hcd_entry_function = (UINT (*) (struct UX_HCD_STRUCT *, UINT, VOID *))tmp; + + /**************************************************/ + /**************************************************/ + /** Testing _ux_host_class_storage_request_sense() **/ + /**************************************************/ + /**************************************************/ + + /**************************************************/ + /** Test case: request_sense_response = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH); fails **/ + /**************************************************/ + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + dummy_memory_block_first -> ux_memory_block_size = 0; + _ux_system -> ux_system_regular_memory_pool_start = dummy_memory_block_first; + _ux_system -> ux_system_cache_safe_memory_pool_start = dummy_memory_block_first; + + status = _ux_host_class_storage_request_sense(global_storage); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + _ux_system -> ux_system_regular_memory_pool_start = original_regular_memory_block; + _ux_system -> ux_system_cache_safe_memory_pool_start = original_cache_safe_memory_block; + + /**************************************************/ + /**************************************************/ + /** Testing _ux_host_class_storage_media_open() **/ + /**************************************************/ + /**************************************************/ + + /**************************************************/ + /** Test case: storage_media -> ux_host_class_storage_media_memory = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_STORAGE_MEMORY_BUFFER_SIZE); fails **/ + /**************************************************/ + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + dummy_memory_block_first -> ux_memory_block_size = 0; + _ux_system -> ux_system_regular_memory_pool_start = dummy_memory_block_first; + _ux_system -> ux_system_cache_safe_memory_pool_start = dummy_memory_block_first; + + status = _ux_host_class_storage_media_open(global_storage, 0); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + _ux_system -> ux_system_regular_memory_pool_start = original_regular_memory_block; + _ux_system -> ux_system_cache_safe_memory_pool_start = original_cache_safe_memory_block; + + /**************************************************/ + /**************************************************/ + /** Testing _ux_host_class_storage_media_mount() **/ + /**************************************************/ + /**************************************************/ + + /**************************************************/ + /** Test case: sector_memory = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, storage -> ux_host_class_storage_sector_size); fails **/ + /**************************************************/ + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + dummy_memory_block_first -> ux_memory_block_size = 0; + _ux_system -> ux_system_regular_memory_pool_start = dummy_memory_block_first; + _ux_system -> ux_system_cache_safe_memory_pool_start = dummy_memory_block_first; + + status = _ux_host_class_storage_media_mount(global_storage, 0); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + _ux_system -> ux_system_regular_memory_pool_start = original_regular_memory_block; + _ux_system -> ux_system_cache_safe_memory_pool_start = original_cache_safe_memory_block; + + /**************************************************/ + /**************************************************/ + /** Testing _ux_host_class_storage_media_format_capacity_get() **/ + /**************************************************/ + /**************************************************/ + + /**************************************************/ + /** Test case: read_format_capacity_response = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_STORAGE_READ_FORMAT_RESPONSE_LENGTH); fails **/ + /**************************************************/ + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + dummy_memory_block_first -> ux_memory_block_size = 0; + _ux_system -> ux_system_regular_memory_pool_start = dummy_memory_block_first; + _ux_system -> ux_system_cache_safe_memory_pool_start = dummy_memory_block_first; + + status = _ux_host_class_storage_media_format_capacity_get(global_storage); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + _ux_system -> ux_system_regular_memory_pool_start = original_regular_memory_block; + _ux_system -> ux_system_cache_safe_memory_pool_start = original_cache_safe_memory_block; + + /**************************************************/ + /**************************************************/ + /** Testing _ux_host_class_storage_media_characteristics_get() **/ + /**************************************************/ + /**************************************************/ + + /**************************************************/ + /** Test case: inquiry_response = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_STORAGE_INQUIRY_RESPONSE_LENGTH); fails **/ + /**************************************************/ + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + dummy_memory_block_first -> ux_memory_block_size = 0; + _ux_system -> ux_system_regular_memory_pool_start = dummy_memory_block_first; + _ux_system -> ux_system_cache_safe_memory_pool_start = dummy_memory_block_first; + + status = _ux_host_class_storage_media_characteristics_get(global_storage); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + _ux_system -> ux_system_regular_memory_pool_start = original_regular_memory_block; + _ux_system -> ux_system_cache_safe_memory_pool_start = original_cache_safe_memory_block; + + /**************************************************/ + /**************************************************/ + /** Testing _ux_host_class_storage_max_lun_get() **/ + /**************************************************/ + /**************************************************/ + + /**************************************************/ + /** Test case: storage_data_buffer = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, 1); fails **/ + /**************************************************/ + + /* ux_host_class_storage_max_lun is set to 0 at start of max_lun_get() in case of error. */ + tmp = global_storage -> ux_host_class_storage_max_lun; + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + dummy_memory_block_first -> ux_memory_block_size = 0; + _ux_system -> ux_system_regular_memory_pool_start = dummy_memory_block_first; + _ux_system -> ux_system_cache_safe_memory_pool_start = dummy_memory_block_first; + + status = _ux_host_class_storage_max_lun_get(global_storage); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + global_storage -> ux_host_class_storage_max_lun = tmp; + _ux_system -> ux_system_regular_memory_pool_start = original_regular_memory_block; + _ux_system -> ux_system_cache_safe_memory_pool_start = original_cache_safe_memory_block; + + /**************************************************/ + /**************************************************/ + /** Testing _ux_host_class_storage_entry() **/ + /**************************************************/ + /**************************************************/ + + /**************************************************/ + /** Test case: command -> ux_host_class_command_class_ptr -> ux_host_class_thread_stack = + _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, UX_HOST_CLASS_STORAGE_THREAD_STACK_SIZE); fails **/ + /**************************************************/ + + host_class.ux_host_class_thread_stack = UX_NULL; + command.ux_host_class_command_class_ptr = &host_class; + command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_ACTIVATE; + command.ux_host_class_command_class_ptr -> ux_host_class_thread_stack = UX_NULL; + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + dummy_memory_block_first -> ux_memory_block_size = 0; + _ux_system -> ux_system_regular_memory_pool_start = dummy_memory_block_first; + _ux_system -> ux_system_cache_safe_memory_pool_start = dummy_memory_block_first; + + status = _ux_host_class_storage_entry(&command); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + _ux_system -> ux_system_regular_memory_pool_start = original_regular_memory_block; + _ux_system -> ux_system_cache_safe_memory_pool_start = original_cache_safe_memory_block; + + /**************************************************/ + /** Test case: command -> ux_host_class_command_class_ptr -> ux_host_class_thread_stack = + _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, UX_HOST_CLASS_STORAGE_THREAD_STACK_SIZE); fails **/ + /**************************************************/ + + host_class.ux_host_class_thread_stack = UX_NULL; + command.ux_host_class_command_class_ptr = &host_class; + command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_ACTIVATE; + command.ux_host_class_command_class_ptr -> ux_host_class_thread_stack = UX_NULL; + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + dummy_memory_block_first -> ux_memory_block_size = calculate_final_memory_request_size(1, UX_HOST_CLASS_STORAGE_THREAD_STACK_SIZE); + _ux_system -> ux_system_regular_memory_pool_start = dummy_memory_block_first; + _ux_system -> ux_system_cache_safe_memory_pool_start = dummy_memory_block_first; + + status = _ux_host_class_storage_entry(&command); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + + /* Delete thread that was created during call. */ + status = ux_utility_thread_delete(&command.ux_host_class_command_class_ptr -> ux_host_class_thread); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + _ux_system -> ux_system_regular_memory_pool_start = original_regular_memory_block; + _ux_system -> ux_system_cache_safe_memory_pool_start = original_cache_safe_memory_block; + + /**************************************************/ + /** Test case: status = _ux_utility_thread_create(&command -> ux_host_class_command_class_ptr -> ux_host_class_thread, + "ux_storage_thread", _ux_host_class_storage_thread_entry, + (ULONG) command -> ux_host_class_command_class_ptr, + command -> ux_host_class_command_class_ptr -> ux_host_class_thread_stack, + UX_HOST_CLASS_STORAGE_THREAD_STACK_SIZE, + UX_HOST_CLASS_STORAGE_THREAD_PRIORITY_CLASS, + UX_HOST_CLASS_STORAGE_THREAD_PRIORITY_CLASS, + TX_NO_TIME_SLICE, TX_AUTO_START); fails **/ + /**************************************************/ + + host_class.ux_host_class_thread_stack = UX_NULL; + command.ux_host_class_command_class_ptr = &host_class; + command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_ACTIVATE; + command.ux_host_class_command_class_ptr -> ux_host_class_thread_stack = thread_stack; + + /* Create thread that storage_entry() will try to create. */ + status = _ux_utility_thread_create(&command.ux_host_class_command_class_ptr -> ux_host_class_thread, + "ux_storage_thread", _ux_host_class_storage_thread_entry, + (ULONG) (ALIGN_TYPE) command.ux_host_class_command_class_ptr, + command.ux_host_class_command_class_ptr -> ux_host_class_thread_stack, + UX_HOST_CLASS_STORAGE_THREAD_STACK_SIZE, + UX_HOST_CLASS_STORAGE_THREAD_PRIORITY_CLASS, + UX_HOST_CLASS_STORAGE_THREAD_PRIORITY_CLASS, + TX_NO_TIME_SLICE, TX_DONT_START); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + UX_THREAD_EXTENSION_PTR_SET(&command.ux_host_class_command_class_ptr -> ux_host_class_thread, command.ux_host_class_command_class_ptr) + tx_thread_resume(&command.ux_host_class_command_class_ptr -> ux_host_class_thread); + + command.ux_host_class_command_class_ptr -> ux_host_class_thread_stack = UX_NULL; + + status = _ux_host_class_storage_entry(&command); + if (status != UX_THREAD_ERROR) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + status = ux_utility_thread_delete(&command.ux_host_class_command_class_ptr -> ux_host_class_thread); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /**************************************************/ + /** Testing _ux_host_class_storage_activate() **/ + /**************************************************/ + /**************************************************/ + + /**************************************************/ + /** Test case: storage = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, sizeof(UX_HOST_CLASS_STORAGE)); fails **/ + /**************************************************/ + + command.ux_host_class_command_container = &interface; + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + dummy_memory_block_first -> ux_memory_block_size = 0; + _ux_system -> ux_system_regular_memory_pool_start = dummy_memory_block_first; + _ux_system -> ux_system_cache_safe_memory_pool_start = dummy_memory_block_first; + + status = _ux_host_class_storage_activate(&command); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + _ux_system -> ux_system_regular_memory_pool_start = original_regular_memory_block; + _ux_system -> ux_system_cache_safe_memory_pool_start = original_cache_safe_memory_block; + +#if 0 + /**************************************************/ + /** Test case: _ux_host_class_hid_configure() fails. **/ + /** Why direct: When called normally, the device is already configured (via ux_host_stack_class_interface_scan, which always happens before hid_activate()), so _ux_host_class_hid_configure() returns immediately. **/ + /**************************************************/ + + /* Make sure we pass _ux_host_stack_class_instance_create(). */ + host_class.ux_host_class_first_instance = UX_NULL; + + /* Make sure _ux_host_class_hid_configure() fails. */ + device.ux_device_state = ~UX_DEVICE_CONFIGURED; + device.ux_device_handle = 0; + + configuration.ux_configuration_device = &device; + interface.ux_interface_configuration = &configuration; + command.ux_host_class_command_container = &interface; + command.ux_host_class_command_class_ptr = &host_class; + + status = _ux_host_class_storage_activate(&command); + if (status != UX_CONFIGURATION_HANDLE_UNKNOWN) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } +#endif + + /**************************************************/ + /** Test case: status = _ux_utility_semaphore_create(&storage -> ux_host_class_storage_semaphore, "ux_host_class_storage_semaphore", 1); fails **/ + /**************************************************/ + + /* Allocate a keyboard instance like storage_activate(). */ + storage_instance = (UX_HOST_CLASS_STORAGE *) _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_HOST_CLASS_STORAGE)); + if (storage_instance == UX_NULL) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Create the semaphore like storage_activate(). */ + status = _ux_utility_semaphore_create(&storage_instance -> ux_host_class_storage_semaphore, "ux_host_class_storage_semaphore", 0); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Make a copy of the semaphore. */ + storage_instance_semaphore_copy = storage_instance -> ux_host_class_storage_semaphore; + + /* Free the memory so storage_activate() uses the same memory as us, which will cause threadx to detect a semaphore duplicate. */ + ux_utility_memory_free(storage_instance); + + /* Make sure we pass _ux_host_stack_class_instance_create(). */ + host_class.ux_host_class_first_instance = UX_NULL; + + device.ux_device_state = UX_DEVICE_CONFIGURED; + configuration.ux_configuration_device = &device; + interface.ux_interface_configuration = &configuration; + command.ux_host_class_command_container = &interface; + + status = _ux_host_class_storage_activate(&command); + if (status != UX_SEMAPHORE_ERROR) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* ux_utility_memory_allocate() zero'd out our keyboard instance semaphore! Good thing we made a copy! */ + storage_instance -> ux_host_class_storage_semaphore = storage_instance_semaphore_copy; + + /* Restore state for next test. */ + status = ux_utility_semaphore_delete(&storage_instance -> ux_host_class_storage_semaphore); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /**************************************************/ + /** Testing _ux_host_class_storage_driver_entry() **/ + /**************************************************/ + /**************************************************/ + + /**************************************************/ + /** Test case: status = _ux_utility_semaphore_get(&storage -> ux_host_class_storage_semaphore, UX_WAIT_FOREVER); fails **/ + /**************************************************/ + + /* Make sure it fails. */ + global_storage -> ux_host_class_storage_semaphore.tx_semaphore_id++; + + command.ux_host_class_command_instance = global_storage; + + /* Returns VOID. */ + _ux_host_class_storage_driver_entry(global_media); + + /* Restore state. */ + global_storage -> ux_host_class_storage_semaphore.tx_semaphore_id--; + + /**************************************************/ + /**************************************************/ + /** Testing _ux_host_class_storage_configure() **/ + /** Why direct: When called normally, the device is already configured (via ux_host_stack_class_interface_scan, which always happens before hid_activate()), so _ux_host_class_hid_configure() returns immediately. **/ + /**************************************************/ + /**************************************************/ + + /**************************************************/ + /**************************************************/ + /** Testing _ux_host_class_storage_deactivate() **/ + /** NOTE: This should be last. **/ + /**************************************************/ + /**************************************************/ + + /**************************************************/ + /** Test case: status = _ux_utility_semaphore_get(&storage -> ux_host_class_storage_semaphore, UX_WAIT_FOREVER); fails **/ + /**************************************************/ + + /* Make sure it fails. */ + global_storage -> ux_host_class_storage_semaphore.tx_semaphore_id++; + + command.ux_host_class_command_instance = global_storage; + + status = _ux_host_class_storage_deactivate(&command); + if(status != TX_SEMAPHORE_ERROR) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state. */ + global_storage -> ux_host_class_storage_semaphore.tx_semaphore_id--; + + /* The function did a get() on the hid semaphore and never put() it since we error'd out, so we must do it! */ + status = ux_utility_semaphore_put(&global_storage -> ux_host_class_storage_semaphore); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + + +static UINT default_device_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + +UINT status; + + + if(lba == 0) + { + global_ram_disk.fx_media_driver_logical_sector = 0; + global_ram_disk.fx_media_driver_sectors = 1; + global_ram_disk.fx_media_driver_request = FX_DRIVER_BOOT_READ; + global_ram_disk.fx_media_driver_buffer = data_pointer; + _fx_ram_driver(&global_ram_disk); + *(data_pointer) = 0xeb; + *(data_pointer+1) = 0x3c; + *(data_pointer+2) = 0x90; + *(data_pointer+21) = 0xF8; + + *(data_pointer+24) = 0x01; + *(data_pointer+26) = 0x10; + *(data_pointer+28) = 0x01; + + *(data_pointer+510) = 0x55; + *(data_pointer+511) = 0xaa; + ux_utility_memory_copy(data_pointer+0x36,"FAT12",5); + + + status = global_ram_disk.fx_media_driver_status; + } + else + { + while(number_blocks--) + { + status = fx_media_read(&global_ram_disk,lba,data_pointer); + data_pointer+=512; + lba++; + } + } + return(status); +} + +static UINT default_device_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + +UINT status; + + if(lba == 0) + { + global_ram_disk.fx_media_driver_logical_sector = 0; + global_ram_disk.fx_media_driver_sectors = 1; + global_ram_disk.fx_media_driver_request = FX_DRIVER_BOOT_WRITE; + global_ram_disk.fx_media_driver_buffer = data_pointer; + _fx_ram_driver(&global_ram_disk); + + status = global_ram_disk.fx_media_driver_status; + + } + else + { + + while(number_blocks--) + { + status = fx_media_write(&global_ram_disk,lba,data_pointer); + data_pointer+=512; + lba++; + } + return(status); + } + return(status); +} + +UINT default_device_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + + /* The ATA drive never fails. This is just for demo only !!!! */ + return(UX_SUCCESS); +} diff --git a/test/regression/usbx_storage_multi_lun_test.c b/test/regression/usbx_storage_multi_lun_test.c new file mode 100644 index 00000000..87acbe08 --- /dev/null +++ b/test/regression/usbx_storage_multi_lun_test.c @@ -0,0 +1,777 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_class_storage.h" + +/* Define constants. */ +#define UX_DEMO_STACK_SIZE 2048 +#define UX_DEMO_BUFFER_SIZE 2048 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_FILE_SIZE (128 * 512) +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + + + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); + +static UINT demo_thread_media_read1(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write1(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status1(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); + +static UINT demo_thread_media_read2(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write2(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status2(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); + + +/* Define global data structures. */ +UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +ULONG error_counter; +TX_THREAD demo_thread; +UX_HOST_CLASS_STORAGE *storage; +UX_HOST_CLASS_STORAGE_MEDIA *global_storage_media; +FX_MEDIA *media1; +FX_MEDIA *media2; +UINT status; +UINT transfer_completed; +ULONG requested_length; +FX_FILE my_file; +TX_SEMAPHORE demo_semaphore; +CHAR file_name[64]; +UCHAR global_buffer[UX_DEMO_FILE_BUFFER_SIZE]; +UCHAR buffer[512]; +FX_MEDIA ram_disk1; +CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +FX_MEDIA ram_disk2; +CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +#if defined(UX_HOST_CLASS_STORAGE_NO_FILEX) +FX_MEDIA *_ux_host_class_storage_driver_media(INT i); +VOID _ux_host_class_storage_driver_entry(FX_MEDIA *media); +VOID _ux_host_class_storage_media_insert(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG format_open); +VOID _ux_host_class_storage_media_remove(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +FX_MEDIA *_ux_host_class_storage_media_fx_media(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +UCHAR *_ux_host_class_storage_media_fx_media_memory(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); + +static UINT ux_test_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + + switch(event) + { + + case UX_STORAGE_MEDIA_INSERTION: + _ux_host_class_storage_media_insert((UX_HOST_CLASS_STORAGE_MEDIA*)inst, 1); + break; + + case UX_STORAGE_MEDIA_REMOVAL: + _ux_host_class_storage_media_remove((UX_HOST_CLASS_STORAGE_MEDIA*)inst); + _ux_host_class_storage_media_fx_media((UX_HOST_CLASS_STORAGE_MEDIA*)inst) -> fx_media_id = 0;/* Testing code is checking ID to detect removal. */ + break; + + default: + break; + } + + return 0; +} +#else +#define ux_test_system_host_change_function UX_NULL +#endif + + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00 + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00 + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + + + + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_storage_multi_lun_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Initialize FileX. */ + fx_system_initialize(); + + /* 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("Running Multiple LUN Storage Test................................... ERROR #1\n"); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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("Running Multiple LUN Storage Test................................... ERROR #5\n"); + test_control_return(1); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 2; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read1; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write1; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status1; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read2; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write2; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status2; + + /* Initilize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_parameter); + if(status!=UX_SUCCESS) + { + + printf("Running Multiple LUN Storage Test................................... ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running Multiple LUN Storage Test................................... ERROR #7\n"); + test_control_return(1); + } + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(ux_test_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Running Multiple LUN Storage Test................................... ERROR #2\n"); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + if (status != UX_SUCCESS) + { + + printf("Running Multiple LUN Storage Test................................... ERROR #3\n"); + 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("Running Multiple LUN Storage Test................................... ERROR #4\n"); + 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("Running Multiple LUN Storage Test................................... ERROR #8\n"); + test_control_return(1); + } + +} + +static UINT host_storage_instance_get(void) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* We get the first instance of the storage device */ + do + { + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + tx_thread_sleep(10); + } while (status != UX_SUCCESS); + + /* We still need to wait for the storage status to be live */ + while (storage -> ux_host_class_storage_state != UX_HOST_CLASS_INSTANCE_LIVE) + tx_thread_sleep(10); + + /* We try to get the first media attached to the class container. */ + while (class -> ux_host_class_media == UX_NULL) + { + + tx_thread_sleep(10); + } + + /* Setup media pointers. */ + global_storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *) class -> ux_host_class_media; + +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + media1 = &global_storage_media -> ux_host_class_storage_media; + media2 = &(global_storage_media+1) -> ux_host_class_storage_media; +#else + media1 = _ux_host_class_storage_media_fx_media(global_storage_media); + media2 = _ux_host_class_storage_media_fx_media(global_storage_media+1); +#endif + + return(UX_SUCCESS); +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +FX_FILE my_file; +ULONG error_count = 0; +ULONG total_length; +UCHAR buffer_pattern; + + + /* Inform user. */ + printf("Running Multiple LUN Storage Test................................... "); + + /* Format the ram drive 1. */ + status = fx_media_format(&ram_disk1, _fx_ram_driver, ram_disk_memory1, buffer, 512, "RAM DISK", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* Check the media format status. */ + if (status != FX_SUCCESS) + { + + /* Multiple LUN Storage test error. */ + printf("ERROR #9\n"); + test_control_return(1); + } + + /* Format the ram drive 2. */ + status = fx_media_format(&ram_disk2, _fx_ram_driver, ram_disk_memory2, buffer, 512, "RAM DISK", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* Check the media format status. */ + if (status != FX_SUCCESS) + { + + /* Multiple LUN Storage test error. */ + printf("ERROR #10\n"); + test_control_return(1); + } + + + /* Open the ram_disk1 . */ + status = fx_media_open(&ram_disk1, "RAM DISK", _fx_ram_driver, ram_disk_memory1, buffer, 512); + + /* Check the media open status. */ + if (status != FX_SUCCESS) + { + + /* Multiple LUN Storage test error. */ + printf("ERROR #11\n"); + test_control_return(1); + } + + /* Open the ram_disk2 . */ + status = fx_media_open(&ram_disk2, "RAM DISK", _fx_ram_driver, ram_disk_memory2, buffer, 512); + + /* Check the media open status. */ + if (status != FX_SUCCESS) + { + + /* Multiple LUN Storage test error. */ + printf("ERROR #12\n"); + test_control_return(1); + } + + + /* Find the storage class */ + status = host_storage_instance_get(); + if (status != UX_SUCCESS) + { + + /* Multiple LUN Storage test error. */ + printf("ERROR #13\n"); + test_control_return(1); + } + + /* Medfia 1. */ + /* Delete the target file. */ + status = fx_file_delete(media1, "FILE.CPY"); + + /* Create the file. */ + status = fx_file_create(media1, "FILE.CPY"); + if (status != UX_SUCCESS) + { + + /* Multiple LUN Storage test error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + + memset(&my_file, 0, sizeof(my_file)); + + /* Open file for copying. */ + status = fx_file_open(media1, &my_file, "FILE.CPY", FX_OPEN_FOR_WRITE); + if (status != UX_SUCCESS) + { + + /* Multiple LUN Storage test error. */ + printf("ERROR #15\n"); + test_control_return(1); + } + + /* Seek to the beginning to copy over an existing file. */ + fx_file_seek(&my_file, 0); + + /* Set the file length. */ + total_length = UX_DEMO_FILE_SIZE; + + /* Set pattern first letter. */ + buffer_pattern = 'a'; + + while(total_length !=0) + { + + /* Set the buffer with pattern. */ + ux_utility_memory_set(global_buffer, buffer_pattern, UX_DEMO_FILE_BUFFER_SIZE); + + /* Copy the file in blocks */ + status = fx_file_write(&my_file, global_buffer, UX_DEMO_FILE_BUFFER_SIZE); + + /* Check if status OK. */ + if (status != UX_SUCCESS) + { + + /* Multiple LUN Storage test error. */ + printf("ERROR #16\n"); + test_control_return(1); + } + + /* Decrement the length remaining. */ + total_length -= UX_DEMO_FILE_BUFFER_SIZE; + + /* Next pattern. */ + buffer_pattern++; + + /* Check pattern end. */ + if (buffer_pattern > 'z') + + /* Back to beginning. */ + buffer_pattern = 'a'; + + } + /* Finished reading file either at the end or because of error. */ + fx_file_close(&my_file); + + /* Media 2. */ + /* Delete the target file. */ + status = fx_file_delete(media2, "FILE.CPY"); + + /* Create the file. */ + status = fx_file_create(media2, "FILE.CPY"); + if (status != UX_SUCCESS) + { + + /* Multiple LUN Storage test error. */ + printf("ERROR #17\n"); + test_control_return(1); + } + + /* Open file for copying. */ + status = fx_file_open(media2, &my_file, "FILE.CPY", FX_OPEN_FOR_WRITE); + if (status != UX_SUCCESS) + { + + /* Multiple LUN Storage test error. */ + printf("ERROR #18\n"); + test_control_return(1); + } + + /* Seek to the beginning to copy over an existing file. */ + fx_file_seek(&my_file, 0); + + /* Set the file length. */ + total_length = UX_DEMO_FILE_SIZE; + + /* Set pattern first letter. */ + buffer_pattern = 'a'; + + while(total_length !=0) + { + + /* Set the buffer with pattern. */ + ux_utility_memory_set(global_buffer, buffer_pattern, UX_DEMO_FILE_BUFFER_SIZE); + + /* Copy the file in blocks */ + status = fx_file_write(&my_file, global_buffer, UX_DEMO_FILE_BUFFER_SIZE); + + /* Check if status OK. */ + if (status != UX_SUCCESS) + { + + /* Multiple LUN Storage test error. */ + printf("ERROR #19\n"); + test_control_return(1); + } + + /* Decrement the length remaining. */ + total_length -= UX_DEMO_FILE_BUFFER_SIZE; + + /* Next pattern. */ + buffer_pattern++; + + /* Check pattern end. */ + if (buffer_pattern > 'z') + + /* Back to beginning. */ + buffer_pattern = 'a'; + + } + /* Finished reading file either at the end or because of error. */ + fx_file_close(&my_file); + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + + +static UINT demo_thread_media_status1(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + + /* The ATA drive never fails. This is just for demo only !!!! */ + return(UX_SUCCESS); +} + +static UINT demo_thread_media_read1(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + +UINT status; + + if(lba == 0) + { + ram_disk1.fx_media_driver_logical_sector = 0; + ram_disk1.fx_media_driver_sectors = 1; + ram_disk1.fx_media_driver_request = FX_DRIVER_BOOT_READ; + ram_disk1.fx_media_driver_buffer = data_pointer; + _fx_ram_driver(&ram_disk1); + *(data_pointer) = 0xeb; + *(data_pointer+1) = 0x3c; + *(data_pointer+2) = 0x90; + *(data_pointer+21) = 0xF8; + + *(data_pointer+24) = 0x01; + *(data_pointer+26) = 0x10; + *(data_pointer+28) = 0x01; + + *(data_pointer+510) = 0x55; + *(data_pointer+511) = 0xaa; + ux_utility_memory_copy(data_pointer+0x36,"FAT12",5); + + + status = ram_disk1.fx_media_driver_status; + } + else + { + while(number_blocks--) + { + status = fx_media_read(&ram_disk1,lba,data_pointer); + data_pointer+=512; + lba++; + } + } + return(status); +} + +static UINT demo_thread_media_write1(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + +UINT status; + + if(lba == 0) + { + ram_disk1.fx_media_driver_logical_sector = 0; + ram_disk1.fx_media_driver_sectors = 1; + ram_disk1.fx_media_driver_request = FX_DRIVER_BOOT_WRITE; + ram_disk1.fx_media_driver_buffer = data_pointer; + _fx_ram_driver(&ram_disk1); + + status = ram_disk1.fx_media_driver_status; + + } + else + { + + while(number_blocks--) + { + status = fx_media_write(&ram_disk1,lba,data_pointer); + data_pointer+=512; + lba++; + } + return(status); + } + return(1); +} + + + + +static UINT demo_thread_media_status2(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + + /* The ATA drive never fails. This is just for demo only !!!! */ + return(UX_SUCCESS); +} + +static UINT demo_thread_media_read2(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + +UINT status; + + if(lba == 0) + { + ram_disk2.fx_media_driver_logical_sector = 0; + ram_disk2.fx_media_driver_sectors = 1; + ram_disk2.fx_media_driver_request = FX_DRIVER_BOOT_READ; + ram_disk2.fx_media_driver_buffer = data_pointer; + _fx_ram_driver(&ram_disk2); + *(data_pointer) = 0xeb; + *(data_pointer+1) = 0x3c; + *(data_pointer+2) = 0x90; + *(data_pointer+21) = 0xF8; + + *(data_pointer+24) = 0x01; + *(data_pointer+26) = 0x10; + *(data_pointer+28) = 0x01; + + *(data_pointer+510) = 0x55; + *(data_pointer+511) = 0xaa; + ux_utility_memory_copy(data_pointer+0x36,"FAT12",5); + + + status = ram_disk2.fx_media_driver_status; + } + else + { + while(number_blocks--) + { + status = fx_media_read(&ram_disk2,lba,data_pointer); + data_pointer+=512; + lba++; + } + } + return(status); +} + +static UINT demo_thread_media_write2(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + +UINT status; + + if(lba == 0) + { + ram_disk2.fx_media_driver_logical_sector = 0; + ram_disk2.fx_media_driver_sectors = 1; + ram_disk2.fx_media_driver_request = FX_DRIVER_BOOT_WRITE; + ram_disk2.fx_media_driver_buffer = data_pointer; + _fx_ram_driver(&ram_disk2); + + status = ram_disk2.fx_media_driver_status; + + } + else + { + + while(number_blocks--) + { + status = fx_media_write(&ram_disk2,lba,data_pointer); + data_pointer+=512; + lba++; + } + return(status); + } + return(1); +} + diff --git a/test/regression/usbx_storage_tests.c b/test/regression/usbx_storage_tests.c new file mode 100644 index 00000000..15e35039 --- /dev/null +++ b/test/regression/usbx_storage_tests.c @@ -0,0 +1,5847 @@ +#include +#include +#include "fx_api.h" +#include "tx_api.h" +#include "ux_api.h" +#include "ux_hcd_sim_host.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "tx_thread.h" + +#include "ux_device_stack.h" +#include "ux_device_class_storage.h" +#include "ux_host_class_storage.h" +#include "ux_dcd_sim_slave.h" + +#include "ux_test.h" +#include "ux_test_actions.h" +#include "ux_test_utility_sim.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_dcd_sim_slave.h" + +typedef struct device_media_read_write_timeout_data +{ + UX_TRANSFER *transfer_request; + ULONG num_timeouts; +} DEVICE_MEDIA_READ_WRITE_TIMEOUT_DATA; + +#define _storage_media_is_mounted() (global_storage_media->ux_host_class_storage_media_status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED) +#if defined(UX_HOST_CLASS_STORAGE_NO_FILEX) +FX_MEDIA *_ux_host_class_storage_driver_media(INT i); +VOID _ux_host_class_storage_driver_entry(FX_MEDIA *media); +VOID _ux_host_class_storage_media_insert(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG format_open); +VOID _ux_host_class_storage_media_remove(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +INT _ux_host_class_storage_media_index(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +FX_MEDIA *_ux_host_class_storage_media_fx_media(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +UCHAR *_ux_host_class_storage_media_fx_media_memory(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +#endif + +/* Define constants. */ +#define UX_TEST_MULTIPLE_TRANSFERS_SECTOR_COUNT (2*UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE/UX_HOST_CLASS_STORAGE_SECTOR_SIZE_FAT) +#define UX_TEST_SLEEP_STORAGE_THREAD_RUN_ONCE (3*UX_HOST_CLASS_STORAGE_THREAD_SLEEP_TIME/2) +#define UX_TEST_DEFAULT_SECTOR_SIZE UX_HOST_CLASS_STORAGE_SECTOR_SIZE_FAT +#define UX_TEST_MAX_SECTOR_SIZE (2*UX_HOST_CLASS_STORAGE_SECTOR_SIZE_FAT) +#define UX_TEST_NUM_DIRECTORY_ENTRIES 512 +#define UX_DEMO_STACK_SIZE 2048 +#define UX_DEMO_BUFFER_SIZE 2048 +#define UX_DEMO_FILE_BUFFER_SIZE UX_TEST_MAX_SECTOR_SIZE +#define UX_DEMO_LARGE_FILE_BUFFER_SIZE (2*UX_HOST_CLASS_STORAGE_MAX_TRANSFER_SIZE) +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (256 * 1024) +#define UX_DEMO_FILE_SIZE (4 * 1024) +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / global_sector_size) -1) +#define BULK_IN 1 +#define BULK_OUT 2 +#define PARTITION_TYPE_UNKNOWN 0xff +#define MEDIA_TYPE_UNKNOWN 0xff +#define PROTOCOL_UNKNOWN 0xff +#define SUB_CLASS_UNKNOWN 0xff +#define bInterfaceSubClass_POS 0x21 +#define bInterfaceProtocol_POS 0x22 +#define bNumEndpoints_FS_POS 0x1f +#define bNumEndpoints_HS_POS 0x29 +#define Endpoint_bLength 0 +#define Endpoint_bDescriptorType 1 +#define Endpoint_bEndpointAddress 2 +#define Endpoint_bmAttributes 3 +#define Endpoint_wMaxPacketSize 4 +#define Endpoint_bInterval 6 + +/* Define local/extern function prototypes. */ +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void ux_test_thread_host_simulation_entry(ULONG); +UINT _ux_dcd_sim_slave_function(UX_SLAVE_DCD *dcd, UINT function, VOID *parameter); + + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +static UINT default_device_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT default_device_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT default_device_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT default_device_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT ux_test_storage_file_co(FX_MEDIA *media, FX_FILE *file, UCHAR fail_on_error); +static UINT ux_test_storage_file_cow(FX_MEDIA *media, FX_FILE *file, UCHAR *data_pointer, ULONG data_length, UCHAR fail_on_error); +static void ux_test_storage_file_cd(FX_MEDIA *media, FX_FILE *file); +static void ux_test_storage_file_cowcd(FX_MEDIA *media, FX_FILE *file, UCHAR *data_pointer, ULONG data_length); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR global_buffer[UX_DEMO_LARGE_FILE_BUFFER_SIZE]; +static UCHAR global_buffer_2x_slave_buffer_size[2*UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE]; +static FX_MEDIA global_ram_disk; +static CHAR global_ram_disk_memory[UX_RAM_DISK_SIZE]; +static UCHAR global_ram_disk_working_buffer[UX_TEST_MAX_SECTOR_SIZE]; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; +static UX_HOST_CLASS *global_host_storage_class; +static UX_HOST_CLASS_STORAGE_EXT *global_host_class_ext; +static UX_HOST_CLASS_STORAGE *global_storage; +static UX_HOST_CLASS_STORAGE *global_storage_change_function; +static TX_THREAD *global_storage_thread; +static UX_HOST_CLASS_STORAGE_MEDIA *global_storage_media; +static UX_HOST_CLASS_STORAGE_MEDIA *global_storage_medias; +static FX_MEDIA *global_media; +static UX_HCD *global_hcd; +static UX_SLAVE_DCD *global_dcd; +static UX_DEVICE *global_host_device; +static UX_SLAVE_DEVICE *global_slave_device; +static UX_SLAVE_CLASS *global_slave_class_container; +static UX_SLAVE_CLASS_STORAGE *global_slave_storage; +static UX_SLAVE_ENDPOINT *global_slave_storage_bulk_in; +static UX_SLAVE_ENDPOINT *global_slave_storage_bulk_out; +static TX_THREAD *global_slave_storage_thread; +static UX_SLAVE_CLASS_STORAGE *global_persistent_slave_storage; +static TX_THREAD *global_enum_thread; +static ULONG global_sector_size = UX_TEST_DEFAULT_SECTOR_SIZE; +static ULONG global_memory_test_no_device_memory_free_amount; +static UCHAR global_is_storage_thread_locked_out; + +/* Common data we match. */ +static UCHAR global_transfer_request_data_request_sense_data_phase[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static UCHAR global_cbw_data_unit_ready_test_sbc[20] = { 85, 83, 66, 67, 67, 66, 83, 85, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0 }; +static UCHAR global_cbw_data_request_sense[26] = { 0x55, 0x53, 0x42, 0x43, 0x43, 0x42, 0x53, 0x55, 0x12, 0x00, 0x00, 0x00, 0x80, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static UCHAR global_cbw_data_format_capacity_get[] = { 0x55, 0x53, 0x42, 0x43, 0x43, 0x42, 0x53, 0x55, 0xfc, 0x00, 0x00, 0x00, 0x80, 0x00, 0x0a, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static UCHAR global_cbw_data_first_sector_read[] = { 0x55, 0x53, 0x42, 0x43, 0x43, 0x42, 0x53, 0x55, 0x00, 0x02, 0x00, 0x00, 0x80, 0x00, 0x0a, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static UCHAR global_cbw_data_media_characteristics_get_sbc[20] = { 0x55, 0x53, 0x42, 0x43, 0x43, 0x42, 0x53, 0x55, 0x24, 0x00, 0x00, 0x00, 0x80, 0x00, 0x06, 0x12, 0x00, 0x00, 0x00, 0x24 }; +static UCHAR global_cbw_data_media_capacity_get_sbc[25] = { 0x55, 0x53, 0x42, 0x43, 0x43, 0x42, 0x53, 0x55, 0x08, 0x00, 0x00, 0x00, 0x80, 0x00, 0x0a, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; + +/* Opcode matching. */ +static UCHAR global_cbw_opcode_read[] = { 'U', 'S', 'B', 'C', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '(' }; +static UCHAR global_cbw_opcode_match_mask[] = { 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; + +/* Common errors. */ +static UX_TEST_ERROR_CALLBACK_ERROR global_transfer_stall_error = { UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HCD, UX_TRANSFER_STALLED }; +static UX_TEST_ERROR_CALLBACK_ERROR global_transfer_timeout_error = { UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_TIMEOUT }; + +/* Test resources. */ +static TX_SEMAPHORE global_test_semaphore; +static TX_TIMER global_timer; + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x45, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x03, 0x08, 0x06, 0x50, + 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, 0x01, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x01, 0x03, 0x08, 0x06, 0x50, + 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, 0x01, + + }; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED ARRAY_COUNT(device_framework_full_speed) + +static UCHAR *bulk_in_endpoint_descriptor_fs = &device_framework_full_speed[0x12 + 0x09 + 0x09]; +static UCHAR *bulk_out_endpoint_descriptor_fs = &device_framework_full_speed[0x12 + 0x09 + 0x09 + 0x07]; +static UCHAR *interrupt_in_endpoint_descriptor_fs = &device_framework_full_speed[0x12 + 0x09 + 0x09 + 0x07 + 0x07]; + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x45, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x03, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Interrupt In) */ + 0x07, 0x05, 0x83, 0x03, 0x40, 0x00, 0x01, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x01, 0x03, 0x08, 0x06, 0x50, + 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, 0x01, + + }; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED ARRAY_COUNT(device_framework_high_speed) + +static UCHAR *bulk_in_endpoint_descriptor_hs = &device_framework_high_speed[0x12 + 0x0a + 0x09 + 0x09]; +static UCHAR *bulk_out_endpoint_descriptor_hs = &device_framework_high_speed[0x12 + 0x0a + 0x09 + 0x09 + 0x07]; +static UCHAR *interrupt_in_endpoint_descriptor_hs = &device_framework_high_speed[0x12 + 0x0a + 0x09 + 0x09 + 0x07 + 0x07]; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +/* OS wrappers. */ + +static void ux_test_semaphore_get(TX_SEMAPHORE *sempahore, UINT wait_option) +{ + +UINT status; + + + status = ux_utility_semaphore_get(sempahore, wait_option); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n",__LINE__,(ULONG)status); + test_control_return(1); + } +} + +/* General test resources. */ + +static void lock_out_storage_thread() +{ + +UINT status; + + + status = ux_utility_semaphore_get(&global_storage -> ux_host_class_storage_semaphore,TX_WAIT_FOREVER); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n",__LINE__,(ULONG)status); + test_control_return(1); + } + + global_is_storage_thread_locked_out = 1; +} + +static void lock_in_storage_thread() +{ + +UINT status; + + + status = ux_utility_semaphore_put(&global_storage -> ux_host_class_storage_semaphore); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n",__LINE__,(ULONG)status); + test_control_return(1); + } + + global_is_storage_thread_locked_out = 0; +} + +static UINT ux_test_host_class_storage_media_read(UX_HOST_CLASS_STORAGE *storage, ULONG sector_start, ULONG sector_count, UCHAR *data_pointer) +{ + + UX_TEST_ASSERT(global_is_storage_thread_locked_out); + return(ux_host_class_storage_media_read(storage, sector_start, sector_count, data_pointer)); +} + +static UINT ux_test_host_class_storage_media_write(UX_HOST_CLASS_STORAGE *storage, ULONG sector_start, ULONG sector_count, UCHAR *data_pointer) +{ + + UX_TEST_ASSERT(global_is_storage_thread_locked_out); + return(ux_host_class_storage_media_write(storage, sector_start, sector_count, data_pointer)); +} + +/* Does a write - for times when you just want a write to trigger a CBW or something. */ +static void do_any_write() +{ + + lock_out_storage_thread(); + ux_test_host_class_storage_media_write(global_storage, 10, 10, global_buffer); + lock_in_storage_thread(); +} + +/* Storage thread needs to be locked out when this is called. */ +UINT _ux_host_stack_endpoint_reset(UX_ENDPOINT *endpoint); +static void receive_device_csw() +{ + +UX_TRANSFER *transfer_request; + + + UX_TEST_ASSERT(global_is_storage_thread_locked_out); + + if (global_slave_storage_bulk_in->ux_slave_endpoint_state == UX_ENDPOINT_HALTED) + { + _ux_host_stack_endpoint_reset(global_storage->ux_host_class_storage_bulk_in_endpoint); + } + + transfer_request = &global_storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + transfer_request -> ux_transfer_request_data_pointer = (UCHAR *) &global_storage -> ux_host_class_storage_csw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CSW_LENGTH; + UX_TEST_CHECK_SUCCESS(ux_host_stack_transfer_request(transfer_request)); + UX_TEST_CHECK_SUCCESS(ux_utility_semaphore_get(&transfer_request->ux_transfer_request_semaphore, TX_WAIT_FOREVER)); + + /* Note: we want to do this _after_ because it's possible the device hasn't stalled the OUT endpoint before. */ + if (global_slave_storage_bulk_out->ux_slave_endpoint_state == UX_ENDPOINT_HALTED) + { + _ux_host_stack_endpoint_reset(global_storage->ux_host_class_storage_bulk_out_endpoint); + } +} + +/* Sometimes we need to storage instance during enumeration and before our system host change function has been called. */ +static UX_HOST_CLASS_STORAGE *get_internal_host_storage_instance() +{ + return _ux_system_host -> ux_system_host_class_array[0].ux_host_class_first_instance; +} + +/* Sometimes we need to storage instance during enumeration and before our system host change function has been called. */ +static UX_HOST_CLASS_STORAGE_MEDIA *get_internal_host_storage_medias() +{ + return (_ux_system_host -> ux_system_host_class_array[0].ux_host_class_media); +} + +static TX_THREAD *get_host_enum_thread() +{ + return &_ux_system_host->ux_system_host_enum_thread; +} + +static VOID ux_slave_class_storage_instance_activate(VOID *instance) +{ + +UX_SLAVE_ENDPOINT *tmp; + + + global_slave_storage = (UX_SLAVE_CLASS_STORAGE *)instance; + + global_slave_storage_bulk_in = global_slave_storage->ux_slave_class_storage_interface->ux_slave_interface_first_endpoint; + global_slave_storage_bulk_out = global_slave_storage_bulk_in->ux_slave_endpoint_next_endpoint; + if ((global_slave_storage_bulk_in->ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) != UX_ENDPOINT_IN) + { + + tmp = global_slave_storage_bulk_in; + global_slave_storage_bulk_in = global_slave_storage_bulk_out; + global_slave_storage_bulk_out = tmp; + } + + /* As long as we don't unregister the storage class, this _should_ be fine! */ + global_persistent_slave_storage = global_slave_storage; +} + +static VOID ux_slave_class_storage_instance_deactivate(VOID *instance) +{ + + global_slave_storage = UX_NULL; + global_slave_storage_bulk_in = UX_NULL; + global_slave_storage_bulk_out = UX_NULL; +} + +static UINT ux_test_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + + switch(event) + { + + case UX_DEVICE_INSERTION: + + global_storage_change_function = inst; + break; + + case UX_DEVICE_REMOVAL: + + global_storage_change_function = UX_NULL; + break; + +#if defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + case UX_STORAGE_MEDIA_INSERTION: + /* keep using first media. */ + if (_ux_host_class_storage_media_index((UX_HOST_CLASS_STORAGE_MEDIA*)inst) == 0) + { + _ux_host_class_storage_media_insert((UX_HOST_CLASS_STORAGE_MEDIA*)inst, 1); + global_media = _ux_host_class_storage_media_fx_media((UX_HOST_CLASS_STORAGE_MEDIA*)inst); + } + break; + + case UX_STORAGE_MEDIA_REMOVAL: + if (_ux_host_class_storage_media_index((UX_HOST_CLASS_STORAGE_MEDIA*)inst) == 0) + { + _ux_host_class_storage_media_remove((UX_HOST_CLASS_STORAGE_MEDIA*)inst); + } + break; +#endif + + default: + break; + } + + return 0; +} + +/* General worker thread resources. */ + +typedef struct UX_TEST_WORKER_WORK +{ + ULONG input; + void (*function)(ULONG); +} UX_TEST_WORKER_WORK; + +static UX_TEST_WORKER_WORK *ux_test_worker_current_work; +static TX_SEMAPHORE ux_test_worker_semaphore; +static TX_THREAD ux_test_worker_thread; +static UCHAR ux_test_worker_thread_stack[4096]; + +static void ux_test_worker_add_work(UX_TEST_WORKER_WORK *work) +{ + +UINT status; + + + /* There shouldn't be more than one work at a time. */ + UX_TEST_ASSERT(ux_test_worker_semaphore.tx_semaphore_suspended_count == 1); + + ux_test_worker_current_work = work; + + status = ux_utility_semaphore_put(&ux_test_worker_semaphore); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } +} + +static void ux_test_worker_thread_entry(ULONG input) +{ + +UINT status; + + + while (1) + { + + /* Wait for some work. */ + status = ux_utility_semaphore_get(&ux_test_worker_semaphore, TX_WAIT_FOREVER); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + /* Do the work. */ + ux_test_worker_current_work->function(ux_test_worker_current_work->input); + } +} + +static void ux_test_worker_initialize() +{ + +UINT status; + + + status = ux_utility_semaphore_create(&ux_test_worker_semaphore, "ux_test_worker_semaphore", 0); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + status = ux_utility_thread_create(&ux_test_worker_thread, "ux_test_worker_thread", ux_test_worker_thread_entry, 0, + ux_test_worker_thread_stack, UX_DEMO_STACK_SIZE, 1, 1, TX_NO_TIME_SLICE, TX_AUTO_START); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } +} + +/* Simulate CBI resources. */ + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); +static TX_SEMAPHORE *cbi_interrupt_endpoint_transfer_semaphore; +static TX_SEMAPHORE cbi_transfer_request_csw_semaphore_host; +static UCHAR *cbi_host_transfer_csw_data_pointer; +static UINT global_cbi_fail_on_csw; +static UINT global_cbi_actual_csw = UX_TRUE; + +void ux_cbi_simulator_initialize() +{ + +UINT status; + + + status = ux_utility_semaphore_create(&cbi_transfer_request_csw_semaphore_host, "transfer request csw semaphore device", 0); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } +} + +static UX_ENDPOINT *get_host_bulk_endpoint(UCHAR get_bulk_out) +{ + +UX_ENDPOINT *bulk_out; +UINT direction = (get_bulk_out == UX_TRUE) ? UX_ENDPOINT_OUT : UX_ENDPOINT_IN; + + + bulk_out = global_host_device->ux_device_first_configuration->ux_configuration_first_interface->ux_interface_first_endpoint; + while (bulk_out) + { + + if ((bulk_out->ux_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) == direction && + (bulk_out->ux_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) == UX_BULK_ENDPOINT) + { + break; + } + + bulk_out = bulk_out->ux_endpoint_next_endpoint; + } + return bulk_out; +} + +static UX_ENDPOINT *get_host_bulk_out_endpoint() +{ + return get_host_bulk_endpoint(UX_TRUE); +} + +static UX_ENDPOINT *get_host_bulk_in_endpoint() +{ + return get_host_bulk_endpoint(UX_FALSE); +} + +static UINT _ux_hcd_sim_host_entry_bo_to_cbi(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; +UINT entry_status; +UX_TRANSFER *transfer_request; +UX_ENDPOINT *bulk_out; +UX_TRANSFER *bulk_out_transfer_request; +UCHAR *cbw; +UCHAR *cb; +UINT old_threshold; + + + if (function == UX_HCD_TRANSFER_REQUEST) + { + + transfer_request = parameter; + + /* Is this a CBW? */ + if (transfer_request->ux_transfer_request_endpoint->ux_endpoint_descriptor.bmAttributes == 0x0 && + transfer_request->ux_transfer_request_type == (UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE)) + { + + /* Right now it's being sent on the control endpoint. Need to switch to bulk. */ + + bulk_out = get_host_bulk_out_endpoint(); + bulk_out_transfer_request = &bulk_out->ux_endpoint_transfer_request; + + /* Make the following check and assignment atomic. */ + tx_thread_priority_change(tx_thread_identify(), 0, &old_threshold); + + /* We can only transfer when the device is ATTACHED, ADDRESSED OR CONFIGURED. */ + if ((global_host_device -> ux_device_state == UX_DEVICE_ATTACHED) || (global_host_device -> ux_device_state == UX_DEVICE_ADDRESSED) + || (global_host_device -> ux_device_state == UX_DEVICE_CONFIGURED)) + + /* Set the pending transfer request. */ + bulk_out_transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_STATUS_PENDING; + + tx_thread_priority_change(tx_thread_identify(), old_threshold, &old_threshold); + + if (bulk_out_transfer_request -> ux_transfer_request_completion_code != UX_TRANSFER_STATUS_PENDING) + return(UX_TRANSFER_NOT_READY); + + /* Through the power of friendship, we know the CBW is located behind the UFI. */ + cb = transfer_request->ux_transfer_request_data_pointer; + cbw = cb - UX_HOST_CLASS_STORAGE_CBW_CB; + + bulk_out_transfer_request->ux_transfer_request_data_pointer = cbw; + bulk_out_transfer_request->ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CBW_LENGTH; + + entry_status = _ux_hcd_sim_host_entry(hcd, function, bulk_out_transfer_request); + if (entry_status == UX_SUCCESS) + { + + /* The caller expects this to be blocking since it's a control transfer, so wait for it to complete. */ + status = ux_utility_semaphore_get(&bulk_out_transfer_request->ux_transfer_request_semaphore, TX_WAIT_FOREVER); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + } + + transfer_request->ux_transfer_request_completion_code = bulk_out_transfer_request->ux_transfer_request_completion_code; + transfer_request->ux_transfer_request_status = bulk_out_transfer_request->ux_transfer_request_status; + + return entry_status; + } + + /* Is this a CSW (only thing that could be on the interrupt endpoint)? */ + else if (transfer_request->ux_transfer_request_endpoint->ux_endpoint_descriptor.bmAttributes == 0x03) + { + + /* Make the following check and assignment atomic. */ + tx_thread_priority_change(tx_thread_identify(), 0, &old_threshold); + + /* We can only transfer when the device is ATTACHED, ADDRESSED OR CONFIGURED. */ + if ((global_host_device -> ux_device_state == UX_DEVICE_ATTACHED) || (global_host_device -> ux_device_state == UX_DEVICE_ADDRESSED) + || (global_host_device -> ux_device_state == UX_DEVICE_CONFIGURED)) + + /* Set the pending transfer request. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_STATUS_PENDING; + + tx_thread_priority_change(tx_thread_identify(), old_threshold, &old_threshold); + + if (transfer_request -> ux_transfer_request_completion_code != UX_TRANSFER_STATUS_PENDING) + return(UX_TRANSFER_NOT_READY); + + cbi_host_transfer_csw_data_pointer = transfer_request->ux_transfer_request_data_pointer; + cbi_interrupt_endpoint_transfer_semaphore = &transfer_request->ux_transfer_request_semaphore; + + if (global_cbi_actual_csw == UX_TRUE) + { + + /* Tell device we've received csw request. */ + status = ux_utility_semaphore_put(&cbi_transfer_request_csw_semaphore_host); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + /* Wait for device to copy data. */ + status = ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, TX_WAIT_FOREVER); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + /* Release semaphore for caller. */ + status = ux_utility_semaphore_put(&transfer_request->ux_transfer_request_semaphore); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + } + else + { + + global_cbi_actual_csw = UX_TRUE; + } + + transfer_request->ux_transfer_request_completion_code = UX_SUCCESS; + transfer_request->ux_transfer_request_status = UX_TRANSFER_STATUS_COMPLETED; + + if (global_cbi_fail_on_csw == UX_TRUE) + { + + global_cbi_fail_on_csw = UX_FALSE; + return(UX_ERROR); + } + + return UX_SUCCESS; + } + } + + return _ux_hcd_sim_host_entry(hcd, function, parameter); +} + +static UINT _ux_dcd_sim_slave_function_bo_to_cbi(UX_SLAVE_DCD *dcd, UINT function, VOID *parameter) +{ + +UINT status; +ULONG mask; +UX_SLAVE_TRANSFER *transfer_request; + + + if (function == UX_DCD_TRANSFER_REQUEST) + { + +#if 0 + /* See matching #if block in host bo_to_cbi. */ +#else + transfer_request = parameter; + + mask = ux_utility_long_get(&transfer_request->ux_slave_transfer_request_data_pointer[UX_SLAVE_CLASS_STORAGE_CSW_SIGNATURE]); + + /* Is this a CSW? */ + if (mask == UX_SLAVE_CLASS_STORAGE_CSW_SIGNATURE_MASK) + { + + /* Wait for host to send CSW request. */ + status = ux_utility_semaphore_get(&cbi_transfer_request_csw_semaphore_host, TX_WAIT_FOREVER); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + /* Copy CSW to host. */ + ux_utility_memory_copy(cbi_host_transfer_csw_data_pointer, + transfer_request->ux_slave_transfer_request_current_data_pointer, UX_SLAVE_CLASS_STORAGE_CSW_LENGTH); + + /* Tell host we've copied data */ + status = ux_utility_semaphore_put(cbi_interrupt_endpoint_transfer_semaphore); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + transfer_request->ux_slave_transfer_request_completion_code = UX_SUCCESS; + transfer_request->ux_slave_transfer_request_status = UX_TRANSFER_STATUS_COMPLETED; + + return UX_SUCCESS; + } +#endif + } + + return _ux_dcd_sim_slave_function(dcd, function, parameter); +} + +/* Simulate CB resources. */ + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); +static UINT _ux_hcd_sim_host_entry_bo_to_cb(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; +UINT entry_status; +UX_TRANSFER *transfer_request; +UX_ENDPOINT *bulk_out; +UX_TRANSFER *bulk_out_transfer_request; +UCHAR *cbw; +UCHAR *cb; +UINT old_threshold; + + + if (function == UX_HCD_TRANSFER_REQUEST) + { + + transfer_request = parameter; + + /* Is this a CBW? */ + if (transfer_request->ux_transfer_request_type == (UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE)) + { + + /* Right now it's being sent on the control endpoint. Need to switch to bulk. */ + + bulk_out = global_host_device->ux_device_first_configuration->ux_configuration_first_interface->ux_interface_first_endpoint->ux_endpoint_next_endpoint; + bulk_out_transfer_request = &bulk_out->ux_endpoint_transfer_request; + + /* Make the following check and assignment atomic. */ + tx_thread_priority_change(tx_thread_identify(), 0, &old_threshold); + + /* We can only transfer when the device is ATTACHED, ADDRESSED OR CONFIGURED. */ + if ((global_host_device -> ux_device_state == UX_DEVICE_ATTACHED) || (global_host_device -> ux_device_state == UX_DEVICE_ADDRESSED) + || (global_host_device -> ux_device_state == UX_DEVICE_CONFIGURED)) + + /* Set the pending transfer request. */ + bulk_out_transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_STATUS_PENDING; + + tx_thread_priority_change(tx_thread_identify(), old_threshold, &old_threshold); + + if (transfer_request -> ux_transfer_request_completion_code != UX_TRANSFER_STATUS_PENDING) + return(UX_TRANSFER_NOT_READY); + + /* Through the power of friendship, we know the CBW is located behind the UFI. */ + cb = transfer_request->ux_transfer_request_data_pointer; + cbw = cb - UX_HOST_CLASS_STORAGE_CBW_CB; + + bulk_out_transfer_request->ux_transfer_request_data_pointer = cbw; + bulk_out_transfer_request->ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CBW_LENGTH; + + entry_status = _ux_hcd_sim_host_entry(hcd, function, bulk_out_transfer_request); + + if (entry_status == UX_SUCCESS) + { + + /* The caller expects this to be blocking since it's a control transfer, so wait for it to complete. */ + status = ux_utility_semaphore_get(&bulk_out_transfer_request->ux_transfer_request_semaphore, TX_WAIT_FOREVER); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + } + + transfer_request->ux_transfer_request_completion_code = bulk_out_transfer_request->ux_transfer_request_completion_code; + transfer_request->ux_transfer_request_status = bulk_out_transfer_request->ux_transfer_request_status; + + return entry_status; + } + } + + return _ux_hcd_sim_host_entry(hcd, function, parameter); +} + +static UINT _ux_dcd_sim_slave_function_bo_to_cb(UX_SLAVE_DCD *dcd, UINT function, VOID *parameter) +{ + +UX_SLAVE_TRANSFER *transfer_request; +ULONG mask; + + + if (function == UX_DCD_TRANSFER_REQUEST) + { + + transfer_request = parameter; + + mask = ux_utility_long_get(&transfer_request->ux_slave_transfer_request_data_pointer[UX_SLAVE_CLASS_STORAGE_CSW_SIGNATURE]); + + /* Is this a CSW? */ + if (mask == UX_SLAVE_CLASS_STORAGE_CSW_SIGNATURE_MASK) + { + + /* Sike, that's the wrong number! */ + /* Ignore cause there is no CSW in CB protocol. */ + + transfer_request->ux_slave_transfer_request_completion_code = UX_SUCCESS; + transfer_request->ux_slave_transfer_request_status = UX_TRANSFER_STATUS_COMPLETED; + + return UX_SUCCESS; + } + } + + return _ux_dcd_sim_slave_function(dcd, function, parameter); +} + +static void format_ram_disk() +{ + +UINT status; + + + /* We need to close media before formatting. */ + status = fx_media_close(&global_ram_disk); + if (status != FX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + status = fx_media_format(&global_ram_disk, _fx_ram_driver, global_ram_disk_memory, global_ram_disk_working_buffer, global_sector_size, "RAM DISK", 2, UX_TEST_NUM_DIRECTORY_ENTRIES, 0, UX_RAM_DISK_SIZE/global_sector_size, global_sector_size, 4, 1, 1); + if (status != FX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + status = fx_media_open(&global_ram_disk, "RAM DISK", _fx_ram_driver, global_ram_disk_memory, global_ram_disk_working_buffer, sizeof(global_ram_disk_working_buffer)); + if (status != FX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } +} + +/* Disconnection and connection functions. Note that these should be the only ways you disconnect and connect, for the + sake of 'funneling'. */ + +/* This function should not be called from inside USBX because we wait for the deactivation to finish. If we have a + semaphore the deactivation routine requires, then we have deadlock. + Note that we format the ram disk during connection because global_sector_size uses changes after we call + disconnect(). */ +static void disconnect_host_and_slave() +{ + + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect_no_wait(); + + /* Wait for disconnect to finish. */ + while (global_hcd->ux_hcd_nb_devices != 0) + tx_thread_sleep(10); + + /* Do a memory check. */ + + /* Has the value not been initialized yet? */ + if (global_memory_test_no_device_memory_free_amount == 0) + return; + + if (_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available != global_memory_test_no_device_memory_free_amount) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } +} + +static void disconnect_host_and_slave_work_func(ULONG input) +{ + + disconnect_host_and_slave(); +} + +static UX_TEST_WORKER_WORK global_disconnect_host_and_slave_work = { 0, disconnect_host_and_slave_work_func }; +static void disconnect_host_and_slave_action_func(UX_TEST_ACTION *action, VOID *_params) +{ + +UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *params = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *)_params; + + + ux_test_worker_add_work(&global_disconnect_host_and_slave_work); + + /* Allow enum thread to run. This is what we want to have happen, like, all of the time. */ + tx_thread_relinquish(); +} + +/* Note: This assumes the enum thread is already running AKA enum thread's semaphore + was put() before. */ +static UINT wait_for_enum_completion_and_get_global_storage_values() +{ + +UINT status; + + + /* Should already be running! */ + UX_TEST_ASSERT(_ux_system_host -> ux_system_host_enum_semaphore.tx_semaphore_suspended_count == 0); + + /* Wait for enum thread to complete. */ + while (_ux_system_host -> ux_system_host_enum_semaphore.tx_semaphore_suspended_count == 0) + tx_thread_sleep(10); + + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &global_host_storage_class); + UX_TEST_ASSERT(status == UX_SUCCESS); + + status = ux_host_stack_class_instance_get(global_host_storage_class, 0, (void **) &global_storage); + if (status) + return status; + + global_host_class_ext = global_host_storage_class -> ux_host_class_ext; + + if (global_storage -> ux_host_class_storage_state != UX_HOST_CLASS_INSTANCE_LIVE || + global_host_class_ext == UX_NULL || + global_host_storage_class -> ux_host_class_media == UX_NULL) + return UX_ERROR; + + global_storage_medias = global_host_storage_class->ux_host_class_media; + global_storage_media = &global_storage_medias[0]; +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + global_media = &global_storage_media->ux_host_class_storage_media; +#endif + global_storage_thread = &global_host_class_ext->ux_host_class_thread; + + return status; +} + +/* Returns whether or not the enumeration succeeded. */ +static UINT connect_host_and_slave() +{ + +UINT status; + + + /* The worker thread might be in the middle of waiting for the disconnect + to complete. Don't confuse it! */ + while (ux_test_worker_semaphore.tx_semaphore_suspended_count == 0) + tx_thread_sleep(10); + + /* During the basic test, although we delete the file, it seems to stay + on the disk. Clear everything and reformat the disk (reformatting doesn't + clear everything). */ + memset(global_ram_disk_memory, 0, sizeof(global_ram_disk_memory)); + format_ram_disk(); + + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + + /* No wait because wait_for_enum...() expects the enum thread to be running + when it's called. */ + ux_test_hcd_sim_host_connect_no_wait(UX_FULL_SPEED_DEVICE); + + status = wait_for_enum_completion_and_get_global_storage_values(); + + return status; +} + +static void switch_to_protocol(UCHAR protocol) +{ + switch (protocol) + { + + case UX_HOST_CLASS_STORAGE_PROTOCOL_BO: + device_framework_full_speed[bInterfaceProtocol_POS] = UX_HOST_CLASS_STORAGE_PROTOCOL_BO; + device_framework_high_speed[bInterfaceProtocol_POS] = UX_HOST_CLASS_STORAGE_PROTOCOL_BO; + device_framework_full_speed[bInterfaceSubClass_POS] = UX_HOST_CLASS_STORAGE_SUBCLASS_SCSI; + device_framework_high_speed[bInterfaceSubClass_POS] = UX_HOST_CLASS_STORAGE_SUBCLASS_SCSI; + global_hcd->ux_hcd_entry_function = _ux_test_hcd_sim_host_entry; + global_dcd->ux_slave_dcd_function = _ux_test_dcd_sim_slave_function; + break; + + case UX_HOST_CLASS_STORAGE_PROTOCOL_CBI: + device_framework_full_speed[bInterfaceProtocol_POS] = UX_HOST_CLASS_STORAGE_PROTOCOL_CBI; + device_framework_high_speed[bInterfaceProtocol_POS] = UX_HOST_CLASS_STORAGE_PROTOCOL_CBI; + device_framework_full_speed[bInterfaceSubClass_POS] = UX_HOST_CLASS_STORAGE_SUBCLASS_UFI; + device_framework_high_speed[bInterfaceSubClass_POS] = UX_HOST_CLASS_STORAGE_SUBCLASS_UFI; + global_hcd->ux_hcd_entry_function = _ux_hcd_sim_host_entry_bo_to_cbi; + global_dcd->ux_slave_dcd_function = _ux_dcd_sim_slave_function_bo_to_cbi; + break; + + case UX_HOST_CLASS_STORAGE_PROTOCOL_CB: + device_framework_full_speed[bInterfaceProtocol_POS] = UX_HOST_CLASS_STORAGE_PROTOCOL_CB; + device_framework_high_speed[bInterfaceProtocol_POS] = UX_HOST_CLASS_STORAGE_PROTOCOL_CB; + device_framework_full_speed[bInterfaceSubClass_POS] = UX_HOST_CLASS_STORAGE_SUBCLASS_UFI; + device_framework_high_speed[bInterfaceSubClass_POS] = UX_HOST_CLASS_STORAGE_SUBCLASS_UFI; + global_hcd->ux_hcd_entry_function = _ux_hcd_sim_host_entry_bo_to_cb; + global_dcd->ux_slave_dcd_function = _ux_dcd_sim_slave_function_bo_to_cb; + break; + } +} + +/* For restoring state for next test. */ +static void reset_to_bo() +{ + + disconnect_host_and_slave(); + + global_sector_size = UX_HOST_CLASS_STORAGE_SECTOR_SIZE_FAT; + + switch_to_protocol(UX_HOST_CLASS_STORAGE_PROTOCOL_BO); + + bulk_in_endpoint_descriptor_fs[Endpoint_bEndpointAddress] = 0x81; + bulk_in_endpoint_descriptor_hs[Endpoint_bEndpointAddress] = 0x81; + bulk_in_endpoint_descriptor_fs[Endpoint_bmAttributes] = 0x02; + bulk_in_endpoint_descriptor_hs[Endpoint_bmAttributes] = 0x02; + + bulk_out_endpoint_descriptor_fs[Endpoint_bEndpointAddress] = 0x02; + bulk_out_endpoint_descriptor_hs[Endpoint_bEndpointAddress] = 0x02; + bulk_out_endpoint_descriptor_fs[Endpoint_bmAttributes] = 0x02; + bulk_out_endpoint_descriptor_hs[Endpoint_bmAttributes] = 0x02; + + interrupt_in_endpoint_descriptor_fs[Endpoint_bEndpointAddress] = 0x83; + interrupt_in_endpoint_descriptor_hs[Endpoint_bEndpointAddress] = 0x83; + interrupt_in_endpoint_descriptor_fs[Endpoint_bmAttributes] = 0x03; + interrupt_in_endpoint_descriptor_hs[Endpoint_bmAttributes] = 0x03; + + global_persistent_slave_storage->ux_slave_class_storage_number_lun = 1; + global_persistent_slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_type = UX_HOST_CLASS_STORAGE_MEDIA_FAT_DISK; + global_persistent_slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_persistent_slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_block_length = global_sector_size; + + connect_host_and_slave(); +} + +/* This function is called when the device tries to read/write to the device. We return an error so that transfer + succeeds, but the CSW contains an error (this is for the multiple read retries test). */ +static UINT fx_media_read_write_test_error_action_func(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + + *media_status = (ULONG)-1; + return UX_ERROR; +} + +UX_TEST_SETUP global_setup_endpoint_reset_in1 = +{ + UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_ENDPOINT, + UX_CLEAR_FEATURE, + UX_ENDPOINT_HALT, + 0x81 +}; + +UX_TEST_SETUP global_setup_endpoint_reset_out2 = +{ + UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_ENDPOINT, + UX_CLEAR_FEATURE, + UX_ENDPOINT_HALT, + 0x02 +}; + +UX_TEST_SETUP global_setup_mass_storage_reset = +{ + UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE, + UX_HOST_CLASS_STORAGE_RESET, + 0, + 0 +}; + +/* Action creation functions. */ + +static void ux_test_memory_allocate_all_memory_action_func(UX_TEST_ACTION *action, VOID *_params) +{ + + ux_test_utility_sim_mem_allocate_until_align_flagged(0, 0, action->memory_cache_flag); +} + +static UX_TEST_ACTION create_disconnect_on_thread_preemption_change(TX_THREAD *thread_to_match, TX_THREAD *preemption_change_param_thread_ptr, UINT preemption_change_param_new_threshold) +{ + +UX_TEST_ACTION action = { 0 }; + + + action.usbx_function = UX_TEST_OVERRIDE_TX_THREAD_PREEMPTION_CHANGE; + action.thread_ptr = preemption_change_param_thread_ptr; + action.new_threshold = preemption_change_param_new_threshold; + action.action_func = disconnect_host_and_slave_action_func; + action.thread_to_match = thread_to_match; + action.do_after = 1; + + return action; +} + +static VOID device_media_write_block_action_func(UX_TEST_ACTION *action, VOID *_params) +{ + +UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ_WRITE_FLUSH_PARAMS *params = (UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ_WRITE_FLUSH_PARAMS *)_params; + + + /* 100% of the time, we're doing this block so we can hit a transfer timeout branch. The problem is that the + timeouts can take a while, so we abort the waits prematurely from here since the test thread (and therefore host) + are blocked. */ + +DEVICE_MEDIA_READ_WRITE_TIMEOUT_DATA *timeout_data = (DEVICE_MEDIA_READ_WRITE_TIMEOUT_DATA *)action->user_data; +TX_SEMAPHORE *semaphore = &timeout_data->transfer_request->ux_transfer_request_semaphore; + + + while (timeout_data->num_timeouts--) + { + + /* Wait for host thread to wait on the semaphore. */ + while (semaphore->tx_semaphore_suspended_count == 0) + tx_thread_sleep(10); + + UX_TEST_ASSERT(semaphore->tx_semaphore_suspension_list != UX_NULL); + + /* Now simulate a timeout. */ + UX_TEST_CHECK_SUCCESS(tx_thread_wait_abort(semaphore->tx_semaphore_suspension_list)); + } + + /* It's unrealistic for us the complete the write _right_ after the host timeouts. Therefore, we sleep a little + longer. It's up to the user to unblock the CSW we do after. + Note: I got this sleep value from ux_hcd_sim_host_transfer_abort.c: it's 10x the 1 ms it does. */ + ux_utility_delay_ms(10*1); +} + +static UX_TEST_ACTION create_device_media_write_block_action(DEVICE_MEDIA_READ_WRITE_TIMEOUT_DATA *timeout_data) +{ + +UX_TEST_ACTION action = { 0 }; + + + action.usbx_function = UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_WRITE; + action.ignore_params = 1; + action.no_return = 0; + action.status = UX_ERROR; + action.action_func = device_media_write_block_action_func; + action.user_data = (ALIGN_TYPE)timeout_data; + + return(action); +} + +static VOID device_media_read_write_media_status_error_action_func(UX_TEST_ACTION *action, VOID *_params) +{ + +UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ_WRITE_FLUSH_PARAMS *params = (UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ_WRITE_FLUSH_PARAMS *)_params; + + + *params->media_status = ~0; +} + +static VOID device_media_status_error_action_func(UX_TEST_ACTION *action, VOID *_params) +{ + +UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_STATUS_PARAMS *params = (UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_STATUS_PARAMS *)_params; + + + *params->media_status = ~0; +} + +static UX_TEST_ACTION create_device_media_read_fail_action() +{ + +UX_TEST_ACTION action = { 0 }; + + + action.usbx_function = UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ; + action.ignore_params = 1; + action.action_func = device_media_read_write_media_status_error_action_func; + action.no_return = 0; + action.status = UX_ERROR; + + return action; +} + +static UX_TEST_ACTION create_device_media_write_fail_action() +{ + +UX_TEST_ACTION action = { 0 }; + + + action.usbx_function = UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_WRITE; + action.ignore_params = 1; + action.action_func = device_media_read_write_media_status_error_action_func; + action.no_return = 0; + action.status = UX_ERROR; + + return action; +} + +static void configuration_reset_action_func(UX_TEST_ACTION *action, VOID *_params) +{ + +UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *params = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *)_params; +UINT status; + + + status = ux_host_stack_device_configuration_reset(global_host_device); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } +} + +static UX_TEST_ACTION create_disconnect_on_media_characteristics_get_action(TX_THREAD *thread_to_match) +{ + +UX_TEST_ACTION action = { 0 }; + + + action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + action.function = UX_HCD_TRANSFER_REQUEST; + action.req_data = global_cbw_data_media_characteristics_get_sbc; + action.req_actual_len = sizeof(global_cbw_data_media_characteristics_get_sbc); + action.action_func = disconnect_host_and_slave_action_func; + action.thread_to_match = thread_to_match; + action.no_return = 1; + + return action; +} + +static UX_TEST_ACTION create_format_capacity_get_match_action(TX_THREAD *thread_to_match) +{ + +UX_TEST_ACTION action = { 0 }; + + + action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + action.function = UX_HCD_TRANSFER_REQUEST; + action.req_action = UX_TEST_MATCH_REQ_LEN; + action.req_requested_len = UX_HOST_CLASS_STORAGE_READ_FORMAT_RESPONSE_LENGTH; + action.thread_to_match = thread_to_match; + action.no_return = 1; + + return action; +} + +static UX_TEST_ACTION create_disconnect_on_transfer_data_match_action(TX_THREAD *thread_to_match, UCHAR *data, UINT data_size) +{ + +UX_TEST_ACTION action = { 0 }; + + + action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + action.function = UX_HCD_TRANSFER_REQUEST; + action.req_data = data; + action.req_actual_len = data_size; + action.action_func = disconnect_host_and_slave_action_func; + action.thread_to_match = thread_to_match; + action.no_return = 1; + + return action; +} + +static UX_TEST_ACTION create_allocate_all_memory_on_transfer_data_match_action(TX_THREAD *thread_to_match, ULONG memory_cache_flag, UCHAR *data, UINT data_size) +{ + +UX_TEST_ACTION action = { 0 }; + + + action = create_disconnect_on_transfer_data_match_action(thread_to_match, data, data_size); + action.memory_cache_flag = memory_cache_flag; + action.action_func = ux_test_memory_allocate_all_memory_action_func; + action.no_return = 1; + + return action; +} + +static UX_TEST_ACTION create_setup_match_action(TX_THREAD *thread_to_match, UX_TEST_SETUP *req_setup) +{ + +UX_TEST_ACTION action = { 0 }; + + + action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + action.function = UX_HCD_TRANSFER_REQUEST; + action.req_action = UX_TEST_SETUP_MATCH_REQ_V_I; + action.req_setup = req_setup; + action.thread_to_match = thread_to_match; + action.no_return = 1; + + return action; +} + +static UX_TEST_ACTION create_mass_storage_reset_match_action(TX_THREAD *thread_to_match) +{ + +UX_TEST_ACTION action = { 0 }; + + + action = create_setup_match_action(thread_to_match, &global_setup_mass_storage_reset); + + return action; +} + +static UX_TEST_ACTION create_disconnect_on_mass_storage_reset_match_action(TX_THREAD *thread_to_match) +{ + +UX_TEST_ACTION action = { 0 }; + + + action = create_setup_match_action(thread_to_match, &global_setup_mass_storage_reset); + action.action_func = disconnect_host_and_slave_action_func; + + return action; +} + +static UX_TEST_ACTION create_error_match_action_from_error(UX_TEST_ERROR_CALLBACK_ERROR error) +{ + +UX_TEST_ACTION action = create_error_match_action(error.system_level, error.system_context, error.error_code); + + + return action; +} + +static UX_TEST_ACTION create_memory_allocation_fail_error_match_action() +{ + +UX_TEST_ACTION action = create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_UTILITY, UX_MEMORY_INSUFFICIENT); + + + return action; +} + +/* Note: do_after and do_before refer to when the action func is called relative to the HCD function. */ +/* This is to be used as an action func. It simply sets the completion code of a transfer to UX_ERROR */ +static void async_transfer_completion_code_error_action_func_do_after(UX_TEST_ACTION *action, VOID *_params) +{ + +UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *params = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *)_params; +UINT status; +UX_TRANSFER *transfer = params->parameter; + + + status = ux_utility_semaphore_get(&transfer->ux_transfer_request_semaphore, TX_WAIT_FOREVER); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + transfer->ux_transfer_request_completion_code = UX_ERROR; + + status = ux_utility_semaphore_put(&transfer->ux_transfer_request_semaphore); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } +} + +/* This changes the transfer completion code before the HCD is called. */ +static void async_transfer_completion_code_success_action_func_do_before(UX_TEST_ACTION *action, VOID *_params) +{ + +UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *params = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *)_params; +UINT status; +UX_TRANSFER *transfer_request = params->parameter; + + + transfer_request->ux_transfer_request_completion_code = UX_SUCCESS; + + /* Since we're not calling the HCD, we don't wait for the transfer to complete via a sempahore_get(). However, + the caller is still going to wait on the semaphore, so make sure we put() it. */ + status = ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n",__LINE__,(ULONG)status); + test_control_return(1); + } +} + +static UX_TEST_ACTION create_semaphore_get_match_action(TX_THREAD *thread, TX_SEMAPHORE *semaphore, ULONG semaphore_signal) +{ + +UX_TEST_ACTION action = { 0 }; + + + action.usbx_function = UX_TEST_OVERRIDE_TX_SEMAPHORE_GET; + action.semaphore_ptr = semaphore; + action.wait_option = semaphore_signal; + action.thread_to_match = thread; + action.no_return = 1; + + return action; +} + +static UX_TEST_ACTION create_semaphore_get_disconnect_action(TX_THREAD *thread, TX_SEMAPHORE *semaphore, ULONG semaphore_signal) +{ + +UX_TEST_ACTION action = { 0 }; + + + action.usbx_function = UX_TEST_OVERRIDE_TX_SEMAPHORE_GET; + action.semaphore_ptr = semaphore; + action.wait_option = semaphore_signal; + action.thread_to_match = thread; + action.action_func = disconnect_host_and_slave_action_func; + action.no_return = 1; + + return action; +} + +static UX_TEST_ACTION create_test_unit_ready_match_action(TX_THREAD *thread_to_match) +{ + +UX_TEST_ACTION action = { 0 }; + + + action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + action.function = UX_HCD_TRANSFER_REQUEST; + action.req_data = global_cbw_data_unit_ready_test_sbc; + action.req_actual_len = sizeof(global_cbw_data_unit_ready_test_sbc); + action.no_return = 1; + action.thread_to_match = thread_to_match; + + return action; +} + +static UX_TEST_ACTION create_semaphore_get_fail_with_check_override_action(TX_THREAD *thread, TX_SEMAPHORE *semaphore, ULONG semaphore_signal, UCHAR (*check)()) +{ + +UX_TEST_ACTION action = { 0 }; + + + action.usbx_function = UX_TEST_OVERRIDE_TX_SEMAPHORE_GET; + action.semaphore_ptr = semaphore; + action.wait_option = semaphore_signal; + action.thread_to_match = thread; + action.check_func = check; + action.no_return = 1; + + return action; +} + +static void async_transport_stall_test_action_func(UX_TEST_ACTION *action, VOID *_params) +{ + +UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *params = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *)_params; +UINT status; +UX_TRANSFER *transfer_request = params->parameter; + + + transfer_request->ux_transfer_request_completion_code = UX_TRANSFER_STALLED; + + /* Caller is waiting for transfer completion. */ + status = ux_utility_semaphore_put(&transfer_request->ux_transfer_request_semaphore); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } +} + +static void create_request_sense_error_action_func(UX_TEST_ACTION *action, VOID *_params) +{ + +UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *params = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *)_params; +UINT status; +UX_TRANSFER *transfer_request = params->parameter; + + + /* Wait for transfer to complete. */ + status = ux_utility_semaphore_get(&transfer_request->ux_transfer_request_semaphore, TX_WAIT_FOREVER); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + transfer_request->ux_transfer_request_data_pointer[UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_SENSE_KEY] = (UCHAR)action->user_data; + transfer_request->ux_transfer_request_completion_code = UX_SUCCESS; + + /* Signal caller that transfer is complete. */ + status = ux_utility_semaphore_put(&transfer_request->ux_transfer_request_semaphore); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } +} + +static UX_TEST_ACTION create_request_sense_error_action(TX_THREAD *thread_to_match, UINT request_sense_code) +{ + +UX_TEST_ACTION action = { 0 }; + + + /* For making Request Sense contain error. */ + action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + action.function = UX_HCD_TRANSFER_REQUEST; + action.req_action = UX_TEST_MATCH_REQ_LEN; + action.req_requested_len = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH; + action.action_func = create_request_sense_error_action_func; + action.do_after = 1; + action.no_return = 1; + action.thread_to_match = thread_to_match; + action.user_data = request_sense_code; + + return action; +} + +/* Action function for making the CSW contain an error. */ +static void csw_error_action_func(UX_TEST_ACTION *action, VOID *_params) +{ + +UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *params = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *)_params; +UINT status; +UX_TRANSFER *transfer_request = params->parameter; + + + /* Wait for transfer to complete. */ + status = ux_utility_semaphore_get(&transfer_request->ux_transfer_request_semaphore, TX_WAIT_FOREVER); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + transfer_request->ux_transfer_request_data_pointer[UX_HOST_CLASS_STORAGE_CSW_STATUS] = (UCHAR)action->user_data; + transfer_request->ux_transfer_request_completion_code = UX_SUCCESS; + + /* Signal caller that transfer is complete. */ + status = ux_utility_semaphore_put(&transfer_request->ux_transfer_request_semaphore); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } +} + +/* Action function for skipping transfer. */ +static void skip_transfer_action_func(UX_TEST_ACTION *action, VOID *_params) +{ + +UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *params = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *)_params; +UINT status; +UX_TRANSFER *transfer_request = params->parameter; + + + /* Caller is gonna wait! */ + status = ux_utility_semaphore_put(&transfer_request->ux_transfer_request_semaphore); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + transfer_request->ux_transfer_request_completion_code = UX_SUCCESS; +} + +static UX_TEST_ACTION create_endpoint_reset_match_action(TX_THREAD *thread_to_match, UX_TEST_SETUP *setup) +{ + +UX_TEST_ACTION action = { 0 }; + + + action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + action.function = UX_HCD_TRANSFER_REQUEST; + action.req_action = UX_TEST_SETUP_MATCH_REQ_V_I; + action.no_return = 0; /* Host side tests, the actual request is not sent. */ + /* TODO: modify testing to make changes in device side. */ + action.req_setup = setup; + action.thread_to_match = thread_to_match; + + return action; +} + +/* Sets the CSW status to the value specific ('error'). Note: the reason we add the thread to match is because of the + pesky little background storage thread. */ +static UX_TEST_ACTION create_csw_error_action(TX_THREAD *thread_to_match, UINT error) +{ + +UX_TEST_ACTION action = { 0 }; + + + /* For making CSW contain error. */ + action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + action.function = UX_HCD_TRANSFER_REQUEST; + action.req_action = UX_TEST_MATCH_REQ_LEN; + action.req_requested_len = UX_HOST_CLASS_STORAGE_CSW_LENGTH; + action.action_func = csw_error_action_func; + action.do_after = 1; + action.no_return = 1; + action.thread_to_match = thread_to_match; + action.user_data = error; + + return action; +} + +static UX_TEST_ACTION create_data_match_action(TX_THREAD *thread_to_match, UCHAR *data, ULONG data_length) +{ + +UX_TEST_ACTION action = { 0 }; + + + action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + action.function = UX_HCD_TRANSFER_REQUEST; + action.req_data = data; + action.req_actual_len = data_length; + action.thread_to_match = thread_to_match; + action.no_return = 1; + + return action; +} + +static UX_TEST_ACTION create_csw_match_action(TX_THREAD *thread_to_match) +{ + +UX_TEST_ACTION action = { 0 }; + + + action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + action.function = UX_HCD_TRANSFER_REQUEST; + action.req_action = UX_TEST_MATCH_REQ_LEN; + action.req_requested_len = UX_HOST_CLASS_STORAGE_CSW_LENGTH; + action.thread_to_match = thread_to_match; + action.no_return = 1; + + return action; +} + +static UX_TEST_ACTION create_csw_skip_hcd_no_put_action(TX_THREAD *thread_to_match) +{ + +UX_TEST_ACTION action = { 0 }; + + + action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + action.function = UX_HCD_TRANSFER_REQUEST; + action.req_action = UX_TEST_MATCH_REQ_LEN; + action.req_requested_len = UX_HOST_CLASS_STORAGE_CSW_LENGTH; + action.thread_to_match = thread_to_match; + action.no_return = 0; + action.status = UX_SUCCESS; + + return action; +} + +static UX_TEST_ACTION create_csw_skip_hcd_action(TX_THREAD *thread_to_match) +{ + +UX_TEST_ACTION action = { 0 }; + + + action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + action.function = UX_HCD_TRANSFER_REQUEST; + action.req_action = UX_TEST_MATCH_REQ_LEN; + action.req_requested_len = UX_HOST_CLASS_STORAGE_CSW_LENGTH; + action.thread_to_match = thread_to_match; + action.action_func = skip_transfer_action_func; + action.no_return = 0; + action.status = UX_SUCCESS; + + return action; +} + +static UX_TEST_ACTION create_transfer_requested_length_match_action(TX_THREAD *thread_to_match, ULONG length_to_match) +{ + +UX_TEST_ACTION action = { 0 }; + + + action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + action.function = UX_HCD_TRANSFER_REQUEST; + action.req_action = UX_TEST_MATCH_REQ_LEN; + action.req_requested_len = length_to_match; + action.thread_to_match = thread_to_match; + action.no_return = 1; + + return action; +} + +static UX_TEST_ACTION create_data_phase_sector_size_match_action(TX_THREAD *thread_to_match) +{ + +UX_TEST_ACTION action = { 0 }; + + + action = create_transfer_requested_length_match_action(thread_to_match, UX_TEST_DEFAULT_SECTOR_SIZE); + + return action; +} + +static UX_TEST_ACTION create_data_phase_sector_size_stall_action(TX_THREAD *thread_to_match) +{ + +UX_TEST_ACTION action = { 0 }; + + + action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + action = create_data_phase_sector_size_match_action(thread_to_match); + action.action_func = async_transport_stall_test_action_func; + action.do_after = 0; + action.no_return = 0; + action.status = UX_SUCCESS; + action.thread_to_match = thread_to_match; + + return action; +} + +static UX_TEST_ACTION create_disconnect_on_sector_size_transfer_action(TX_THREAD *thread_to_match) +{ + +UX_TEST_ACTION action = { 0 }; + + + action = create_data_phase_sector_size_match_action(thread_to_match); + action.action_func = disconnect_host_and_slave_action_func; + + return action; +} + +static UX_TEST_ACTION create_cbw_match_action(TX_THREAD *thread_to_match) +{ + +UX_TEST_ACTION action = { 0 }; + + + action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + action.function = UX_HCD_TRANSFER_REQUEST; + action.req_action = UX_TEST_MATCH_REQ_LEN; + action.req_requested_len = UX_HOST_CLASS_STORAGE_CBW_LENGTH; + action.thread_to_match = thread_to_match; + action.no_return = 1; + + return action; +} + +static UX_TEST_ACTION create_timeout_on_cbw_action(TX_THREAD *thread_to_match) +{ + +UX_TEST_ACTION action = { 0 }; + + + /* We do this by just not sending the request to the device. */ + + action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + action.function = UX_HCD_TRANSFER_REQUEST; + action.req_action = UX_TEST_MATCH_REQ_LEN; + action.req_requested_len = UX_HOST_CLASS_STORAGE_CBW_LENGTH; + action.thread_to_match = thread_to_match; + action.no_return = 0; + + return action; +} + +static UX_TEST_ACTION create_timeout_on_transfer_action(TX_THREAD *thread_to_match) +{ + +UX_TEST_ACTION action = { 0 }; + + + /* We do this by just not sending the request to the device. */ + + action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + action.function = UX_HCD_TRANSFER_REQUEST; + action.thread_to_match = thread_to_match; + action.no_return = 0; + + return action; +} + +static UX_TEST_ACTION create_cbw_opcode_match_action(TX_THREAD *thread_to_match, UCHAR opcode) +{ + +UX_TEST_ACTION action = { 0 }; + + + action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + action.function = UX_HCD_TRANSFER_REQUEST; + action.req_action = 0; + /* Opcode is right after CBW. */ + action.req_actual_len = UX_HOST_CLASS_STORAGE_CBW_CB + 1; + action.thread_to_match = thread_to_match; + action.no_return = 1; + + action.req_data_match_mask = global_cbw_opcode_match_mask; + + switch (opcode) + { + case UX_HOST_CLASS_STORAGE_SCSI_READ16: + action.req_data = global_cbw_opcode_read; + break; + + default: + UX_TEST_ASSERT(0); + } + + return action; +} + +static UX_TEST_ACTION create_disconnect_on_requested_length_action(TX_THREAD *thread_to_match, UINT requested_length) +{ + +UX_TEST_ACTION action = { 0 }; + + + action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + action.function = UX_HCD_TRANSFER_REQUEST; + action.req_action = UX_TEST_MATCH_REQ_LEN; + action.req_requested_len = requested_length; + action.action_func = disconnect_host_and_slave_action_func; + action.thread_to_match = thread_to_match; + action.no_return = 1; + + return action; +} + +static UX_TEST_ACTION create_config_reset_on_requested_length_action(TX_THREAD *thread_to_match, UINT requested_length) +{ + +UX_TEST_ACTION action = { 0 }; + + + action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + action.function = UX_HCD_TRANSFER_REQUEST; + action.req_action = UX_TEST_MATCH_REQ_LEN; + action.req_requested_len = requested_length; + action.action_func = configuration_reset_action_func; + action.thread_to_match = thread_to_match; + action.no_return = 1; + + return action; +} + +static UX_TEST_ACTION create_cbw_disconnect_action(TX_THREAD *thread_to_match) +{ + +UX_TEST_ACTION action = create_disconnect_on_requested_length_action(thread_to_match, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + + + return action; +} + +static UX_TEST_ACTION create_cbw_config_reset_action(TX_THREAD *thread_to_match) +{ + +UX_TEST_ACTION action = create_config_reset_on_requested_length_action(thread_to_match, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + + + return action; +} + +static UX_TEST_ACTION create_csw_disconnect_action(TX_THREAD *thread_to_match) +{ + +UX_TEST_ACTION action = create_disconnect_on_requested_length_action(thread_to_match, UX_HOST_CLASS_STORAGE_CSW_LENGTH); + + + return action; +} + +/* This will match a CSW and call the supplied action function. */ +static UX_TEST_ACTION create_csw_match_action_with_func(VOID (*entry_func_action)(UX_TEST_ACTION *action, VOID *params), TX_THREAD *thread_to_match) +{ + +UX_TEST_ACTION action = { 0 }; + + + action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + action.function = UX_HCD_TRANSFER_REQUEST; + action.req_action = UX_TEST_MATCH_REQ_LEN; + action.req_requested_len = UX_HOST_CLASS_STORAGE_CSW_LENGTH; + action.action_func = entry_func_action; + action.do_after = 1; + action.thread_to_match = thread_to_match; + + return action; +} + +/* Note: This should be a last resort. + + This will match a CSW and force the transfer completion to stall. Note that this returns before the HCD is called + This because if the transfer makes it to the device, the device will send the CSW, host will see the stall, ask for + another, but won't get it. */ +static UX_TEST_ACTION create_csw_stall_action(TX_THREAD *thread_to_match) +{ + +UX_TEST_ACTION action = { 0 }; + + + action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + action.function = UX_HCD_TRANSFER_REQUEST; + action.req_action = UX_TEST_MATCH_REQ_LEN; + action.req_requested_len = UX_HOST_CLASS_STORAGE_CSW_LENGTH; + action.action_func = async_transport_stall_test_action_func; + action.do_after = 0; + action.thread_to_match = thread_to_match; + + return action; +} + +static UX_TEST_ACTION create_cbw_stall_action(TX_THREAD *thread_to_match) +{ + +UX_TEST_ACTION action = { 0 }; + + + action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + action.function = UX_HCD_TRANSFER_REQUEST; + action.req_action = UX_TEST_MATCH_REQ_LEN; + action.req_requested_len = UX_HOST_CLASS_STORAGE_CBW_LENGTH; + action.action_func = async_transport_stall_test_action_func; + action.do_after = 0; + action.thread_to_match = thread_to_match; + + return action; +} + +static UX_TEST_ACTION create_device_media_status_fail_action() +{ + +UX_TEST_ACTION action = { 0 }; + + + action.usbx_function = UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_STATUS; + action.ignore_params = 1; + action.action_func = device_media_status_error_action_func; + action.no_return = 0; + action.status = UX_ERROR; + + return action; +} + +static VOID add_multiple_read_retries_fails_actions(UX_TEST_ACTION *user_list, TX_THREAD *thread_to_match) +{ + +UINT i; + + + for (i = 0; i < UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RETRY; i++) + { + /* Remember, entire read has to succeed to storage -> ux_host_class_storage_data_phase_length is valid. */ + + /* For safety, match the read CBW. */ + ux_test_add_action_to_user_list(user_list, create_cbw_opcode_match_action(thread_to_match, UX_HOST_CLASS_STORAGE_SCSI_READ16)); + + /* We only send the request sense if the CSW contains an error. */ + ux_test_add_action_to_user_list(user_list, create_csw_error_action(thread_to_match, UX_HOST_CLASS_STORAGE_CSW_FAILED)); + + ux_test_add_action_to_user_list(user_list, create_request_sense_error_action(thread_to_match, UX_ERROR)); + } +} + +static VOID add_multiple_write_retries_fails_actions(UX_TEST_ACTION *user_list) +{ + +UINT i; + + + for (i = 0; i < UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RETRY; i++) + { + ux_test_add_action_to_user_list(user_list, create_device_media_write_fail_action()); + ux_test_add_action_to_user_list(user_list, create_error_match_action_from_error(global_transfer_stall_error)); + } +} + +static VOID add_multiple_status_retries_fails_actions(UX_TEST_ACTION *user_list) +{ + +UINT i; + + + for (i = 0; i < UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RETRY; i++) + { + ux_test_add_action_to_user_list(user_list, create_device_media_status_fail_action()); + ux_test_add_action_to_user_list(user_list, create_error_match_action_from_error(global_transfer_stall_error)); + } +} + +/* Action creation functions END. */ + +/* Action addition utilities. */ + +static void add_unit_ready_test_not_ready_actions(UX_TEST_ACTION *actions) +{ + + ux_test_add_action_to_user_list(actions, create_csw_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_CSW_FAILED)); + ux_test_add_action_to_user_list(actions, create_request_sense_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_SENSE_KEY_NOT_READY)); +} + +static void initialize_test_resources() +{ + +UINT status; + +#if defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + /* Reset media IDs. */ + for (int i = 0; i < UX_HOST_CLASS_STORAGE_MAX_MEDIA; i ++) + _ux_host_class_storage_driver_media(i)->fx_media_id = 0; +#endif + + status = ux_utility_semaphore_create(&global_test_semaphore, "test_semaphore", 0); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + ux_cbi_simulator_initialize(); + ux_test_worker_initialize(); +} + +static void basic_read_write_test(FX_FILE *file) +{ + +UINT status; +ULONG total_length; +UCHAR buffer_pattern; +ULONG bytes_read; +UINT i; + + + /* Set the file length. */ + total_length = UX_DEMO_FILE_SIZE; + + /* Set pattern first letter. */ + buffer_pattern = 'a'; + + /* Seek to the beginning to copy over an existing file. */ + status = fx_file_seek(file, 0); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + while (total_length !=0) + { + + /* Set the buffer with pattern. */ + ux_utility_memory_set(global_buffer, buffer_pattern, UX_DEMO_FILE_BUFFER_SIZE); + + /* Copy the file in blocks */ + status = fx_file_write(file, global_buffer, UX_DEMO_FILE_BUFFER_SIZE); + + /* Check if status OK. */ + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + /* Decrement the length remaining. */ + total_length -= UX_DEMO_FILE_BUFFER_SIZE; + + /* Next pattern. */ + buffer_pattern++; + + /* Check pattern end. */ + if (buffer_pattern > 'z') + + /* Back to beginning. */ + buffer_pattern = 'a'; + } + + /* Seek to the beginning to read. */ + status = fx_file_seek(file, 0); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + /* Set the file length. */ + total_length = UX_DEMO_FILE_SIZE; + + /* Set pattern first letter. */ + buffer_pattern = 'a'; + + while(total_length !=0) + { + + /* Read the file in blocks */ + status = fx_file_read(file, global_buffer, UX_DEMO_FILE_BUFFER_SIZE, &bytes_read); + + /* Check if status OK. */ + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + if (bytes_read != UX_DEMO_FILE_BUFFER_SIZE) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Do compare. */ + for (i = 0; i < UX_DEMO_FILE_BUFFER_SIZE; i++) + { + + if (global_buffer[i] != buffer_pattern) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + } + + /* Decrement the length remaining. */ + total_length -= UX_DEMO_FILE_BUFFER_SIZE; + + /* Next pattern. */ + buffer_pattern++; + + /* Check pattern end. */ + if (buffer_pattern > 'z') + + /* Back to beginning. */ + buffer_pattern = 'a'; + } +} + +/* Performs basic test including deletion, creation, open, writing, and reading. */ +static void basic_test_pre_existing_file(UINT iterations, char *message, FX_FILE *file) +{ + + if (message != UX_NULL) + { + stepinfo("%s", message); + } + + while (iterations--) + basic_read_write_test(file); +} + +/* Performs basic test including deletion, creation, open, writing, and reading. */ +static void basic_test(FX_MEDIA *media, UINT iterations, char *message) +{ + +UINT status; +FX_FILE file; + + + if (message != UX_NULL) + { + stepinfo("%s", message); + } + + while (iterations--) + { + + /* Try to delete the non-existent target file. */ + status = fx_file_delete(media, "FILE.CPY"); + if (status != FX_NOT_FOUND) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + /* Create and open file. */ + ux_test_storage_file_co(media, &file, UX_TRUE); + + basic_read_write_test(&file); + + /* Close and delete file. */ + ux_test_storage_file_cd(media, &file); + } +} + +/* This is for use in the tests array. */ +static void basic_test_with_globals() +{ + + stepinfo("basic_test_with_globals\n"); + basic_test(global_media, 1, UX_NULL); +} + +UINT ux_test_device_class_storage_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + +UINT status; +ULONG old_time_slice; +UX_SLAVE_CLASS *storage_class; +TX_THREAD *storage_thread; + + + status = _ux_device_class_storage_entry(command); + + if (command -> ux_slave_class_command_request == UX_SLAVE_CLASS_COMMAND_INITIALIZE) + { + + storage_class = command->ux_slave_class_command_class_ptr; + + /* Currently, the slave storage thread has no time slice. This is a problem + in the following case: + 1) Device write to storage device fails + 2) Device stalls bulk OUT endpoint + 3) Device sends CSW, waits for transaction scheduler + 4) Host tries to receive CSW, waits for transaction scheduler + 5) Transaction scheduler completes transfer, resumes device + 6) Device storage thread loops forever (with no sleep) waiting for host + to clear OUT endpoint, but host thread can't run because slave + storage thread runs forever. + + This is valid behavior on the device's part since, obviously, + the host isn't running on the same processor. + + The fix is to give the device storage thread a very large time slice; + if it ever reaches the end of the time slice, it means it's waiting + for the host to clear the stall. */ + storage_thread = &storage_class->ux_slave_class_thread; + status = tx_thread_time_slice_change(storage_thread, 100, &old_time_slice); + if (status != TX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + } + + return(status); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_storage_tests_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; + + + /* Inform user. */ + printf("Running Storage Basic Functionality Test............................ "); +#if !(UX_TEST_MULTI_IFC_ON) || !(UX_MAX_SLAVE_LUN > 1) + printf("SKIP!"); + test_control_return(0); + return; +#endif + + stepinfo("\n"); + + /* Initialize testing-related resources. */ + initialize_test_resources(); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Initialize the free memory pointer */ + stack_pointer = (CHAR *) usbx_memory; + memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 2); + + /* Initialize USBX. Memory */ + ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL,0); + + /* Reset ram disk memory. */ + ux_utility_memory_set(global_ram_disk_memory, 0, UX_RAM_DISK_SIZE); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + /* Set the instance activate and deactivate callbacks. */ + global_storage_parameter.ux_slave_class_storage_instance_activate = ux_slave_class_storage_instance_activate; + global_storage_parameter.ux_slave_class_storage_instance_deactivate = ux_slave_class_storage_instance_deactivate; + + /* Initialize the storage class parameters for reading/writing to the Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = global_sector_size; + /* Note: The multiple_and_different_lun_types_test tests the other two types (OPTICAL DISK and IOMEGA CLICK). */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = UX_HOST_CLASS_STORAGE_MEDIA_FAT_DISK; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = default_device_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = default_device_media_write; +#ifdef BUGFIX /* USBX_200 */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = default_device_media_flush; +#endif + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = default_device_media_status; + + /* Initilize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_test_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_parameter); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + global_dcd = &_ux_system_slave->ux_system_slave_dcd; + global_slave_class_container = &_ux_system_slave->ux_system_slave_class_array[0]; + global_slave_device = &_ux_system_slave->ux_system_slave_device; + global_slave_storage_thread = &global_slave_class_container->ux_slave_class_thread; + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(ux_test_system_host_change_function); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + global_host_device = &_ux_system_host->ux_system_host_device_array[0]; + global_enum_thread = &_ux_system_host->ux_system_host_enum_thread; + + /* Register the error callback. */ + ux_utility_error_callback_register(ux_test_error_callback); + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + global_hcd = &_ux_system_host->ux_system_host_hcd_array[0]; + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_demo_thread_host_simulation, "tx demo host simulation", ux_test_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, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } +} + +/* CO: Create and Open */ +static UINT ux_test_storage_file_co(FX_MEDIA *media, FX_FILE *file, UCHAR fail_on_error) +{ + +UINT status; + + + /* Create the file. */ + status = fx_file_create(media, "FILE.CPY"); + if (fail_on_error == UX_TRUE && status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + memset(file,0,sizeof(FX_FILE)); + + /* Open file for copying. */ + status = fx_file_open(media,file,"FILE.CPY",FX_OPEN_FOR_WRITE); + if (fail_on_error == UX_TRUE && status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + /* Seek to the beginning to copy over an existing file. */ + status = fx_file_seek(file,0); + if (fail_on_error == UX_TRUE && status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + return status; +} + +/* COW: Create, Open, and Write */ +static UINT ux_test_storage_file_cow(FX_MEDIA *media, FX_FILE *file, UCHAR *data_pointer, ULONG data_length, UCHAR fail_on_error) +{ + +UINT status; + + + status = ux_test_storage_file_co(media, file, fail_on_error); + if (fail_on_error == UX_TRUE && status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + status = fx_file_write(file, data_pointer, data_length); + if (fail_on_error == UX_TRUE && status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + /* Ensure it's actually written to. */ + UX_TEST_CHECK_SUCCESS(fx_media_flush(media)); + + /* Most of the time, we want to do a read right after. */ + status = fx_file_seek(file, 0); + if (fail_on_error == UX_TRUE && status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + return status; +} + +static void ux_test_storage_file_cd(FX_MEDIA *media, FX_FILE *file) +{ + +UINT status; + + + /* Close the file. */ + status = fx_file_close(file); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + /* Delete the target file. */ + status = fx_file_delete(media, "FILE.CPY"); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } +} + +static void ux_test_storage_file_cowcd(FX_MEDIA *media, FX_FILE *file, UCHAR *data_pointer, ULONG data_length) +{ + + ux_test_storage_file_cow(media, file, data_pointer, data_length, UX_TRUE); + ux_test_storage_file_cd(media, file); +} + +/* Device reset test resources. */ + +static void device_reset_test(UINT cb_length, UCHAR *message) +{ + +UCHAR transfer_request_data_unit_test_cbw[] = { 0x55, 0x53, 0x42, 0x43, 0x43, 0x42, 0x53, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, cb_length, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +UX_TEST_ACTION actions[] = { + create_cbw_match_action(tx_thread_identify()), + create_csw_error_action(tx_thread_identify(), UX_HOST_CLASS_STORAGE_CSW_PHASE_ERROR), + { 0 } +}; + + + /* Test ux_host_class_storage_device_reset. */ + if (message) + { + stepinfo("%s", message); + } + + /* Set our amazing action. */ + ux_test_set_main_action_list_from_array(actions); + + lock_out_storage_thread(); + UX_TEST_CHECK_NOT_SUCCESS(ux_test_host_class_storage_media_write(global_storage, 10, 1, global_buffer)); + lock_in_storage_thread(); +} + +static void let_storage_thread_run() +{ + + /* Get the semaphore so we can keep track of the storage thread. */ + lock_out_storage_thread(); + + /* Wait for storage thread to wait on the semaphore. */ + while (global_storage->ux_host_class_storage_semaphore.tx_semaphore_suspended_count == 0) + tx_thread_sleep(10); + + /* Now let storage thread run. */ + lock_in_storage_thread(); + tx_thread_sleep(100); + + /* TODO: match a 2 second sleep via test action engine (trademark)? */ + + /* Wait for storage thread to complete a single cycle. We know it has when it does the 2 second sleep (hopefullly + there aren't any other sleeps it does though...). */ + UINT global_storage_thread_state; + do + { + + tx_thread_sleep(10); + UX_TEST_CHECK_SUCCESS(tx_thread_info_get(global_storage_thread, UX_NULL, &global_storage_thread_state, UX_NULL, UX_NULL, UX_NULL, UX_NULL, UX_NULL, UX_NULL)); + } while (global_storage_thread_state != TX_SLEEP); +} + +/* Test unit ready test resourcs. */ + +UCHAR turt_unit_attention_first_semaphore_get_fails_check_action_function() +{ + + /* Have we closed the media yet? */ + return global_media->fx_media_id == 0 ? UX_TRUE : UX_FALSE; +} + +static void test_unit_ready_test() +{ + +UINT i; +UINT sense_code_values[] = { UX_HOST_CLASS_STORAGE_SENSE_KEY_NOT_READY, UX_HOST_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION }; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UCHAR *stringies[] = { "UX_HOST_CLASS_STORAGE_SENSE_KEY_NOT_READY", "UX_HOST_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION" }; +UX_HOST_CLASS_STORAGE *local_init_storage = global_storage; +UX_TEST_ACTION *action_item; + + UX_TEST_ACTION not_ready_actions[] = { + create_csw_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_CSW_FAILED), + create_request_sense_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_SENSE_KEY_NOT_READY), + { 0 } + }; + + UX_TEST_ACTION unit_attention_actions[] = { + create_csw_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_CSW_FAILED), + create_request_sense_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION), + { 0 } + }; + + UX_TEST_ACTION not_ready_first_semaphore_get_disconnect_actions[] = { + create_csw_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_CSW_FAILED), + create_request_sense_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_SENSE_KEY_NOT_READY), + /* The first semaphore_get() will be from the fx_media_close to flush. */ + create_semaphore_get_match_action(global_storage_thread, &global_storage->ux_host_class_storage_semaphore, UX_WAIT_FOREVER), + /* The second semaphore_get() will be from the fx_media_close to unittialize driver. */ + create_semaphore_get_match_action(global_storage_thread, &global_storage->ux_host_class_storage_semaphore, UX_WAIT_FOREVER), + create_semaphore_get_disconnect_action(global_storage_thread, &global_storage->ux_host_class_storage_semaphore, UX_WAIT_FOREVER), + { 0 } + }; + + UX_TEST_ACTION first_class_instance_semaphore_get_disconnect_actions[] = { + create_semaphore_get_disconnect_action(global_storage_thread, &global_storage->ux_host_class_storage_semaphore, UX_WAIT_FOREVER), + { 0 } + }; + + UX_TEST_ACTION unit_attention_unit_ready_test_disconnect_actions[] = { + create_csw_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_CSW_FAILED), + create_request_sense_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION), + create_disconnect_on_transfer_data_match_action(global_storage_thread, global_cbw_data_unit_ready_test_sbc, sizeof(global_cbw_data_unit_ready_test_sbc)), + { 0 } + }; + + UX_TEST_ACTION unit_attention_media_characteristics_get_disconnect_actions[] = { + create_csw_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_CSW_FAILED), + create_request_sense_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION), + create_disconnect_on_media_characteristics_get_action(global_storage_thread), + { 0 } + }; + + UX_TEST_ACTION unit_attention_unit_ready_test_request_sense_disconnect_actions[] = { + create_csw_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_CSW_FAILED), + create_request_sense_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION), + create_disconnect_on_transfer_data_match_action(global_storage_thread, global_cbw_data_unit_ready_test_sbc, sizeof(global_cbw_data_unit_ready_test_sbc)), + { 0 } + }; + + UX_TEST_ACTION unit_attention_format_capacity_get_fails_via_memory_alloc_failure_actions[] = { + create_csw_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_CSW_FAILED), + create_request_sense_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION), + create_test_unit_ready_match_action(global_storage_thread), + /* We do two format_capacity_get()s. Make the second one fail. */ + create_format_capacity_get_match_action(global_storage_thread), + /* The only way format_capacity_get fails is via memory allocation failure. */ + create_allocate_all_memory_on_transfer_data_match_action(global_storage_thread, UX_CACHE_SAFE_MEMORY, global_cbw_data_media_capacity_get_sbc, sizeof(global_cbw_data_media_capacity_get_sbc)), + create_memory_allocation_fail_error_match_action(global_storage_thread), + { 0 } + }; + + UX_TEST_ACTION unit_attention_first_semaphore_get_disconnect_actions[] = { + create_csw_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_CSW_FAILED), + create_request_sense_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION), + /* The first semaphore_get() will be from the fx_media_close to flush. */ + create_semaphore_get_match_action(global_storage_thread, &global_storage->ux_host_class_storage_semaphore, UX_WAIT_FOREVER), + /* The second semaphore_get() will be from the fx_media_close to unittialize driver. */ + create_semaphore_get_match_action(global_storage_thread, &global_storage->ux_host_class_storage_semaphore, UX_WAIT_FOREVER), + create_semaphore_get_disconnect_action(global_storage_thread, &global_storage->ux_host_class_storage_semaphore, UX_WAIT_FOREVER), + { 0 } + }; + + UX_TEST_ACTION *all_actions[] = { + unit_attention_format_capacity_get_fails_via_memory_alloc_failure_actions, + unit_attention_first_semaphore_get_disconnect_actions, + not_ready_first_semaphore_get_disconnect_actions, + unit_attention_media_characteristics_get_disconnect_actions, + first_class_instance_semaphore_get_disconnect_actions, + not_ready_actions, + unit_attention_actions, + unit_attention_unit_ready_test_disconnect_actions, + unit_attention_unit_ready_test_request_sense_disconnect_actions, + }; + + + stepinfo("unit_ready_test_test\n"); + + stepinfo(" single lun\n"); + + for (i = 0; i < ARRAY_COUNT(all_actions); i++) + { + + stepinfo(" doing %d\n", i); + + if (global_storage != local_init_storage) + { + action_item = all_actions[i]; + while(action_item->function != 0 || action_item->usbx_function != 0) + { + if (action_item->semaphore_ptr == &local_init_storage->ux_host_class_storage_semaphore) + { + action_item->semaphore_ptr = &global_storage->ux_host_class_storage_semaphore; + } + action_item ++; + } + } + + ux_test_set_main_action_list_from_array(all_actions[i]); + + let_storage_thread_run(); + + /* Ensure expected result and clean up. */ + + if (all_actions[i] == not_ready_actions) + { + + /* Make sure storage media is unmounted. */ + if (!!_storage_media_is_mounted()) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + } + else if (all_actions[i] == unit_attention_actions) + { + + /* Make sure storage media is mounted. */ + if (!_storage_media_is_mounted()) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* In thierry, we should've remounted the media, so run a basic test. */ + basic_test(global_media, 1, " running basic test\n"); + } + else if (all_actions[i] == unit_attention_first_semaphore_get_disconnect_actions || + all_actions[i] == first_class_instance_semaphore_get_disconnect_actions || + all_actions[i] == unit_attention_unit_ready_test_disconnect_actions || + all_actions[i] == unit_attention_unit_ready_test_request_sense_disconnect_actions || + all_actions[i] == unit_attention_media_characteristics_get_disconnect_actions || + all_actions[i] == not_ready_first_semaphore_get_disconnect_actions) + { + + /* Note: the disconnection method we use ensures disconnection is complete. */ + + if (global_media->fx_media_id != 0) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Setup for next test. */ + connect_host_and_slave(); + } + else if (all_actions[i] == unit_attention_format_capacity_get_fails_via_memory_alloc_failure_actions) + { + + UX_TEST_ASSERT(ux_test_check_actions_empty()); + + if (global_media->fx_media_id != 0) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* This test consisted of a memory allocation failure. Free the memory. */ + ux_test_utility_sim_mem_free_all_flagged(UX_CACHE_SAFE_MEMORY); + + /* The media is in an unstable state. Reset. */ + disconnect_host_and_slave(); + connect_host_and_slave(); + } + else + { + + /* We should handle them individually. */ + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + UX_TEST_ASSERT(ux_test_check_actions_empty()); + } + + /* For this test, there two LUNs and the second one reports the errors. */ + stepinfo(" Host receives NOT_READY and UNIT_ATTENTION sense keys from second LUN\n"); + + /* Add another LUN. */ + global_persistent_slave_storage->ux_slave_class_storage_number_lun = 2; + global_persistent_slave_storage->ux_slave_class_storage_lun[1] = global_persistent_slave_storage->ux_slave_class_storage_lun[0]; + + for (i = 0;; i++) + { + + stepinfo(" doing %s\n", stringies[i]); + + disconnect_host_and_slave(); + connect_host_and_slave(); + + UX_TEST_ACTION multi_lun_not_ready_actions[] = { + create_csw_match_action(global_storage_thread), + create_csw_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_CSW_FAILED), + create_request_sense_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_SENSE_KEY_NOT_READY), + { 0 } + }; + + UX_TEST_ACTION multi_lun_unit_attention_actions[] = { + create_csw_match_action(global_storage_thread), + create_csw_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_CSW_FAILED), + create_request_sense_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION), + { 0 } + }; + + UX_TEST_ACTION *multi_lun_actions[] = { + multi_lun_not_ready_actions, + multi_lun_unit_attention_actions, + }; + + ux_test_set_main_action_list_from_array(multi_lun_actions[i]); + + /* Let storage thread run at least once. */ + ux_utility_delay_ms(UX_TEST_SLEEP_STORAGE_THREAD_RUN_ONCE); + + /* First LUN should still be mounted. */ + storage_media = global_host_storage_class->ux_host_class_media; + if (!_storage_media_is_mounted()) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + storage_media++; + if (multi_lun_actions[i] == multi_lun_not_ready_actions) + { + + /* Make sure storage media is unmounted. */ + if (!_storage_media_is_mounted()) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + } + else if (multi_lun_actions[i] == multi_lun_unit_attention_actions) + { + + /* Make sure storage media is mounted. */ + if (!_storage_media_is_mounted()) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* In thierry, we should've remounted the media, so run a basic test */ + basic_test(global_media, 1, " running basic test\n"); + } + + if (i == ARRAY_COUNT(multi_lun_actions) - 1) + { + break; + } + } +} + +/* Abort media test resources. */ + +static void abort_media_test() +{ + +UINT status; +FX_FILE file; + + + /* Test aborting the media. */ + stepinfo("Abort media test\n"); + + /* Create file and write something. */ + ux_test_storage_file_cow(global_media, &file, global_buffer, 1, UX_TRUE); + + /* Abort media. Media must be reopened if it is to be used again. */ + status = fx_media_abort(global_media); + if (status != FX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + /* Reopen media. */ +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + status = fx_media_open(global_media, UX_HOST_CLASS_STORAGE_MEDIA_NAME, _ux_host_class_storage_driver_entry, + global_storage, global_storage_media->ux_host_class_storage_media_memory, + UX_HOST_CLASS_STORAGE_MEMORY_BUFFER_SIZE); +#else + status = fx_media_open(global_media, UX_HOST_CLASS_STORAGE_MEDIA_NAME, _ux_host_class_storage_driver_entry, + global_storage_media, _ux_host_class_storage_media_fx_media_memory(global_storage_media), + UX_HOST_CLASS_STORAGE_MEMORY_BUFFER_SIZE); +#endif + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + /* Delete the target file. */ + status = fx_file_delete(global_media, "FILE.CPY"); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + /* Do basic test to ensure everything still works. */ + ux_test_storage_file_cowcd(global_media, &file, global_buffer, 1); +} + +/* boot_sector_write_fail_test resources */ + +static void boot_sector_write_fail_test() +{ + +UINT status; + + + /* Test formatting the media. */ + stepinfo("boot_sector_write_fail_test\n"); + + /* This test forces the boot write in ux_host_class_storage_driver_entry to fail. Writing to the boot sector occurs + during fx_media_volume_set. + Specific test case: ux_host_class_storage_driver_entry.c case FX_DRIVER_BOOT_WRITE */ + stepinfo(" fx_media_volume_set fails due to write error (also boot write fails test)\n"); + + UX_TEST_ACTION actions = { 0 }; + add_multiple_read_retries_fails_actions(&actions, tx_thread_identify()); + ux_test_set_main_action_list_from_list(&actions); + + status = fx_media_volume_set(global_media, "C"); + if (status == UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + stepinfo(" fx_media_volume_set succeeds\n"); + + /* Do it again without the broken media write function. */ + status = fx_media_volume_set(global_media, "C"); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + /* Do basic test to ensure everything still works. */ + basic_test(global_media, 1, " basic testerino\n"); +} + +/* Flush media test resources. */ + +static void flush_media_test() +{ + +UINT status; +FX_FILE file; + + + /* Test flushing the media. */ + stepinfo("Flush media test\n"); + + /* Create, open, and write file. */ + ux_test_storage_file_cow(global_media, &file, global_buffer, 1, UX_TRUE); + + status = fx_media_flush(global_media); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + /* Close and delete file */ + ux_test_storage_file_cd(global_media, &file); +} + +/* Close media test resources. */ + +static void close_media_test() +{ + +UINT status; + + + /* Test closing the media. */ + stepinfo("Close media test\n"); + + status = fx_media_close(global_media); + if (status != FX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } +} + +/* Entry command test resources. */ + +static void entry_command_test() +{ + +UINT status; +UX_HOST_CLASS_COMMAND command; +UX_TEST_ACTION actions[] = { + create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_FUNCTION_NOT_SUPPORTED), + {0} +}; + + + /* Test _ux_host_class_storage_entry unknown command */ + stepinfo("_ux_host_class_storage_entry unknown command\n"); + + ux_test_set_main_action_list_from_array(actions); + + command.ux_host_class_command_request = 0xdeadbeef; + status = ux_host_class_storage_entry(&command); + if (status == UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } +} + +static UINT get_sector_start() +{ +UINT sector_start = global_media->fx_media_driver_logical_sector +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + + global_storage_media->ux_host_class_storage_media_partition_start +#endif + ; + + + return sector_start; +} + +static void ux_test_host_class_storage_media_read_write_basic_test(UINT iterations, char *message, UINT lun) +{ + +UCHAR buffer_pattern; +UINT sector_count; +UINT size; +UINT i; +UINT j; + + + /* Basic ux_test_host_class_storage_media_write & ux_test_host_class_storage_media_write tests. */ + if (message != UX_NULL) + { + stepinfo("%s", message); + } + + if (iterations > 2) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + buffer_pattern = 'G'; + +#if 0 + for (i = 0; i < iterations; i++) +#else + for (i = 0; i < 1; i++) +#endif + { + + if (i == 0) + size = UX_DEMO_FILE_BUFFER_SIZE; + else + size = UX_DEMO_LARGE_FILE_BUFFER_SIZE; + + sector_count = ((size - 1) + global_storage_media->ux_host_class_storage_media_sector_size) / global_storage_media->ux_host_class_storage_media_sector_size; + + if (i == 0) + { + + /* Set buffer we're going to use to write. */ + ux_utility_memory_set(global_buffer, buffer_pattern, size); + } + else + { + + /* Set one half. */ + ux_utility_memory_set(global_buffer, buffer_pattern, size / 2); + + /* Set the other half. */ + ux_utility_memory_set(global_buffer + size / 2, buffer_pattern + 1, size / 2); + } + + lock_out_storage_thread(); + global_storage->ux_host_class_storage_lun = lun; + ux_test_host_class_storage_media_write(global_storage, + global_media->fx_media_driver_logical_sector +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + + global_storage_media->ux_host_class_storage_media_partition_start +#endif + , + sector_count, global_buffer); + lock_in_storage_thread(); + + /* Clear buffer to make sure read() really works. */ + ux_utility_memory_set(global_buffer, 0, UX_DEMO_FILE_BUFFER_SIZE); + + lock_out_storage_thread(); + global_storage->ux_host_class_storage_lun = lun; + ux_test_host_class_storage_media_read(global_storage, + global_media->fx_media_driver_logical_sector +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + + global_storage_media->ux_host_class_storage_media_partition_start +#endif + , + sector_count, global_buffer); + lock_in_storage_thread(); + + /* Check result of read(). */ + if (i == 0) + { + + for (j = 0; j < size; j++) + { + + if (global_buffer[j] != buffer_pattern) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + } + } + else + { + + for (j = 0; j < size / 2; j++) + { + + if ((global_buffer[j] != buffer_pattern) || (global_buffer[size / 2 + j] != (buffer_pattern + 1))) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + } + } + } +} + +/* fx_media_write test resources */ + +/* This is used to match our action with cbw transfer (CBW has a length field, we try to match it). */ +#define WRITE_SIZE (2*UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE) + +static void fx_media_write_test() +{ + +UINT status; +FX_FILE file; + + + stepinfo("Test fx_media_write API\n"); + + /* Specific test case: in ux_host_class_storage_driver_entry, the media_write() fails. */ + stepinfo(" transfer fails\n"); + + ux_test_storage_file_co(global_media, &file, UX_TRUE); + + UX_TEST_ACTION cbw_transfer_fail_actions[] = { + create_cbw_disconnect_action(tx_thread_identify()), + { 0 } + }; + ux_test_set_main_action_list_from_array(cbw_transfer_fail_actions); + + status = fx_file_write(&file, global_buffer, WRITE_SIZE); + if (status == FX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + UX_TEST_ASSERT(ux_test_check_actions_empty()); + connect_host_and_slave(); + + stepinfo(" data phase fails due to timeout\n"); + + DEVICE_MEDIA_READ_WRITE_TIMEOUT_DATA timeout_data; + timeout_data.num_timeouts = 1; + timeout_data.transfer_request = &global_storage->ux_host_class_storage_bulk_out_endpoint->ux_endpoint_transfer_request; + + UX_TEST_ACTION data_phase_timeout_actions[] = { + create_device_media_write_block_action(&timeout_data), + create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_TIMEOUT), + { 0 } + }; + ux_test_set_main_action_list_from_array(data_phase_timeout_actions); + + lock_out_storage_thread(); + UX_TEST_CHECK_NOT_SUCCESS(ux_test_host_class_storage_media_write(global_storage, 10, UX_TEST_MULTIPLE_TRANSFERS_SECTOR_COUNT, global_buffer)); + receive_device_csw(); + lock_in_storage_thread(); + UX_TEST_ASSERT(ux_test_check_actions_empty()); + basic_test(global_media, 1, " basic test\n"); + + /* Specific test case: while (media_retry-- != 0) fails in ux_test_host_class_storage_media_write */ + /* How: Having the device write fail, causing the device to stall the endpoint and send a CSW with error. */ + stepinfo(" multiple retries fails\n"); + + ux_test_storage_file_co(global_media, &file, UX_TRUE); + + UX_TEST_ACTION actions = { 0 }; + add_multiple_write_retries_fails_actions(&actions); + ux_test_set_main_action_list_from_list(&actions); + + status = fx_file_write(&file, global_buffer, WRITE_SIZE); + if (status == FX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + basic_test_pre_existing_file(1, " running basic test\n", &file); + + UX_TEST_ASSERT(ux_test_check_actions_empty()); +} + +#undef WRITE_SIZE + +/* fx_media_read test resources */ + +static UCHAR boot_read_fails_action_check_function() +{ + +UCHAR result; + +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + /* Is this from FileX? */ + result = (get_internal_host_storage_medias()->ux_host_class_storage_media_memory != UX_NULL); +#else + result = UX_TRUE; +#endif + return result ? UX_TRUE : UX_FALSE; +} + +static UX_TEST_ACTION create_boot_read_from_filex_fails_action(TX_THREAD *thread_to_match) +{ + +UX_TEST_ACTION action; + + + action = create_device_media_read_fail_action(thread_to_match); + action.check_func = boot_read_fails_action_check_function; + + return action; +} + +/* BUG_ID_19 - tldr; original sim is broken, so this size only works with fixed sim. */ +#define READ_SIZE (2*UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE) + +static void fx_media_read_test() +{ + +UINT status; +UX_TEST_ERROR_CALLBACK_ERROR transfer_stall_error = { UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HCD, UX_TRANSFER_STALLED }; +FX_FILE file; +ULONG actual_size; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UINT i; + + + stepinfo("Test fx_media_read API\n"); + + stepinfo(" large read\n"); + + /* Set first half of buffer to 'a', second half to 'b'. */ + ux_utility_memory_set(global_buffer_2x_slave_buffer_size, 'a', sizeof(global_buffer_2x_slave_buffer_size)/2); + ux_utility_memory_set(global_buffer_2x_slave_buffer_size + sizeof(global_buffer_2x_slave_buffer_size)/2, 'b', sizeof(global_buffer_2x_slave_buffer_size)/2); + + /* We need to create a file and write to it, since there actually needs to be something to read. */ + ux_test_storage_file_cow(global_media, &file, global_buffer_2x_slave_buffer_size, READ_SIZE, UX_TRUE); + + status = fx_file_read(&file, global_buffer_2x_slave_buffer_size, READ_SIZE, &actual_size); + if (status != FX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + /* Ensure data is correct. */ + for (i = 0; i < sizeof(global_buffer_2x_slave_buffer_size)/2; i++) + { + + if (global_buffer_2x_slave_buffer_size[i] != 'a' || + global_buffer_2x_slave_buffer_size[sizeof(global_buffer_2x_slave_buffer_size)/2 + i] != 'b') + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + } + + /* Specific test case: in ux_host_class_storage_driver_entry, the media_read() fails. */ + stepinfo(" transfer fails\n"); + + status = fx_file_seek(&file, 0); + if (status != FX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + UX_TEST_ACTION cbw_disconnect_actions[] = { + create_cbw_disconnect_action(tx_thread_identify()), + { 0 } + }; + ux_test_set_main_action_list_from_array(cbw_disconnect_actions); + + UX_TEST_CHECK_NOT_SUCCESS(fx_file_read(&file, global_buffer_2x_slave_buffer_size, READ_SIZE, &actual_size)); + connect_host_and_slave(); + +#if 0 /* NOBUGFIX: BUG_ID_25 */ + stepinfo(" multiple BO data phase transfers, first one fails\n"); + + /* Action for making read fail. */ + read_fail_actions[0].is_valid = UX_TRUE; + read_fail_actions[0].func = ux_test_host_class_storage_media_read_test_media_read_action_func; + + /* Set media read action. */ + set_device_media_read_actions(read_fail_actions); + + /* We should get one stall error. */ + ux_test_error_callback_add_error_to_ignore(stall_error); + + status = ux_test_media_read(storage, media->fx_media_driver_logical_sector + + storage_media->ux_host_class_storage_media_partition_start, + 8, media->fx_media_driver_buffer, UX_FALSE); + if (status == UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } +#endif + + /* Specific test case: while (media_retry-- != 0) fails */ + /* Specific test case: if (*(cbw + UX_HOST_CLASS_STORAGE_CBW_FLAGS) == UX_HOST_CLASS_STORAGE_DATA_IN) in + ux_host_class_transport_bo */ + /* Note: this one is a pain in the ass, since the sense code check is after + the data phase length check. This means the data phase has to "succeed", + but the sense code contains an error. Is this even possible? I think so: + if the device has less data to send than the host requests, but pads out + the data, then according to the spec (thirteen cases), the device will + stall the endpoint, and most likely, the request sense will have an error. */ + stepinfo(" multiple retries fails\n"); + + ux_test_storage_file_cow(global_media, &file, global_buffer, 512, UX_TRUE); + UX_TEST_ACTION actions = { 0 }; + add_multiple_read_retries_fails_actions(&actions, tx_thread_identify()); + ux_test_set_main_action_list_from_list(&actions); + UX_TEST_CHECK_NOT_SUCCESS(fx_file_read(&file, global_buffer, 512, &actual_size)); + UX_TEST_ASSERT(ux_test_check_actions_empty()); + basic_test_pre_existing_file(1, " running basic test\n", &file); + +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) /* Boot read is available only when FX_MEDIA is integrated. */ + /* This test occurs during enumeration. The boot sector read needs to fail in the USBX storage driver for FileX. + This means we can't just fail during the first boot sector read; we need to fail only when it's a boot sector + read from FileX. How do we determine if it's from FileX? Before USBX calls fx_media_open() (which does the boot + sector read), it initializes a UX_HOST_CLASS_STORAGE_MEDIA instance. We check if that instance is initialized + and if it is, we know FileX is doing the read... The problem is that upon deinitialization, USBX doesn't clear + reset the instance's members, so we do it ourselves. + + Specific test case: ux_host_class_storage_driver_entry.c case FX_DRIVER_BOOT_READ + and + / Ask FileX to mount the partition. / + ux_host_class_storage_media_open.c fx_media_open fails + */ + stepinfo(" boot read fails\n"); + + disconnect_host_and_slave(); + + /* Point the media structure to the first media in the container. */ + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *) _ux_system_host -> ux_system_host_class_array[0].ux_host_class_media; +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + storage_media -> ux_host_class_storage_media_memory = UX_NULL; +#endif + + for (i = 0; i < UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RETRY; i++) + { + ux_test_add_action_to_main_list(create_boot_read_from_filex_fails_action(tx_thread_identify())); + ux_test_add_action_to_main_list(create_error_match_action_from_error(transfer_stall_error)); + } + + connect_host_and_slave(); + + /* Since boot read should've failed, the storage instance shouldn't be valid. */ + if (global_media -> fx_media_id != 0) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } +#endif +} + +/* first_sector_non_boot_test_ram_disk_memory test resources */ + +static CHAR first_sector_non_boot_test_ram_disk_memory[1*1024]; + +static VOID first_sector_non_boot_test_media_read_action_func(UX_TEST_ACTION *action, VOID *_params) +{ + +UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ_WRITE_FLUSH_PARAMS *params = (UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ_WRITE_FLUSH_PARAMS *)_params; + + + while (params->number_blocks--) + { + ux_utility_memory_copy(params->data_pointer, first_sector_non_boot_test_ram_disk_memory + global_sector_size * params->lba, global_sector_size); + params->lba++; + } +} + +static UX_TEST_ACTION create_first_sector_non_boot_test_media_read_action() +{ + +UX_TEST_ACTION action = { 0 }; + + + action.usbx_function = UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ; + action.ignore_params = 1; + action.no_return = 0; + action.status = UX_SUCCESS; + action.action_func = first_sector_non_boot_test_media_read_action_func; + + return action; +} + +/* Tests the cases where the first sector is not the boot sector, but instead a partition table. */ +static void first_sector_non_boot_test() +{ + +UINT i; +UX_SLAVE_CLASS_STORAGE *device_storage; +UCHAR *extended_partition; +UCHAR *partition_table; +UCHAR partition_types[] = { + /* Extended partitions. */ + UX_HOST_CLASS_STORAGE_PARTITION_EXTENDED, + UX_HOST_CLASS_STORAGE_PARTITION_EXTENDED_LBA_MAPPED, + + /* Regular partitions. */ + UX_HOST_CLASS_STORAGE_PARTITION_FAT_12, + UX_HOST_CLASS_STORAGE_PARTITION_FAT_16, + UX_HOST_CLASS_STORAGE_PARTITION_FAT_16L, + UX_HOST_CLASS_STORAGE_PARTITION_FAT_16_LBA_MAPPED, + UX_HOST_CLASS_STORAGE_PARTITION_FAT_32_1, + UX_HOST_CLASS_STORAGE_PARTITION_FAT_32_2, + + /* Unknown partition. */ + 0xff +}; +UX_TEST_ACTION first_sector_non_boot_test_extended_media_actions[] = { + create_first_sector_non_boot_test_media_read_action(), + create_first_sector_non_boot_test_media_read_action(), + { 0 } +}; +UX_TEST_ACTION first_sector_non_boot_test_media_read_actions[] = { + create_first_sector_non_boot_test_media_read_action(), + { 0 } +}; + + + stepinfo("first sector is not boot test\n"); + + /* Get device storage instance. */ + device_storage = _ux_system_slave->ux_system_slave_class_array[0].ux_slave_class_instance; + + for (i = 0; i < ARRAY_COUNT(partition_types); i++) + { + + stepinfo(" doing %d\n", i); + + disconnect_host_and_slave(); + + /* Set disk. */ + + partition_table = &first_sector_non_boot_test_ram_disk_memory[UX_HOST_CLASS_STORAGE_PARTITION_TABLE_START]; + + /* Set partition signature. */ + ux_utility_short_put(first_sector_non_boot_test_ram_disk_memory + 510, UX_HOST_CLASS_STORAGE_PARTITION_SIGNATURE); + + /* Make sure there's no boot signature. */ + first_sector_non_boot_test_ram_disk_memory[0] = 0x00; + first_sector_non_boot_test_ram_disk_memory[1] = 0x00; + first_sector_non_boot_test_ram_disk_memory[2] = 0x00; + + /* Set the partition table entry type. */ + partition_table[UX_HOST_CLASS_STORAGE_PARTITION_TYPE] = partition_types[i]; + + /* Is this an extended entry? An extended entry means it points to another partition table. */ + if (partition_types[i] == UX_HOST_CLASS_STORAGE_PARTITION_EXTENDED || + partition_types[i] == UX_HOST_CLASS_STORAGE_PARTITION_EXTENDED_LBA_MAPPED) + { + + /* The extended partition is located one sector away. */ + partition_table[UX_HOST_CLASS_STORAGE_PARTITION_SECTORS_BEFORE] = 1; + + /* Set disk. */ + + extended_partition = &first_sector_non_boot_test_ram_disk_memory[UX_HOST_CLASS_STORAGE_SECTOR_SIZE_FAT]; + partition_table = &extended_partition[UX_HOST_CLASS_STORAGE_PARTITION_TABLE_START]; + + /* Set partition signature. */ + ux_utility_short_put(extended_partition + 510, UX_HOST_CLASS_STORAGE_PARTITION_SIGNATURE); + + /* Make sure there's no boot signature. */ + extended_partition[0] = 0x00; + extended_partition[1] = 0x00; + extended_partition[2] = 0x00; + + /* Set the type to something non-extended so we don't recurse. */ + partition_table[UX_HOST_CLASS_STORAGE_PARTITION_TYPE] = UX_HOST_CLASS_STORAGE_PARTITION_FAT_12; + + /* We want subsequent boot sector reads to read the beginning of the ram disk (where FileX formatted it). + We need to overflow to get the SECTORS_BEFORE to equal zero. */ + ux_utility_long_put(&partition_table[UX_HOST_CLASS_STORAGE_PARTITION_SECTORS_BEFORE], ~0); + + /* Set action for media read. Since it's an extended entry, it will read twice. */ + ux_test_set_main_action_list_from_array(first_sector_non_boot_test_extended_media_actions); + } + else + { + + /* We want subsequent boot sector reads to read the beginning of the ram disk (where FileX formatted it). */ + partition_table[UX_HOST_CLASS_STORAGE_PARTITION_SECTORS_BEFORE] = 0; + + /* Set action for media read. */ + ux_test_set_main_action_list_from_array(first_sector_non_boot_test_media_read_actions); + } + + /* Start enumeration. */ + connect_host_and_slave(); + + if (partition_types[i] != PARTITION_TYPE_UNKNOWN) + { + + if (global_storage == UX_NULL) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + basic_test(global_media, 1, " running basic test\n"); + } + /* Ensure unknown partition wasn't mounted. */ + else if (global_media->fx_media_id != 0) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + } + + /* Since during the last test the media was never opened, we need to disconnect and reconnect. */ + disconnect_host_and_slave(); + connect_host_and_slave(); +} + +/* multiple_and_different_lun_types_test resources */ + +static UINT madltt_media_types[] = { UX_HOST_CLASS_STORAGE_MEDIA_OPTICAL_DISK, UX_HOST_CLASS_STORAGE_MEDIA_IOMEGA_CLICK, UX_HOST_CLASS_STORAGE_MEDIA_CDROM, MEDIA_TYPE_UNKNOWN }; +static UX_TEST_ERROR_CALLBACK_ERROR dltt_media_not_supported_error = { UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_MEDIA_NOT_SUPPORTED }; +static UCHAR dltt_unit_test_called_actions_data[UX_HOST_CLASS_STORAGE_MAX_MEDIA][sizeof(global_cbw_data_unit_ready_test_sbc)]; +static UX_TEST_ACTION dltt_unit_test_called_actions[UX_HOST_CLASS_STORAGE_MAX_MEDIA + 1]; + +/* This tests every possible permutation of LUN types within the allowable number of medias + (UX_HOST_CLASS_STORAGE_MAX_MEDIA). We don't use the max LUNs because it's possible for us to run out of medias + (USBX-93). */ +static void dltt_test_every_lun_type_permutation(UINT luns_remaining) +{ + +UINT lun_idx; +UINT media_idx; +UINT num_medias; +UINT expected_medias; +UINT expected_unit_ready_tests; +UX_TEST_ACTION media_not_supported_match_action = create_error_match_action_from_error(dltt_media_not_supported_error); + + + if (luns_remaining > 0) + { + + for (lun_idx = 0; lun_idx < ARRAY_COUNT(madltt_media_types); lun_idx++) + { + + global_persistent_slave_storage->ux_slave_class_storage_lun[luns_remaining - 1].ux_slave_class_storage_media_type = madltt_media_types[lun_idx]; + global_persistent_slave_storage->ux_slave_class_storage_lun[luns_remaining - 1].ux_slave_class_storage_media_removable_flag = (lun_idx % 2) ? 0x80 : 0x00; + dltt_test_every_lun_type_permutation(luns_remaining - 1); + } + } + else + { + + /* All the LUNs are set. Let's do it! */ + + stepinfo(" disconnecting...\n"); + + disconnect_host_and_slave(); + + global_persistent_slave_storage->ux_slave_class_storage_number_lun = UX_HOST_CLASS_STORAGE_MAX_MEDIA; + + /* Initialize actions. */ + ux_utility_memory_set(dltt_unit_test_called_actions, 0, sizeof(dltt_unit_test_called_actions)); + + /* Get the number of medias we expect the LUNs should have, and add errors to ignore. */ + expected_medias = 0; + expected_unit_ready_tests = 0; + for (lun_idx = 0; lun_idx < ARRAY_COUNT(global_persistent_slave_storage->ux_slave_class_storage_lun); lun_idx++) + { + + if (global_persistent_slave_storage->ux_slave_class_storage_lun[lun_idx].ux_slave_class_storage_media_type == UX_HOST_CLASS_STORAGE_MEDIA_OPTICAL_DISK || + global_persistent_slave_storage->ux_slave_class_storage_lun[lun_idx].ux_slave_class_storage_media_type == UX_HOST_CLASS_STORAGE_MEDIA_IOMEGA_CLICK || + global_persistent_slave_storage->ux_slave_class_storage_lun[lun_idx].ux_slave_class_storage_media_type == UX_HOST_CLASS_STORAGE_MEDIA_FAT_DISK) + { + expected_medias++; + +#if 0 /* NOBUGFIX: USBX_100 */ + if (global_persistent_slave_storage->ux_slave_class_storage_lun[lun_idx].ux_slave_class_storage_media_removable_flag == 0x80) + { + + ux_utility_memory_copy(dltt_unit_test_called_actions_data[expected_unit_ready_tests], global_transfer_request_data_unit_test_sbc_cbw, sizeof(global_transfer_request_data_unit_test_sbc_cbw)); + dltt_unit_test_called_actions_data[expected_unit_ready_tests][UX_HOST_CLASS_STORAGE_CBW_LUN] = lun_idx; + dltt_unit_test_called_actions[expected_unit_ready_tests].function = UX_HCD_TRANSFER_REQUEST; + dltt_unit_test_called_actions[expected_unit_ready_tests].req_actual_len = sizeof(global_transfer_request_data_unit_test_sbc_cbw); + dltt_unit_test_called_actions[expected_unit_ready_tests].no_return = 1; + dltt_unit_test_called_actions[expected_unit_ready_tests].req_data = dltt_unit_test_called_actions_data[expected_unit_ready_tests]; + expected_unit_ready_tests++; + } +#endif + } + else if (global_persistent_slave_storage->ux_slave_class_storage_lun[lun_idx].ux_slave_class_storage_media_type == MEDIA_TYPE_UNKNOWN) + { + + ux_test_add_action_to_main_list(media_not_supported_match_action); + } + } + + for (lun_idx = 0; lun_idx < UX_HOST_CLASS_STORAGE_MAX_MEDIA; lun_idx++) + stepinfo( " media type: %lu\n", global_persistent_slave_storage->ux_slave_class_storage_lun[lun_idx].ux_slave_class_storage_media_type); + + stepinfo(" connecting...\n"); + connect_host_and_slave(); + + stepinfo(" waiting 2 seconds for storage thread to run...\n"); + +#if 0 /* NOBUGFIX: USBX_100 */ + /* Add actions. */ + if (dltt_unit_test_called_actions[0].function != 0) + ux_test_set_actions(dltt_unit_test_called_actions); +#endif + + /* Let storage thread run least once. */ + ux_utility_delay_ms(UX_TEST_SLEEP_STORAGE_THREAD_RUN_ONCE); + +#if 0 /* NOBUGFIX USBX_100 */ + if (ux_test_actions_empty_check() != UX_TRUE) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } +#endif + + /* Go through each LUN and run a test if applicable. */ + num_medias = 0; + media_idx = 0; + for (lun_idx = 0; lun_idx < UX_HOST_CLASS_STORAGE_MAX_MEDIA; lun_idx++) + { + + if (global_storage->ux_host_class_storage_lun_types[lun_idx] == UX_HOST_CLASS_STORAGE_MEDIA_OPTICAL_DISK || + global_storage->ux_host_class_storage_lun_types[lun_idx] == UX_HOST_CLASS_STORAGE_MEDIA_IOMEGA_CLICK || + global_storage->ux_host_class_storage_lun_types[lun_idx] == UX_HOST_CLASS_STORAGE_MEDIA_FAT_DISK) + { + + /* Only optical disks, fat disks, and iomega clicks have FX_MEDIAs instances, which is why we only + increment media_idx if the type is one of those two. */ + basic_test( +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + &global_storage_medias[media_idx++].ux_host_class_storage_media, +#else + _ux_host_class_storage_media_fx_media(&global_storage_medias[media_idx++]), +#endif + 1, " running basic test...\n"); + + /* We need to remove the file entirely for the next test. Usually disconnect_host_and_slave() does this + but we're not calling that in between basic_test() calls, now are we?...!...? */ + format_ram_disk(); + + num_medias++; + } + else if (global_storage->ux_host_class_storage_lun_types[lun_idx] == UX_HOST_CLASS_STORAGE_MEDIA_CDROM) + { + + /* For CDROMs, we don't mount the partition, so we can't use FileX. Also, we have to manually set which + LUN we want USBX to write to. */ + ux_test_host_class_storage_media_read_write_basic_test(1, " running basic test...\n", lun_idx); + } + else// if(MEDIA_TYPE_UNKNOWN) + { + /* Do nothing. */ + } + } + + if (num_medias != expected_medias) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + if (ux_test_check_actions_empty() == UX_FALSE) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + } +} + +static void multiple_and_different_lun_types_test() +{ + +UINT i; +UX_TEST_ACTION unknown_media_error_actions[] = { + create_error_match_action_from_error(dltt_media_not_supported_error), + { 0 } +}; + + + /* Specific test cases: (storage -> ux_host_class_storage_removable_media == UX_HOST_CLASS_STORAGE_MEDIA_REMOVABLE) + passes and fails in ux_host_class_storage_thread_entry.c */ + + stepinfo("multiple_and_different_lun_types_test\n"); + + stepinfo(" max lun test\n"); + + for (i = 1; i < UX_HOST_CLASS_STORAGE_MAX_MEDIA; i++) + { + global_persistent_slave_storage->ux_slave_class_storage_lun[i] = global_persistent_slave_storage->ux_slave_class_storage_lun[0]; + } + + dltt_test_every_lun_type_permutation(UX_HOST_CLASS_STORAGE_MAX_MEDIA); + + /* Note: if there's a test after this, we should reset_to_bo(). */ + reset_to_bo(); + + /* When we disconnect the slave, it sets the global device storage pointer to null. Save it! */ + global_persistent_slave_storage = global_slave_storage; +} + +/* Transport failures cause device reset test resources. */ + +static void transport_failures_cause_device_reset_test() +{ + + UX_TEST_ACTION actions[] = { + /* This will cause the CSW to contain an error. */ + create_device_media_write_fail_action(), + /* This is how we make the REQUEST SENSE fail. Every other option is completely ridiculous (i.e. transmission + error, which never ever happens, and if they do happen, then the controller is broken). */ + create_disconnect_on_transfer_data_match_action(tx_thread_identify(), global_cbw_data_request_sense, sizeof(global_cbw_data_request_sense)), + /* Since we disconnect, the request is never sent to the HCD, so we can't check it. */ + //create_mass_storage_reset_match_action(tx_thread_identify()), + { 0 } + }; + + + stepinfo("transport_failures_cause_device_reset_test\n"); + + ux_test_set_main_action_list_from_array(actions); + + lock_out_storage_thread(); + UX_TEST_CHECK_NOT_SUCCESS(ux_test_host_class_storage_media_write(global_storage, 10, 1, global_buffer)); + lock_in_storage_thread(); + + connect_host_and_slave(); +} + +/* Resources for failure of starting the UFI device test. */ + +static void ufi_start_fails_action_func(UX_TEST_ACTION *action, VOID *_params) +{ + +UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *params = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *)_params; +UX_TRANSFER *transfer_request = params->parameter; + + + transfer_request->ux_transfer_request_completion_code = UX_ERROR; +} + +/* Specific test case: _ux_host_class_storage_start_stop fails in _ux_host_class_storage_media_mount */ +static void ufi_start_fails() +{ + +UCHAR transfer_data_ufi_start_cb[] = { 0x55, 0x53, 0x42, 0x43, 0x43, 0x42, 0x53, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +UX_TEST_ACTION actions[2] = { 0 }; + + + stepinfo("ufi_start_fails test\n"); + + /* Action for making transfer of start command fail. */ + actions[0].usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + actions[0].function = UX_HCD_TRANSFER_REQUEST; + actions[0].action_func = ufi_start_fails_action_func; + actions[0].req_data = transfer_data_ufi_start_cb; + actions[0].req_actual_len = sizeof(transfer_data_ufi_start_cb); + actions[0].no_return = 0; + actions[0].status = UX_ERROR; + + disconnect_host_and_slave(); + + /* Switch to CBI (only CBI requires start command). */ + + device_framework_full_speed[bInterfaceProtocol_POS] = UX_HOST_CLASS_STORAGE_PROTOCOL_CBI; + device_framework_high_speed[bInterfaceProtocol_POS] = UX_HOST_CLASS_STORAGE_PROTOCOL_CBI; + device_framework_full_speed[bInterfaceSubClass_POS] = UX_HOST_CLASS_STORAGE_SUBCLASS_UFI; + device_framework_high_speed[bInterfaceSubClass_POS] = UX_HOST_CLASS_STORAGE_SUBCLASS_UFI; + + global_hcd->ux_hcd_entry_function = _ux_hcd_sim_host_entry_bo_to_cbi; + global_dcd->ux_slave_dcd_function = _ux_dcd_sim_slave_function_bo_to_cbi; + + /* Set actions */ + ux_test_set_main_action_list_from_array(actions); + + connect_host_and_slave(); + + if (global_media->fx_media_id == FX_MEDIA_ID) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } +} + +/* First sector read fails test resources. */ + +/* Specific test case: case UX_HOST_CLASS_STORAGE_SENSE_ERROR: and default: in ux_host_class_storage_media_mount */ +static void media_mount_first_sector_read_fails_test() +{ + +UINT errors[] = { UX_ERROR, UX_HOST_CLASS_STORAGE_SENSE_ERROR }; + + + stepinfo("media_mount_first_sector_read_fail test\n"); + + /* How: Read keeps failing. Note: this assumes the very first read the one we're looking for. */ + stepinfo(" case UX_HOST_CLASS_STORAGE_SENSE_ERROR: \n"); + + disconnect_host_and_slave(); + UX_TEST_ACTION actions = { 0 }; + add_multiple_read_retries_fails_actions(&actions, tx_thread_identify()); + ux_test_set_main_action_list_from_list(&actions); + connect_host_and_slave(); + + /* How: we disconnect during the read. */ + stepinfo(" default :\n"); + + disconnect_host_and_slave(); + ux_test_add_action_to_main_list(create_disconnect_on_transfer_data_match_action(global_enum_thread, global_cbw_data_first_sector_read, sizeof(global_cbw_data_first_sector_read))); + UX_TEST_ASSERT(connect_host_and_slave() != UX_SUCCESS); +} + +/* First sector not partition test resources. */ + +static UINT first_sector_different_signatures_test_num; +static ULONG first_sector_different_signatures_sig_values[5][6] = +{ + /* 510 */ /* 0 */ /* 2 */ /* 0x16 */ /* 0x24 */ + /* _ux_utility_short_get(sector_memory + 510) == UX_HOST_CLASS_STORAGE_PARTITION_SIGNATURE fails */ + { ~UX_HOST_CLASS_STORAGE_PARTITION_SIGNATURE, 0, 0, 0, 0, UX_ERROR }, + /* (*sector_memory == 0xe9) fails */ + { UX_HOST_CLASS_STORAGE_PARTITION_SIGNATURE, 0xeb, 0x90, 0xff, 0, UX_SUCCESS }, + /* *(sector_memory + 2) == 0x90 fails */ + { UX_HOST_CLASS_STORAGE_PARTITION_SIGNATURE, 0xeb, 0, 0, 0, UX_ERROR }, + /* _ux_utility_short_get(sector_memory + 0x16) != 0x0 fails and _ux_utility_long_get(sector_memory + 0x24) != 0x0 succeeds */ + { UX_HOST_CLASS_STORAGE_PARTITION_SIGNATURE, 0xe9, 0, 0x00, 0xff, UX_SUCCESS }, + /* _ux_utility_long_get(sector_memory + 0x24) != 0x0 fails */ + { UX_HOST_CLASS_STORAGE_PARTITION_SIGNATURE, 0xe9, 0, 0x00, 0x00, UX_ERROR }, +}; + +static VOID first_sector_different_signatures_action_func(UX_TEST_ACTION *action, VOID *_params) +{ + +UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ_WRITE_FLUSH_PARAMS *params = (UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ_WRITE_FLUSH_PARAMS *)_params; + + + params->data_pointer[510] = (UCHAR) first_sector_different_signatures_sig_values[first_sector_different_signatures_test_num][0]; + params->data_pointer[0] = (UCHAR) first_sector_different_signatures_sig_values[first_sector_different_signatures_test_num][1]; + params->data_pointer[2] = (UCHAR) first_sector_different_signatures_sig_values[first_sector_different_signatures_test_num][2]; + ux_utility_short_put(¶ms->data_pointer[0x16], (USHORT)first_sector_different_signatures_sig_values[first_sector_different_signatures_test_num][3]); + ux_utility_long_put(¶ms->data_pointer[0x24], first_sector_different_signatures_sig_values[first_sector_different_signatures_test_num][4]); +} + +static UX_TEST_ACTION create_first_sector_different_signature_action() +{ + +UX_TEST_ACTION action = { 0 }; + + + action.usbx_function = UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ; + action.action_func = first_sector_different_signatures_action_func; + action.do_after = 1; + action.no_return = 1; + action.ignore_params = 1; + + return action; +} + +/* Specific test case: if (_ux_utility_short_get(sector_memory + 510) == UX_HOST_CLASS_STORAGE_PARTITION_SIGNATURE) fails in ux_host_class_storage_media_mount */ +static void first_sector_different_signatures_test() +{ + +UX_TEST_ACTION actions[] = { + create_first_sector_different_signature_action(), + { 0 } +}; + + + stepinfo("first_sector_different_signatures\n"); + + for (; first_sector_different_signatures_test_num < ARRAY_COUNT(first_sector_different_signatures_sig_values); first_sector_different_signatures_test_num++) + { + + disconnect_host_and_slave(); + ux_test_set_main_action_list_from_array(actions); + connect_host_and_slave(); + + if ((first_sector_different_signatures_sig_values[first_sector_different_signatures_test_num][5] == UX_SUCCESS && global_media->fx_media_id != FX_MEDIA_ID) || + (first_sector_different_signatures_sig_values[first_sector_different_signatures_test_num][5] == UX_ERROR && global_media->fx_media_id == FX_MEDIA_ID)) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + if (first_sector_different_signatures_sig_values[first_sector_different_signatures_test_num][5] == UX_SUCCESS) + basic_test(global_media, 1, " basic test\n"); + } +} + +/* General disconnection test resources. */ + +static VOID disconnection_tests_transfer_action_func(UX_TEST_ACTION *action, VOID *parameter) +{ + + disconnect_host_and_slave(); +} + +static VOID disconnection_tests_transfer_with_relinquish_action_func(UX_TEST_ACTION *action, VOID *parameter) +{ + + ux_test_hcd_sim_host_disconnect_no_wait(); + + /* Simulate time slice running out. */ + tx_thread_relinquish(); +} + +/* Storage class related device disconnect test resources. */ + +static TX_SEMAPHORE transfer_initiated_semaphore; + +static VOID device_disconnect_test_action_func(UX_TEST_ACTION *action, VOID *_params) +{ + +UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *params = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *)_params; +UINT status; + + + /* Tell test thread to start disconnection. */ + status = ux_utility_semaphore_put(&transfer_initiated_semaphore); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } +} + +/* system_host_change_function_test resources */ + +static void system_host_change_function_test() +{ + + stepinfo("system_host_change_function_test\n"); + + disconnect_host_and_slave(); + + /* Set change function to null. */ + _ux_system_host -> ux_system_host_change_function = UX_NULL; + + connect_host_and_slave(); + + /* Since there's no change function registered, our instance should remain null. */ + if (global_storage_change_function != UX_NULL) + { + + printf("Error on line %d, %p\n", __LINE__, global_storage_change_function); + test_control_return(1); + } + + /* Disconnect with null change function. */ + disconnect_host_and_slave(); + + /* Restore change function. */ + _ux_system_host -> ux_system_host_change_function = ux_test_system_host_change_function; + + stepinfo(" connecting...\n"); + + /* Connect with non-null change function. */ + connect_host_and_slave(); + + /* Since our change function was restored, our storage function should've been invoked. */ + if (global_storage_change_function == UX_NULL) + { + + printf("Error on line %d, %p\n", __LINE__, global_storage_change_function); + test_control_return(1); + } +} + +static void direct_calls_test() +{ + +FX_MEDIA media; +UX_TEST_ERROR_CALLBACK_ERROR error = { UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_ENDPOINT_HANDLE_UNKNOWN }; +UX_TEST_ACTION actions[] = { + create_error_match_action_from_error(error), + { 0 } +}; + + + stepinfo("direct calls test\n"); + + /* These cases have no way of being triggered via normal circumstances, and therefore direct calls are required. An + explanation should be provided with each. */ + + /* The FileX storage driver handles every request FileX sends to it. */ + stepinfo(" ux_host_class_storage_driver_entry unknown command\n"); + + media.fx_media_driver_info = global_storage; + media.fx_media_reserved_for_user = (ALIGN_TYPE)global_host_storage_class->ux_host_class_media; + + /* Set to unknown driver request. */ + media.fx_media_driver_request = 0xffffffff; + + _ux_host_class_storage_driver_entry(&media); + if (media.fx_media_driver_status == FX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)media.fx_media_driver_status); + test_control_return(1); + } + +#ifdef BUGFIX /* USBX_89 */ + /* Make interrupt in search fail by setting it's type to non-interrupt. */ + tmp = global_storage->ux_host_class_storage_interface->ux_interface_descriptor.bInterfaceProtocol; + global_storage->ux_host_class_storage_interface->ux_interface_descriptor.bInterfaceProtocol = UX_HOST_CLASS_STORAGE_PROTOCOL_CBI; + global_storage->ux_host_class_storage_interface->ux_interface_first_endpoint->ux_endpoint_next_endpoint->ux_endpoint_next_endpoint->ux_endpoint_descriptor.bmAttributes = 0x00; + ux_test_set_main_action_list_from_array(actions); + status = _ux_host_class_storage_endpoints_get(global_storage); + if (status == UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)media.fx_media_driver_status); + test_control_return(1); + } + global_storage->ux_host_class_storage_interface->ux_interface_first_endpoint->ux_endpoint_next_endpoint->ux_endpoint_next_endpoint->ux_endpoint_descriptor.bmAttributes = UX_INTERRUPT_ENDPOINT; + global_storage->ux_host_class_storage_interface->ux_interface_descriptor.bInterfaceProtocol = tmp; + + global_storage->ux_host_class_storage_interface->ux_interface_descriptor.bNumEndpoints = original_num_endpoints; +#endif +} + +#define ENDPOINT_TYPE_BULK 0x02 +#define ENDPOINT_TYPE_INTERRUPT 0x03 + +static void storage_endpoints_get_test() +{ + +UINT endpoint_addresses[] = { 0x81, 0x02 }; +UCHAR *first_endpoint_fs, *first_endpoint_hs; +UCHAR *second_endpoint_fs, *second_endpoint_hs; +UCHAR *third_endpoint_fs, *third_endpoint_hs; +UX_TEST_ERROR_CALLBACK_ERROR error = { UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_ENDPOINT_HANDLE_UNKNOWN }; + + + stepinfo("_ux_host_class_storage_endpoints_get\n"); + + first_endpoint_fs = bulk_in_endpoint_descriptor_fs; + first_endpoint_hs = bulk_in_endpoint_descriptor_hs; + second_endpoint_fs = bulk_out_endpoint_descriptor_fs; + second_endpoint_hs = bulk_out_endpoint_descriptor_hs; + third_endpoint_fs = interrupt_in_endpoint_descriptor_hs; + third_endpoint_hs = interrupt_in_endpoint_descriptor_fs; + + /* None of these should pass enumeration. It's impossible to hit the test cases without breaking everything (device + assumes bulk endpoints are always first, and one of the test cases is that one of the endpoints before a bulk is + non-bulk). */ + + /** For bulk out: **/ + + /* 1) An endpoint before bulk out must be IN. Set them all to IN. */ + + disconnect_host_and_slave(); + + first_endpoint_fs[Endpoint_bEndpointAddress] = 0x81; + first_endpoint_hs[Endpoint_bEndpointAddress] = 0x81; + + second_endpoint_fs[Endpoint_bEndpointAddress] = 0x82; + second_endpoint_hs[Endpoint_bEndpointAddress] = 0x82; + + third_endpoint_fs[Endpoint_bEndpointAddress] = 0x83; + third_endpoint_hs[Endpoint_bEndpointAddress] = 0x83; + + /* Ignore error. */ + ux_test_add_action_to_main_list(create_error_match_action_from_error(error)); + + connect_host_and_slave(); + + if (global_media->fx_media_id != 0) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, global_media->fx_media_id); + test_control_return(1); + } + + /* 2) An endpoint before bulk out must be OUT and non-bulk. Set the first to OUT and non-bulk. The rest must be IN + so it fails. */ + + disconnect_host_and_slave(); + + first_endpoint_fs[Endpoint_bEndpointAddress] = 0x01; + first_endpoint_hs[Endpoint_bEndpointAddress] = 0x01; + first_endpoint_fs[Endpoint_bmAttributes] = ENDPOINT_TYPE_INTERRUPT; + first_endpoint_hs[Endpoint_bmAttributes] = ENDPOINT_TYPE_INTERRUPT; + first_endpoint_fs[Endpoint_bInterval] = 0x01; + first_endpoint_hs[Endpoint_bInterval] = 0x01; + + second_endpoint_fs[Endpoint_bEndpointAddress] = 0x82; + second_endpoint_hs[Endpoint_bEndpointAddress] = 0x82; + + third_endpoint_fs[Endpoint_bEndpointAddress] = 0x83; + third_endpoint_hs[Endpoint_bEndpointAddress] = 0x83; + + /* This third endpoint is Interrupt, but we must change since if we have multiple Interrupt endpoints, USBX breaks. */ + third_endpoint_fs[Endpoint_bmAttributes] = ENDPOINT_TYPE_BULK; + third_endpoint_hs[Endpoint_bmAttributes] = ENDPOINT_TYPE_BULK; + + /* Ignore error. */ + ux_test_add_action_to_main_list(create_error_match_action_from_error(error)); + + connect_host_and_slave(); + + if (global_media->fx_media_id != 0) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, global_media->fx_media_id); + test_control_return(1); + } + + /** For bulk in (Note: in order to even search for bulk in, bulk out must be valid, so the first should be bulk + out): **/ + + /* 1) An endpoint before bulk in must be OUT. Set them all to out so it fails. */ + + disconnect_host_and_slave(); + + first_endpoint_fs[Endpoint_bEndpointAddress] = 0x01; + first_endpoint_hs[Endpoint_bEndpointAddress] = 0x01; + first_endpoint_fs[Endpoint_bmAttributes] = ENDPOINT_TYPE_BULK; + first_endpoint_hs[Endpoint_bmAttributes] = ENDPOINT_TYPE_BULK; + + second_endpoint_fs[Endpoint_bEndpointAddress] = 0x02; + second_endpoint_hs[Endpoint_bEndpointAddress] = 0x02; + + third_endpoint_fs[Endpoint_bEndpointAddress] = 0x03; + third_endpoint_hs[Endpoint_bEndpointAddress] = 0x03; + + /* Ignore error. */ + ux_test_add_action_to_main_list(create_error_match_action_from_error(error)); + + connect_host_and_slave(); + + if (global_media->fx_media_id != 0) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, global_media->fx_media_id); + test_control_return(1); + } + + /* 2) An endpoint before bulk in must be IN and non-bulk. Set the second to IN and non-bulk. The rest must be OUT + so it fails. */ + + disconnect_host_and_slave(); + + second_endpoint_fs[Endpoint_bEndpointAddress] = 0x82; + second_endpoint_hs[Endpoint_bEndpointAddress] = 0x82; + second_endpoint_fs[Endpoint_bmAttributes] = ENDPOINT_TYPE_INTERRUPT; + second_endpoint_hs[Endpoint_bmAttributes] = ENDPOINT_TYPE_INTERRUPT; + second_endpoint_fs[Endpoint_bInterval] = 0x01; + second_endpoint_hs[Endpoint_bInterval] = 0x01; + + third_endpoint_fs[Endpoint_bEndpointAddress] = 0x03; + third_endpoint_hs[Endpoint_bEndpointAddress] = 0x03; + + /* Ignore error. */ + ux_test_add_action_to_main_list(create_error_match_action_from_error(error)); + + connect_host_and_slave(); + + if (global_media->fx_media_id != 0) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, global_media->fx_media_id); + test_control_return(1); + } + +#ifdef BUGFIX + /** For interrupt in: **/ + + /* 1) CBI but no interrupt endpoint */ + + disconnect_host_and_slave(); + + device_framework_full_speed[bInterfaceProtocol_POS] = UX_HOST_CLASS_STORAGE_PROTOCOL_CBI; + device_framework_high_speed[bInterfaceProtocol_POS] = UX_HOST_CLASS_STORAGE_PROTOCOL_CBI; + device_framework_full_speed[bInterfaceSubClass_POS] = UX_HOST_CLASS_STORAGE_SUBCLASS_UFI; + device_framework_high_speed[bInterfaceSubClass_POS] = UX_HOST_CLASS_STORAGE_SUBCLASS_UFI; + + first_endpoint_fs[Endpoint_bEndpointAddress] = 0x81; + first_endpoint_hs[Endpoint_bEndpointAddress] = 0x81; + first_endpoint_fs[Endpoint_bmAttributes] = 0x02; + first_endpoint_hs[Endpoint_bmAttributes] = 0x02; + + second_endpoint_fs[Endpoint_bEndpointAddress] = 0x01; + second_endpoint_hs[Endpoint_bEndpointAddress] = 0x01; + second_endpoint_fs[Endpoint_bmAttributes] = 0x02; + second_endpoint_hs[Endpoint_bmAttributes] = 0x02; + + third_endpoint_fs[Endpoint_bEndpointAddress] = 0x81; + third_endpoint_hs[Endpoint_bEndpointAddress] = 0x81; + third_endpoint_fs[Endpoint_bmAttributes] = 0x02; + third_endpoint_hs[Endpoint_bmAttributes] = 0x02; + + connect_host_and_slave(); + + if (global_media->fx_media_id != 0) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, global_media->fx_media_id); + test_control_return(1); + } +#endif + + /* reset_to_bo() resets the endpoint addresses, so we don't have to. */ +} + +#undef ENDPOINT_TYPE_BULK +#undef ENDPOINT_TYPE_INTERRUPT + +/* max_lun_get_test resources */ + +static VOID max_lun_get_test_action_func(UX_TEST_ACTION *action, VOID *_params) +{ + +UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *params = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *)_params; +UX_TRANSFER *transfer = params->parameter; + + + /* Host expects a length of 1. Set it to not 1. */ + transfer->ux_transfer_request_actual_length = 0xdeadbeef; +} + +static void max_lun_get_test() +{ + +UX_TEST_SETUP setup = { 0 }; +UX_TEST_ACTION actions[2] = { 0 }; + + + /* We still expect USBX to mount the LUN because 1) max_lun_get always returns UX_SUCCESS 2) when it fails, the + storage instance's max_lun count is 0 which means 1 LUN, so USBX continues as normal. + Also, the real world example of when this would happen is the device not being ready yet, so it stalls the + endpoint. */ + + stepinfo("max_lun_get_test\n"); + + stepinfo(" transfer_request fails\n"); + + disconnect_host_and_slave(); + + setup.ux_test_setup_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + setup.ux_test_setup_request = UX_HOST_CLASS_STORAGE_GET_MAX_LUN; + + actions[0].usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + actions[0].function = UX_HCD_TRANSFER_REQUEST; + actions[0].req_setup = &setup; + actions[0].req_action = UX_TEST_SETUP_MATCH_REQUEST; + actions[0].no_return = 0; + actions[0].status = UX_ERROR; + + ux_test_set_main_action_list_from_array(actions); + + connect_host_and_slave(); + + if (global_media->fx_media_id == 0) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, global_media->fx_media_id); + test_control_return(1); + } + + stepinfo(" invalid actual length\n"); + + disconnect_host_and_slave(); + + setup.ux_test_setup_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + setup.ux_test_setup_request = UX_HOST_CLASS_STORAGE_GET_MAX_LUN; + + actions[0].usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + actions[0].function = UX_HCD_TRANSFER_REQUEST; + actions[0].req_setup = &setup; + actions[0].req_action = UX_TEST_SETUP_MATCH_REQUEST; + actions[0].no_return = 0; + actions[0].action_func = max_lun_get_test_action_func; + actions[0].status = UX_SUCCESS; + + ux_test_set_main_action_list_from_array(actions); + + connect_host_and_slave(); + + if (global_media->fx_media_id == 0) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, global_media->fx_media_id); + test_control_return(1); + } +} + +/* media_capacity_get_test resources */ + +static void media_capacity_get_test() +{ + +UINT i; +UX_TEST_ERROR_CALLBACK_ERROR error = { UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HCD, UX_TRANSFER_STALLED }; +ULONG test_sector_size = 2*UX_HOST_CLASS_STORAGE_SECTOR_SIZE_FAT; +UX_TEST_ACTION actions[2] = { 0 }; + + + stepinfo("media_capacity_get_test\n"); + + /* How: We do this by overriding the device's media_status function to return an error. Also, this assumes that + media_capacity_get is the first BO transfer to the device. */ + stepinfo(" transport succeeds, error sense code, fails 10 times\n"); + + disconnect_host_and_slave(); + for (i = 0; i < UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RETRY; i++) + { + ux_test_add_action_to_main_list(create_data_match_action(global_enum_thread, global_cbw_data_media_capacity_get_sbc, sizeof(global_cbw_data_media_capacity_get_sbc))); + ux_test_add_action_to_main_list(create_device_media_status_fail_action()); + ux_test_add_action_to_main_list(create_error_match_action_from_error(global_transfer_stall_error)); + } + connect_host_and_slave(); + + if (ux_test_check_actions_empty() == UX_FALSE) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, global_media->fx_media_id); + test_control_return(1); + } + + stepinfo(" non-default sector size\n"); + + disconnect_host_and_slave(); + + /* Change the sector size. */ + global_sector_size = test_sector_size; + + /* USBX has a default sector size, therefore in order to test this, we change the sector size to the non-default. */ + global_persistent_slave_storage -> ux_slave_class_storage_lun[0].ux_slave_class_storage_media_block_length = test_sector_size; + + connect_host_and_slave(); + + /* Ensure media_capacity_get() received the correctomundo sector size. */ + if (global_storage -> ux_host_class_storage_sector_size != test_sector_size) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, global_storage -> ux_host_class_storage_sector_size); + test_control_return(1); + } + + basic_test(global_media, 1, " basic_test\n"); + + /* Set the sector size back to normal. */ + reset_to_bo(); + + stepinfo(" transport fails\n"); + + disconnect_host_and_slave(); + + UX_TEST_ACTION media_capacity_get_cbw_disconnect_actions[] = { + create_disconnect_on_transfer_data_match_action(global_enum_thread, global_cbw_data_media_capacity_get_sbc, sizeof(global_cbw_data_media_capacity_get_sbc)), + create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_TIMEOUT), + { 0 } + }; + ux_test_set_main_action_list_from_array(media_capacity_get_cbw_disconnect_actions); + UX_TEST_ASSERT(connect_host_and_slave() != UX_SUCCESS); +} + +/* media_characteristics_get_test resources */ + +static void media_characteristics_get_test() +{ + + stepinfo("media_characteristics_get_test\n"); + + stepinfo(" correct characteristics received\n"); + + disconnect_host_and_slave(); + global_persistent_slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_removable_flag = 0x00; + connect_host_and_slave(); + + if (global_storage->ux_host_class_storage_lun_removable_media_flags[0] != 0x00) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, global_media->fx_media_id); + test_control_return(1); + } + + basic_test(global_media, 1, " basic test\n"); + + /* Reset removable flag. */ + reset_to_bo(); + + stepinfo(" fail on transfer\n"); + + disconnect_host_and_slave(); + UX_TEST_ACTION media_characteristics_get_disconnect_actions[] = { + create_disconnect_on_transfer_data_match_action(global_enum_thread, global_cbw_data_media_characteristics_get_sbc, sizeof(global_cbw_data_media_characteristics_get_sbc)), + create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_TIMEOUT), + { 0 } + }; + ux_test_set_main_action_list_from_array(media_characteristics_get_disconnect_actions);; + UX_TEST_ASSERT(connect_host_and_slave() != UX_SUCCESS); +} + +/* ux_test_host_class_storage_media_read_test resources */ + +static void uhcsmrt_action_func(UX_TEST_ACTION *action, VOID *_params) +{ + +UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *params = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *)_params; +UX_TRANSFER *transfer = params->parameter; + + + /* Make it NOT correct. */ + global_storage -> ux_host_class_storage_data_phase_length = ~(global_storage -> ux_host_class_storage_data_phase_length); +} + +/* ux_host_class_storage_request_sense_test resources */ + +static void ux_host_class_storage_request_sense_test() +{ + +UINT status; +UX_TEST_ACTION actions[3] = { 0 }; + + + stepinfo("ux_host_class_storage_request_sense_test\n"); + + /* We accomplish this by forcing a REQUEST_SENSE command to fail via error in CSW. */ + stepinfo(" recursive REQUEST_SENSE command\n"); + + lock_out_storage_thread(); + + /* In order to get USBX to send the REQUEST_SENSE comand, a CSW must contain an error. Therefore, we need to error + CSWs. */ + actions[0] = create_csw_error_action(tx_thread_identify(), UX_HOST_CLASS_STORAGE_CSW_FAILED); + actions[1] = create_csw_error_action(tx_thread_identify(), UX_HOST_CLASS_STORAGE_CSW_FAILED); + ux_test_set_main_action_list_from_array(actions); + + /* This should fail because the transport itself fails, not just the CSW. */ + status = ux_test_host_class_storage_media_read(global_storage, 10, 1, global_buffer); + if (status == UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + lock_in_storage_thread(); +} + +/* ux_host_class_storage_start_stop_test resources */ + +static void uhcsst_action_func(UX_TEST_ACTION *action, VOID *_params) +{ + +UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *params = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *)_params; +UX_TRANSFER *transfer = params->parameter; +UX_HOST_CLASS_STORAGE *storage = get_internal_host_storage_instance(); + + + storage->ux_host_class_storage_sense_code = 0xff; +} + +static void ux_host_class_storage_start_stop_test() +{ + +UCHAR cbw_data_start_stop[] = { 0x55, 0x53, 0x42, 0x43, 0x43, 0x42, 0x53, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +UX_TEST_ACTION actions[51] = { 0 }; +UINT i; + + + /* The host sends the START_STOP command only to UFI devices during enumeration. */ + stepinfo("ux_host_class_storage_start_stop_test\n"); + + /* We do this by detecting the CBW and setting to sense code to error. */ + stepinfo(" 50 retries fail test\n"); + + disconnect_host_and_slave(); + + /* Set this to UFI. */ + switch_to_protocol(UX_HOST_CLASS_STORAGE_PROTOCOL_CBI); + + /* Match CBW and set the sense code to error. */ + actions[0].usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + actions[0].function = UX_HCD_TRANSFER_REQUEST; + actions[0].req_data = cbw_data_start_stop; + actions[0].req_actual_len = sizeof(cbw_data_start_stop); + actions[0].action_func = uhcsst_action_func; + actions[0].no_return = 1; + + /* Host will try to send a REQUEST_SENSE command to device. Make sure it contains an error. */ + for (i = 1; i < (ARRAY_COUNT(actions) - 1); i++) + { + actions[i] = actions[0]; + } + + ux_test_set_main_action_list_from_array(actions); + + connect_host_and_slave(); + + if (global_media->fx_media_id != 0) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } +} + +/* ux_host_class_storage_transport_test resources */ + +/* This tests transport, transport_bo, transport_cb, and transport_cbi. */ +static void ux_host_class_storage_transport_test() +{ + +UX_TEST_ERROR_CALLBACK_ERROR transfer_timeout_error = { UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_TIMEOUT }; + + + stepinfo("ux_host_class_storage_transport_test\n"); + + stepinfo(" CSW 2 timeouts\n"); + + DEVICE_MEDIA_READ_WRITE_TIMEOUT_DATA timeout_data; + timeout_data.transfer_request = &global_storage->ux_host_class_storage_bulk_in_endpoint->ux_endpoint_transfer_request; + timeout_data.num_timeouts = 2; + + UX_TEST_ACTION csw_multiple_retries_fails[] = { + create_device_media_write_block_action(&timeout_data), + { 0 } + }; + ux_test_set_main_action_list_from_array(csw_multiple_retries_fails); + + lock_out_storage_thread(); + UX_TEST_CHECK_NOT_SUCCESS(ux_test_host_class_storage_media_write(global_storage, 10, 1, global_buffer)); + receive_device_csw(); + lock_in_storage_thread(); + basic_test(global_media, 1, " basic test\n"); + + stepinfo(" CBW transfer fail\n"); + + /* Set action for making CBW transfer fail. */ + UX_TEST_ACTION cbw_disconnect_actions[] = { + create_cbw_disconnect_action(tx_thread_identify()), + { 0 } + }; + ux_test_set_main_action_list_from_array(cbw_disconnect_actions); + + lock_out_storage_thread(); + UX_TEST_CHECK_NOT_SUCCESS(ux_test_host_class_storage_media_write(global_storage, 0, 1, global_buffer)); + lock_in_storage_thread(); + connect_host_and_slave(); + +#if 0 /* USBX_54 */ + stepinfo(" CBW stalls\n"); + + actions[0] = create_cbw_stall_action(tx_thread_identify()); + ux_test_set_actions(actions); + + /* Do anything that triggers a CBW. */ + status = ux_test_media_write(global_storage, 0, 1, global_buffer, 0, UX_FALSE); + if (status == UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } +#endif + + /* Note: the device never sends a PHASE ERROR, since it's optional. Therefore, we do the next best thing. */ + stepinfo(" CSW status is Phase Error\n"); + + /* Set action for making CSW contain Phase Error. */ + UX_TEST_ACTION csw_phase_error[] = { + create_csw_error_action(tx_thread_identify(), UX_HOST_CLASS_STORAGE_CSW_PHASE_ERROR), + create_endpoint_reset_match_action(tx_thread_identify(), &global_setup_endpoint_reset_out2), + { 0 } + }; + ux_test_set_main_action_list_from_array(csw_phase_error); + + lock_out_storage_thread(); + UX_TEST_CHECK_SUCCESS(ux_test_host_class_storage_media_write(global_storage, 10, 1, global_buffer)); + lock_in_storage_thread(); + UX_TEST_ASSERT(ux_test_check_actions_empty()); + + stepinfo(" CSW transfer fail\n"); + + /* Set action for making CSW transfer fail. */ + UX_TEST_ACTION csw_disconnect_actions[] = { + create_csw_disconnect_action(tx_thread_identify()), + { 0 } + }; + ux_test_set_main_action_list_from_array(csw_disconnect_actions); + + lock_out_storage_thread(); + UX_TEST_CHECK_NOT_SUCCESS(ux_test_host_class_storage_media_write(global_storage, 10, 1, global_buffer)); + lock_in_storage_thread(); + connect_host_and_slave(); + + stepinfo(" CSW semaphore_get() fails due to disconnect\n"); + + UX_TEST_ACTION csw_semaphore_get_disconnect_actions[] = { + create_csw_match_action(tx_thread_identify()), + create_semaphore_get_disconnect_action(tx_thread_identify(), &global_storage->ux_host_class_storage_bulk_in_endpoint->ux_endpoint_transfer_request.ux_transfer_request_semaphore, UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT), + { 0 } + }; + ux_test_set_main_action_list_from_array(csw_semaphore_get_disconnect_actions); + + lock_out_storage_thread(); + UX_TEST_CHECK_NOT_SUCCESS(ux_test_host_class_storage_media_write(global_storage, 10, 1, global_buffer)); + lock_in_storage_thread(); + connect_host_and_slave(); +} + +/* thirteen_cases_test resources + These tests ensure the host acts conformant to the USB MSC BO spec regarding the thirteen cases specified in section + 6.7. */ + +static UX_TEST_ACTION create_match_unit_test_ready_cbw(TX_THREAD *thread) +{ + +UX_TEST_ACTION action = {0}; + + + /* Action for matching CBW of unit ready test. */ + action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + action.function = UX_HCD_TRANSFER_REQUEST; + action.req_data = global_cbw_data_unit_ready_test_sbc; + action.req_actual_len = sizeof(global_cbw_data_unit_ready_test_sbc); + action.no_return = 1; + action.thread_to_match = thread; + + return action; +} + +static UINT tcht_media_read_test_error_action_func_calls; +static UINT tcht_media_read_test_error_action_func(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + + if (!tcht_media_read_test_error_action_func_calls++) + { + + *media_status = (ULONG)-1; + return UX_ERROR; + } + else + return default_device_media_read(storage, lun, data_pointer, number_blocks, lba, media_status); +} + +static UINT tcht_media_write_test_error_action_func_calls; +static UINT tcht_media_write_test_error_action_func(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + + if (!tcht_media_write_test_error_action_func_calls++) + { + + *media_status = (ULONG)-1; + return UX_ERROR; + } + else + return default_device_media_write(storage, lun, data_pointer, number_blocks, lba, media_status); +} + +static void stall_while_receiving_csw_test() +{ + + /* Case: On a STALL condition receiving the CSW, then: + -The host shall clear the Bulk-In pipe. + -The host shall attempt to receive the CSW again. + + We "hardcode" it because there's no reason AFAIK to trigger this case. */ + stepinfo("stall_while_receiving_csw_test\n"); + + UX_TEST_ACTION actions[] = { + /* Action for matching CBW of unit ready test. */ + create_cbw_match_action(tx_thread_identify()), + /* Force the CSW to stall. */ + create_csw_stall_action(tx_thread_identify()), /* Not actually stalled on device side. */ + /* Match bulk-in endpoint reset. */ + create_endpoint_reset_match_action(tx_thread_identify(), &global_setup_endpoint_reset_in1), + /* Match CSW. */ + create_csw_match_action(tx_thread_identify()), + { 0 } + }; + + lock_out_storage_thread(); + + ux_test_set_expedient(UX_TRUE); + ux_test_set_main_action_list_from_array(actions); + UX_TEST_CHECK_SUCCESS(ux_test_host_class_storage_media_read(global_storage, 10, sizeof(global_buffer_2x_slave_buffer_size)/UX_HOST_CLASS_STORAGE_SECTOR_SIZE_FAT, global_buffer_2x_slave_buffer_size)); + ux_test_set_expedient(UX_FALSE); + + lock_in_storage_thread(); + + /* Ensure we "attempt to receive the CSW again" and "clear the Bulk-In pipe" */ + if (ux_test_check_actions_empty() != UX_TRUE) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } +} + +static void csw_contains_phase_error_test() +{ + + stepinfo("csw_contains_phase_error_test\n"); + + lock_out_storage_thread(); + + UX_TEST_ACTION actions[] = { + create_cbw_match_action(tx_thread_identify()), + create_csw_error_action(tx_thread_identify(), UX_HOST_CLASS_STORAGE_CSW_PHASE_ERROR), + create_mass_storage_reset_match_action(tx_thread_identify()), + create_request_sense_error_action(tx_thread_identify(), 0xff), + { 0 } + }; + ux_test_set_main_action_list_from_array(actions); + + UX_TEST_CHECK_SUCCESS(ux_test_host_class_storage_media_read(global_storage, 10, sizeof(global_buffer_2x_slave_buffer_size)/UX_HOST_CLASS_STORAGE_SECTOR_SIZE_FAT, global_buffer_2x_slave_buffer_size)); + + lock_in_storage_thread(); + + /* Ensure we "attempt to receive the CSW again" and "clear the Bulk-In pipe" */ + UX_TEST_ASSERT(ux_test_check_actions_empty()); +} + +static void thirteen_cases_4_5_test_host() +{ + +UINT status; +UX_TEST_ACTION actions[] = { + create_device_media_read_fail_action(), + create_error_match_action_from_error(ux_error_hcd_transfer_stalled), + create_endpoint_reset_match_action(tx_thread_identify(), &global_setup_endpoint_reset_in1), + { 0 } +}; + + + /* For case 4 and 5, the device should stall during data stage. This is what + we do during this test. */ + stepinfo("thirteen_cases_4_5_test_host\n"); + + lock_out_storage_thread(); + + ux_test_set_main_action_list_from_array(actions); + + /* Make sure it requires multiple transfers (large data size). */ + status = ux_test_host_class_storage_media_read(global_storage, 10, sizeof(global_buffer_2x_slave_buffer_size)/UX_HOST_CLASS_STORAGE_SECTOR_SIZE_FAT, global_buffer_2x_slave_buffer_size); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + lock_in_storage_thread(); + + if (global_media->fx_media_id == 0) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, global_media->fx_media_id); + test_control_return(1); + } + + /* Ensure we "clear the Bulk-In pipe." */ + if (ux_test_check_actions_empty() != UX_TRUE) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } +} + +static void thirteen_cases_9_11_test_host() +{ + +UINT status; +UINT num_transfers; +/* Note that we use the DEVICE's max buffer size because we need the device to process it (for example, if it's less than + the host's and we use the host's, then it would be the same as only sending one transfer). */ +ULONG write_sector_counts[] = { UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE/UX_HOST_CLASS_STORAGE_SECTOR_SIZE_FAT, UX_TEST_MULTIPLE_TRANSFERS_SECTOR_COUNT }; + +/* We don't expect any errors since the device doesn't stall until after we've sent all our data, we don't actually + detect the stall. Instead, we see that the CSW contains an error then clear the endpoint. */ +UX_TEST_ACTION one_transfer_actions[] = { + create_device_media_write_fail_action(), + create_endpoint_reset_match_action(tx_thread_identify(), &global_setup_endpoint_reset_out2), + { 0 } +}; + +/* This time, we will detect the stall in transport_bo.c. */ +UX_TEST_ACTION two_transfers_actions[] = { + create_device_media_write_fail_action(), + create_error_match_action_from_error(ux_error_hcd_transfer_stalled), + create_endpoint_reset_match_action(tx_thread_identify(), &global_setup_endpoint_reset_out2), + { 0 } +}; + + /* For these cases, the device should stall the bulk out during the data + phase. That is what we do during this test. + + We do this test twice for good measuer: one that requires one slave transfer, + and one that requires two slave transfers. */ + stepinfo("thirteen_cases_9_11_test_host\n"); + + for (num_transfers = 1; num_transfers < 3; num_transfers++) + { + + stepinfo(" num_transfers: %d\n", num_transfers); + + if (num_transfers == 1) + { + ux_test_set_main_action_list_from_array(one_transfer_actions); + } + else if (num_transfers == 2) + { + ux_test_set_main_action_list_from_array(two_transfers_actions); + } + + lock_out_storage_thread(); + + /* Make sure it requires multiple transfers (large data size). */ + status = ux_test_host_class_storage_media_write(global_storage, 10, write_sector_counts[num_transfers - 1], global_buffer_2x_slave_buffer_size); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + /* Ensure we "clear the Bulk-Out pipe." Note that we actually do it twice, once in transport_bo() and once in + transport(). See the note in transport() as to why this is indeed the case. */ + if (ux_test_check_actions_empty() != UX_TRUE) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + if (global_storage->ux_host_class_storage_bulk_out_endpoint->ux_endpoint_transfer_request.ux_transfer_request_semaphore.tx_semaphore_count != 0) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + lock_in_storage_thread(); + } +} + +/* get_no_device_memory_free_amount resources. */ + +static void get_no_device_free_memory_amount_action_func(UX_TEST_ACTION *action, VOID *_params) +{ + +UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *params = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *)_params; +ULONG *no_device_memory_free_amount = (ULONG *)action->user_data; + + + /* Log number of memory allocations right before storage class initialization. */ + *no_device_memory_free_amount = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available; +} + +/* device_not_ready_during_enumeration_test resources */ + +static void device_not_ready_during_enumeration_test() +{ + + stepinfo("device_not_ready_during_enumeration_test\n"); + + disconnect_host_and_slave(); + + UX_TEST_ACTION actions[] = { + /* This causes the UNIT READY TEST in _ux_host_class_storage_media_mount to fail. */ + create_test_unit_ready_match_action(global_enum_thread), + create_device_media_status_fail_action(), + /* These two causes the UNIT READY TEST to receive the UNIT_ATTENTION sense key, which will mount us! */ + create_csw_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_CSW_FAILED), + create_request_sense_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION), + { 0 } + }; + ux_test_set_main_action_list_from_array(actions); + + connect_host_and_slave(); + + /* Wait for storage thread to mount us. */ + while (!_storage_media_is_mounted()) + tx_thread_sleep(10); + + /* We should be successfully mounted. Run a basic test. */ + basic_test(global_media, 1, " basic test\n"); +} + +static void disconnect_during_storage_thread_unmounting_media_test() +{ + + stepinfo("disconnect_during_storage_thread_unmounting_media_test\n"); + + UX_TEST_ACTION not_ready_actions = { 0 }; + add_unit_ready_test_not_ready_actions(¬_ready_actions); + ux_test_add_action_to_user_list(¬_ready_actions, create_disconnect_on_thread_preemption_change(global_storage_thread, global_storage_thread, UX_HOST_CLASS_STORAGE_THREAD_PRIORITY_CLASS)); + ux_test_set_main_action_list_from_list(¬_ready_actions); + let_storage_thread_run(); +} + +#ifdef UX_TEST_RACE_CONDITION_TESTS_ON + +/* host_stack_simultaneous_control_transfer_test resources */ + +static void hssctt_thread2_entry(ULONG input) +{ + +UINT status; + + + /** This is Thread2 **/ + + /* ux_host_stack_interface_setting_select() with alternate setting 0. Should override Thread1's transfer. */ + status = ux_host_stack_interface_setting_select(global_host_device->ux_device_first_configuration->ux_configuration_first_interface); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n",__LINE__,(ULONG)status); + test_control_return(1); + } + + /* Resume Thread1. */ + status = ux_utility_semaphore_put(&global_test_semaphore); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } +} + +static void hssctt_action_func(UX_TEST_ACTION *action, VOID *_params) +{ + +UX_TEST_HCD_SIM_HOST_ENTRY_PARAMS *params = (UX_TEST_HCD_SIM_HOST_ENTRY_PARAMS *)_params; +UINT status; +UX_TEST_WORKER_WORK work; + + + work.function = hssctt_thread2_entry; + + /* Remember we are being called from ux_host_stack_interface_set.c */ + + /* Run Thread2 */ + ux_test_worker_add_work(&work); + + /* Wait for Thread2 to finish. */ + status = ux_utility_semaphore_get(&global_test_semaphore, TX_WAIT_FOREVER); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } +} + +static void host_stack_simultaneous_control_transfers_cause_override_test() +{ + +UINT status; +UX_INTERFACE *interface_alternate_setting1; +UX_TRANSFER *transfer_request; +UCHAR buffer; + + + /* Proof of concept for USBX_77 */ + + /* Here is a REALISTIC example of what could POSSIBLY happen: + + -Background storage thread does a UNIT_READY_TEST. + -It fails on the device side, so device stalls endpoint. + -Host just sees that it failed and tries to reset the device (via MSC command on _control endpoint)). + -After setting up transfer request but _before_ calling ux_host_stack_transfer_request, storage thread gets + preempted by ThreadA. + -ThreadA decides it's time to select another interface setting or change the configuration (via + _control endpoint_). + -ThreadA _overrides_ storage thread's transfer request. + -Once storage thread runs again, it wlil send the same request as ThreadA. + + Not only that, but the reverse could happen: storage thread overrides ThreadA's transfer! + + See? this test isn't a waste of time! */ + + stepinfo("host_stack_simultaneous_control_transfer_test\n"); + + UX_TEST_ACTION actions[2] = { 0 }; + actions[0]._usbx_function = UX_TEST_HOST_STACK_INTERFACE_SET; + actions[0].bInterfaceNumber = 0; + actions[0].bAlternateSetting = 1; + actions[0].action_func = hssctt_action_func; + + /** This is Thread1. **/ + + lock_out_storage_thread(); + + /* The device stack calls the class to handle SET_INTERFACE requests. Problem is that device classes don't actually + support it and throw an error. In case this is a bug, I've documented it as BUG_ID_48. */ + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_FUNCTION_NOT_SUPPORTED)); + + /* Set action so that right before transfer_request(), we get preempted by Thread2. */ + ux_test_set_main_action_list_from_array(actions); + + interface_alternate_setting1 = global_storage->ux_host_class_storage_interface->ux_interface_next_interface; + + /* Call ux_host_stack_interface_setting_select() with alternate setting 1. Should be the interface right after the + current one. */ + /* When we resume, our transfer should've been overridden. */ + status = ux_host_stack_interface_setting_select(interface_alternate_setting1); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n",__LINE__,(ULONG)status); + test_control_return(1); + } + + /* Get the current alternate setting from the device (there's no API for this, we'll have to send the transfer + manually). */ + transfer_request = &global_host_device->ux_device_control_endpoint.ux_endpoint_transfer_request; + transfer_request -> ux_transfer_request_data_pointer = &buffer; + transfer_request -> ux_transfer_request_requested_length = 1; + transfer_request -> ux_transfer_request_function = UX_GET_INTERFACE; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_index = 0; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n",__LINE__,(ULONG)status); + test_control_return(1); + } + + if (buffer != 1) + { + + printf("Error on line %d, error code: 0x%lx\n",__LINE__,(ULONG)status); + test_control_return(1); + } + + lock_in_storage_thread(); +} + +/* host_stack_simultaneous_control_transfers_cause_extra_sem_count_test resources */ + +static void hssctcesmt_do_configuration_reset_function(ULONG input) +{ + +UINT status; + + + /* We just need to do A control transfer, doesn't matter which one. */ + status = ux_host_stack_device_configuration_reset(global_host_device); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } +} + +static void hssctcesmt_reactivate_hcd_timer(ULONG input) +{ + +UINT status; +UX_HCD_SIM_HOST *hcd_sim_host = global_hcd -> ux_hcd_controller_hardware; + + + /* Reactivate HCD timer. */ + status = tx_timer_activate(&hcd_sim_host -> ux_hcd_sim_host_timer); + if (status != TX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } +} + +static void host_stack_simultaneous_control_transfers_cause_extra_sem_count_test() +{ + +UINT status; +UX_TEST_WORKER_WORK work_transfer = { 0 }; +UX_HCD_SIM_HOST *hcd_sim_host = global_hcd -> ux_hcd_controller_hardware; + + + /* Proof of concept for USBX_78. */ + + stepinfo(" simulataneous control transfers test\n"); + + work_transfer.function = hssctcesmt_do_configuration_reset_function; + + /* Deactivate HCD timer. No transfers are processed during this time. */ + status = tx_timer_deactivate(&hcd_sim_host -> ux_hcd_sim_host_timer); + if (status != TX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + /* Start our timer. */ + status = tx_timer_create(&global_timer, "timer", hssctcesmt_reactivate_hcd_timer, 0, 100, 0, TX_AUTO_ACTIVATE); + if (status != TX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + /* Place work for doing transfer at the same we are in worker thread. */ + ux_test_worker_add_work(&work_transfer); + + /* Do our control transfer (remember that this is blocking). */ + hssctcesmt_do_configuration_reset_function(0); + + /* Our timer should reactivate HCD timer. */ + + /* If there are no bugs, the device protection semaphore's count is 1 (but with bugs, it should be 2). */ + if (global_host_device->ux_device_protection_semaphore.tx_semaphore_count != 1) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + status = tx_timer_delete(&global_timer); + if (status != TX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } +} +#endif + +/* synchronize_cache_test resources. */ + +/* Opcodes. */ +#define UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE 0x35 + +/* Define Storage Class read format command constants. */ +#define UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_OPERATION 0 +#define UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_FLAGS 1 +#define UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_LBA 2 + +#define UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_NUMBER_OF_BLOCKS 7 +#define UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_COMMAND_LENGTH_SBC 10 + +#define UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_FLAGS_IMMED 0x02 + +static void synchronize_cache_test() +{ + +UCHAR *cbw; +UINT number_of_blocks; +UINT i; + + + stepinfo("synchronize cache test\n"); + + /* For this test, the device will reply with an error in the CSW. This will + cause us to send a REQUEST SENSE. We ensure the REQUEST SENSE is valid. */ + stepinfo(" synchronize cache test - callback NULL\n"); + + /* Set callback to NULL. */ + global_slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_flush = 0; + + number_of_blocks = 0xffff; + + /* Initialize the CBW for this command. */ + _ux_host_class_storage_cbw_initialize(global_storage, 0, 0, UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_COMMAND_LENGTH_SBC); + + /* Prepare the SYNCHRONIZE CACHE command block. */ + cbw = (UCHAR *) global_storage -> ux_host_class_storage_cbw; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_OPERATION) = UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE; + _ux_utility_long_put_big_endian((cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_LBA), 0); + _ux_utility_short_put_big_endian((cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_NUMBER_OF_BLOCKS), number_of_blocks); + + UX_TEST_CHECK_SUCCESS(_ux_host_class_storage_transport(global_storage, UX_NULL)); + UX_TEST_ASSERT(global_storage->ux_host_class_storage_cbw[UX_HOST_CLASS_STORAGE_CSW_STATUS] == UX_SUCCESS); + UX_TEST_ASSERT(ux_test_check_actions_empty()); + + /* Restore callback. */ + global_slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_flush = default_device_media_flush; + + stepinfo(" synchronize cache test - different LBAs and number of blocks\n"); + + /* Try with different blocks and LBAs. */ + UINT lbas[] = {0, 1, 2, 3, 4, 5}; + USHORT number_blocks[] = {0xffff, 10, 9, 8, 7, 6}; + for (i = 0; i < ARRAY_COUNT(lbas); i++) + { + + stepinfo(" synchronize cache test - different LBAs and number of blocks - %d\n", i); + + /* Initialize the CBW for this command. */ + _ux_host_class_storage_cbw_initialize(global_storage, 0, 0, UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_COMMAND_LENGTH_SBC); + + /* Prepare the SYNCHRONIZE CACHE command block. */ + cbw = (UCHAR *) global_storage -> ux_host_class_storage_cbw; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_OPERATION) = UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE; + _ux_utility_long_put_big_endian((cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_LBA), lbas[i]); + _ux_utility_short_put_big_endian((cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_NUMBER_OF_BLOCKS), number_blocks[i]); + + /* Action for matching media flush to make sure device receives it. */ + UX_TEST_ACTION action = { 0 }; + action.usbx_function = UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_FLUSH; + action.lun = 0; + action.lba = lbas[i]; + action.number_blocks = number_blocks[i]; + ux_test_add_action_to_main_list(action); + + UX_TEST_CHECK_SUCCESS(_ux_host_class_storage_transport(global_storage, UX_NULL)); + UX_TEST_ASSERT(global_storage->ux_host_class_storage_cbw[UX_HOST_CLASS_STORAGE_CSW_STATUS] == UX_SUCCESS); + UX_TEST_ASSERT(ux_test_check_actions_empty()); + } + + stepinfo(" synchronize cache test - immediate bit set\n"); + + number_of_blocks = 0xffff; + + /* Initialize the CBW for this command. */ + _ux_host_class_storage_cbw_initialize(global_storage, 0, 0, UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_COMMAND_LENGTH_SBC); + + /* Prepare the SYNCHRONIZE CACHE command block. */ + cbw = (UCHAR *) global_storage -> ux_host_class_storage_cbw; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_OPERATION) = UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE; + _ux_utility_long_put_big_endian((cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_LBA), 0); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_FLAGS) |= UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_FLAGS_IMMED; + _ux_utility_short_put_big_endian((cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_NUMBER_OF_BLOCKS), number_of_blocks); + + /* Action for matching media flush to make sure device receives it. */ + UX_TEST_ACTION action_immediate_bit_set = { 0 }; + action_immediate_bit_set.usbx_function = UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_FLUSH; + action_immediate_bit_set.lun = 0; + action_immediate_bit_set.lba = 0; + action_immediate_bit_set.number_blocks = number_of_blocks; + ux_test_add_action_to_main_list(action_immediate_bit_set); + + UX_TEST_CHECK_SUCCESS(_ux_host_class_storage_transport(global_storage, UX_NULL)); + UX_TEST_ASSERT(global_storage->ux_host_class_storage_cbw[UX_HOST_CLASS_STORAGE_CSW_STATUS] == UX_SUCCESS); + UX_TEST_ASSERT(ux_test_check_actions_empty()); + + basic_test(global_media, 1, " running basic test\n"); +} + +/** This tests the case where the media is unremovable. **/ + +static void unremovable_media_test() +{ + + stepinfo("unremovable_media_test\n"); + + ux_test_disconnect_slave_and_host_wait_for_enum_completion(); + + /* Change the device's removable media flag to unremovable. */ + global_persistent_slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_removable_flag = 0x00; + + /* Now connect. */ + ux_test_connect_slave_and_host_wait_for_enum_completion(); + + /* Wait for storage thread to run. */ + tx_thread_sleep(2*UX_HOST_CLASS_STORAGE_THREAD_SLEEP_TIME); +} + +/* transfer_timeout_test resources */ + +static TX_THREAD ttt_asynchronous_transfer_thread; +static UCHAR ttt_asynchronous_transfer_thread_stack[4096]; + +static void my_completion_function(UX_TRANSFER *transfer_request) +{ + + /* transfer_request_abort() will call this. */ + UX_TEST_ASSERT(transfer_request->ux_transfer_request_completion_code == UX_TRANSFER_STATUS_ABORT); +} + +static VOID ttt_asynchronous_transfer_thread_entry(ULONG input) +{ + +UX_TRANSFER *transfer_request; + + + UX_THREAD_EXTENSION_PTR_GET(transfer_request, UX_TRANSFER, input); + + /* Make sure the transfer never completes. */ + ux_test_add_action_to_main_list(create_timeout_on_transfer_action(tx_thread_identify())); + + transfer_request->ux_transfer_request_completion_function = my_completion_function; + transfer_request->ux_transfer_request_data_pointer = global_buffer; + transfer_request->ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CBW_LENGTH; + UX_TEST_CHECK_SUCCESS(ux_host_stack_transfer_request(transfer_request)); + UX_TEST_ASSERT(ux_test_check_actions_empty()); + + tx_thread_suspend(tx_thread_identify()); +} + +static void transfer_timeout_test() +{ + +UCHAR original_expedient_value; +UX_TRANSFER *transfer_request = &global_storage->ux_host_class_storage_bulk_in_endpoint->ux_endpoint_transfer_request; + + + /* This is to test USBX-115. In summary, the bug is that if the thread timeouts + waiting on a semaphore, then it usually calls transfer_abort(), but abort() + does a semaphore_put() so there is extra count. */ + stepinfo("transfer_timeout_test\n"); + + /* Synchronous means no completion function is set. */ + stepinfo(" transfer_timeout_test - synchronous\n"); + + /* Since we return from the transfer immediately, we need to turn on + expedient mode. */ + ux_test_turn_on_expedient(&original_expedient_value); + + /* Have the transfer timeout. */ + ux_test_add_action_to_main_list(create_timeout_on_cbw_action(tx_thread_identify())); + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_TIMEOUT)); + + /* Do a transfer - the first transfer should be a CBW. */ + do_any_write(); + UX_TEST_ASSERT(ux_test_check_actions_empty()); + + /* Check the bulk-out's transfer semaphore count. */ + UX_TEST_ASSERT(global_storage->ux_host_class_storage_bulk_out_endpoint->ux_endpoint_transfer_request.ux_transfer_request_semaphore.tx_semaphore_count == 0); + + /* Asynchronous means a completion function is set. */ + stepinfo(" transfer_timeout_test - asynchronous\n"); + + /* We use the bulk out endpoint cause we have no others to use. */ + lock_out_storage_thread(); + + UX_TEST_CHECK_SUCCESS(tx_thread_create(&ttt_asynchronous_transfer_thread, "ttt_asynchronous_transfer_thread", + ttt_asynchronous_transfer_thread_entry, (ULONG)(ALIGN_TYPE)transfer_request, + ttt_asynchronous_transfer_thread_stack, sizeof(ttt_asynchronous_transfer_thread_stack), + 20, 20, 10, TX_DONT_START)); + UX_THREAD_EXTENSION_PTR_SET(&ttt_asynchronous_transfer_thread, transfer_request); + UX_TEST_CHECK_SUCCESS(tx_thread_resume(&ttt_asynchronous_transfer_thread)); + + /* Wait for thread to do transfer. */ + int thread_state; + do + { + + UX_TEST_CHECK_SUCCESS(tx_thread_info_get(&ttt_asynchronous_transfer_thread, UX_NULL, &thread_state, UX_NULL, UX_NULL, UX_NULL, UX_NULL, UX_NULL, UX_NULL)); + } while(thread_state != TX_SUSPENDED); + + /* Now abort transfer. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_transfer_request_abort(transfer_request)); + + /* Make sure the semaphore wasn't put(). */ + UX_TEST_ASSERT(transfer_request->ux_transfer_request_semaphore.tx_semaphore_count == 0); + + UX_TEST_CHECK_SUCCESS(tx_thread_terminate(&ttt_asynchronous_transfer_thread)); + UX_TEST_CHECK_SUCCESS(tx_thread_delete(&ttt_asynchronous_transfer_thread)); + + lock_in_storage_thread(); + + ux_test_set_expedient(original_expedient_value); +} + +static void ux_test_thread_host_simulation_entry(ULONG arg) +{ + +UCHAR original_expedient_value; +UINT status; +ULONG error_count = 0; +UINT i; +void(*tests[])() = +{ + + transfer_timeout_test, + unremovable_media_test, + synchronize_cache_test, + fx_media_read_test, + + thirteen_cases_4_5_test_host, + thirteen_cases_9_11_test_host, + stall_while_receiving_csw_test, + csw_contains_phase_error_test, + basic_test_with_globals, + test_unit_ready_test, +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + first_sector_non_boot_test, +#endif + abort_media_test, + flush_media_test, + media_characteristics_get_test, + storage_endpoints_get_test, + system_host_change_function_test, +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + direct_calls_test, + first_sector_different_signatures_test, +#endif + close_media_test, + ux_host_class_storage_request_sense_test, + transport_failures_cause_device_reset_test, + entry_command_test, + media_capacity_get_test, + +#ifdef UX_TEST_RACE_CONDITION_TESTS_ON + disconnect_during_storage_thread_unmounting_media_test, +#endif +}; + + + ux_test_turn_off_expedient(&original_expedient_value); + + /* Format the ram drive. */ + status = fx_media_format(&global_ram_disk, _fx_ram_driver, global_ram_disk_memory, global_ram_disk_working_buffer, global_sector_size, "RAM DISK", 2, UX_TEST_NUM_DIRECTORY_ENTRIES, 0, UX_RAM_DISK_SIZE/global_sector_size, global_sector_size, 4, 1, 1); + if (status != FX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + /* Open the ram_disk. */ + status = fx_media_open(&global_ram_disk, "RAM DISK", _fx_ram_driver, global_ram_disk_memory, global_ram_disk_working_buffer, global_sector_size); + if (status != FX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + UX_TEST_ASSERT(wait_for_enum_completion_and_get_global_storage_values() == UX_SUCCESS); + + /* Ensure slave activate callback was invoked. */ + if (global_slave_storage == UX_NULL) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + /* Get basic memory amount. */ + disconnect_host_and_slave(); + global_memory_test_no_device_memory_free_amount = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + connect_host_and_slave(); + + /* With basic memory amount, now do basic memory test. */ + disconnect_host_and_slave(); + connect_host_and_slave(); + + for (i = 0; i < ARRAY_COUNT(tests); i++) + { + + tests[i](); + + ux_test_free_user_list_actions(); + + if (/* Left over actions? */ + ux_test_check_actions_empty() == UX_FALSE || + /* Invalid semaphore? */ + global_test_semaphore.tx_semaphore_count != 0 || + global_test_semaphore.tx_semaphore_suspended_count != 0) + { + + /* Error! */ + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + /* Reset for next test. */ + reset_to_bo(); + } + + /* The storage thread runs every two seconds. Make sure it runs at least once so the device reset will occurr. */ + ux_utility_delay_ms(UX_TEST_SLEEP_STORAGE_THREAD_RUN_ONCE); + + /* Disconnect device and host. */ + stepinfo("Disconnect test\n"); + + disconnect_host_and_slave(); + + /* Let enum thread run. */ + tx_thread_sleep(50); + + /* Ensure system change callback was invoked. */ + if (global_storage_change_function != UX_NULL) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + /* Ensure slave deactivate callback was invoked. */ + if (global_slave_storage != UX_NULL) + { + + printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status); + test_control_return(1); + } + + /* Start cleaning up. */ + stepinfo("clean up\n"); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_entry); + + /* Deinitialize the device side of usbx. */ + _ux_device_stack_uninitialize(); + + /* And finally the usbx system resources. */ + _ux_system_uninitialize(); + + ux_test_set_expedient(original_expedient_value); + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + + +static UINT default_device_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_STATUS_PARAMS params = { storage, lun, media_id, media_status }; +UX_TEST_ACTION action; + + + action = ux_test_action_handler(UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_STATUS, ¶ms); + if (action.matched) + { + if (action.action_func) + { + action.action_func(&action, ¶ms); + } + + if (!action.no_return) + { + return action.status; + } + } + else + { + *media_status = 0; + } + + /* The ATA drive never fails. This is just for demo only !!!! */ + return(UX_SUCCESS); +} + +static UINT default_device_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + +UINT status; +UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ_WRITE_FLUSH_PARAMS params = { storage, lun, data_pointer, number_blocks, lba, media_status }; +UX_TEST_ACTION action; + + + action = ux_test_action_handler(UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ, ¶ms); + if (action.matched && !action.do_after) + { + if (action.action_func) + { + action.action_func(&action, ¶ms); + } + + if (!action.no_return) + { + return action.status; + } + } + + if (lba == 0) + { + + global_ram_disk.fx_media_driver_logical_sector = 0; + global_ram_disk.fx_media_driver_sectors = 1; + global_ram_disk.fx_media_driver_request = FX_DRIVER_BOOT_READ; + global_ram_disk.fx_media_driver_buffer = data_pointer; + _fx_ram_driver(&global_ram_disk); + *(data_pointer) = 0xeb; + *(data_pointer+1) = 0x3c; + *(data_pointer+2) = 0x90; + *(data_pointer+21) = 0xF8; + + *(data_pointer+24) = 0x01; + *(data_pointer+26) = 0x10; + *(data_pointer+28) = 0x01; + + *(data_pointer+510) = 0x55; + *(data_pointer+511) = 0xaa; + ux_utility_memory_copy(data_pointer+0x36, "FAT12", 5); + + + status = global_ram_disk.fx_media_driver_status; + UX_TEST_CHECK_SUCCESS(status); + } + else + { + + while (number_blocks--) + { + status = fx_media_read(&global_ram_disk, lba, data_pointer); + UX_TEST_CHECK_SUCCESS(status); + data_pointer += global_sector_size; + lba++; + } + } + + if (action.matched && action.do_after) + { + if (action.action_func) + { + action.action_func(&action, ¶ms); + } + + if (!action.no_return) + { + return action.status; + } + } + + return(status); +} + +static UINT default_device_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + +UINT status; +UX_TEST_ACTION action; +UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ_WRITE_FLUSH_PARAMS params = { storage, lun, data_pointer, number_blocks, lba, media_status }; + + + action = ux_test_action_handler(UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_WRITE, ¶ms); + if (action.matched && !action.do_after) + { + if (action.action_func) + { + action.action_func(&action, ¶ms); + } + + if (!action.no_return) + { + return action.status; + } + } + + if(lba == 0) + { + + global_ram_disk.fx_media_driver_logical_sector = 0; + global_ram_disk.fx_media_driver_sectors = 1; + global_ram_disk.fx_media_driver_request = FX_DRIVER_BOOT_WRITE; + global_ram_disk.fx_media_driver_buffer = data_pointer; + _fx_ram_driver(&global_ram_disk); + + status = global_ram_disk.fx_media_driver_status; + + } + else + { + + while(number_blocks--) + { + + status = fx_media_write(&global_ram_disk,lba,data_pointer); + data_pointer+=global_sector_size; + lba++; + } + return(status); + } + + if (action.matched && action.do_after) + { + if (action.action_func) + { + action.action_func(&action, ¶ms); + } + + if (!action.no_return) + { + return action.status; + } + } + + return(status); +} + + +static UINT default_device_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + +UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ_WRITE_FLUSH_PARAMS params = { storage, lun, UX_NULL, number_blocks, lba, media_status }; + + + ux_test_action_handler(UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_FLUSH, ¶ms); + + return(UX_SUCCESS); +} diff --git a/test/regression/usbx_test_USBX_141_keyboard_layout.c b/test/regression/usbx_test_USBX_141_keyboard_layout.c new file mode 100644 index 00000000..f2f36aa9 --- /dev/null +++ b/test/regression/usbx_test_USBX_141_keyboard_layout.c @@ -0,0 +1,614 @@ +/* This test concentrates on the ux_host_class_hid_keyboard_key_get API. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_host_class_hid.h" +#include "ux_host_class_hid_keyboard.h" +#include "ux_device_class_hid.h" +#include "ux_device_stack.h" + +extern UCHAR ux_host_class_hid_keyboard_regular_array[]; + +static UCHAR ux_host_class_hid_keyboard_shift_array_jp_0_9[] = +{ + 0,0,0,0, + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z', + '!','"','#','$','%','&','\'','(',')', 0, /* JP key decode in this part. */ + 0x0d,0x1b,0x08,0x07,0x20,'_','+','{','}', + '|','~',':','"','~','<','>','?',0xf0, + 0xbb,0xbc,0xbd,0xbe,0xbf,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6, + 0x00,0xf1,0x00,0xd2,0xc7,0xc9,0xd3,0xcf,0xd1,0xcd,0xcd,0xd0,0xc8,0xf2, + '/','*','-','+', + 0x0d,'1','2','3','4','5','6','7','8','9','0','.','\\',0x00,0x00,'=', + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +extern UCHAR ux_host_class_hid_keyboard_numlock_on_array[]; +extern UCHAR ux_host_class_hid_keyboard_numlock_off_array[]; + +static UX_HOST_CLASS_HID_KEYBOARD_LAYOUT test_layout_jp_0_9 = +{ + .ux_host_class_hid_keyboard_layout_regular_array = ux_host_class_hid_keyboard_regular_array, + .ux_host_class_hid_keyboard_layout_shift_array = ux_host_class_hid_keyboard_shift_array_jp_0_9, + .ux_host_class_hid_keyboard_layout_numlock_on_array = ux_host_class_hid_keyboard_numlock_on_array, + .ux_host_class_hid_keyboard_layout_numlock_off_array = ux_host_class_hid_keyboard_numlock_off_array, + .ux_host_class_hid_keyboard_layout_keys_upper_range = UX_HID_KEYBOARD_KEYS_UPPER_RANGE, + .ux_host_class_hid_keyboard_layout_letters_lower_range = UX_HID_KEYBOARD_KEY_LETTER_A, + .ux_host_class_hid_keyboard_layout_letters_upper_range = UX_HID_KEYBOARD_KEY_LETTER_Z, + .ux_host_class_hid_keyboard_layout_keypad_lower_range = UX_HID_KEYBOARD_KEYS_KEYPAD_LOWER_RANGE, + .ux_host_class_hid_keyboard_layout_keypad_upper_range = UX_HID_KEYBOARD_KEYS_KEYPAD_UPPER_RANGE, +}; + +/* Define constants. */ +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_MEMORY_SIZE (64*1024) + +/* Define local/extern function prototypes. */ +static void demo_thread_entry(ULONG); +static UINT demo_thread_hid_callback(UX_SLAVE_CLASS_HID *, UX_SLAVE_CLASS_HID_EVENT *); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); +static void tx_demo_thread_slave_simulation_entry(ULONG); + + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static ULONG error_counter; +static TX_THREAD demo_thread; +static UX_HOST_CLASS *class_driver; +static ULONG class_driver_index; +static UX_HOST_CLASS_HID *hid; +static UX_HOST_CLASS_HID_CLIENT *hid_client; +static UX_HOST_CLASS_HID_KEYBOARD *keyboard; +static UINT status; + +static UX_SLAVE_CLASS_HID_PARAMETER hid_parameter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 52 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00, + 0x00, + + /* HID descriptor */ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, 0x3f, + 0x00, + + /* Endpoint descriptor (Interrupt) */ + 0x07, 0x05, 0x82, 0x03, 0x08, 0x00, 0x08 + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 62 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* 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, 0x3f, + 0x00, + + /* 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 + }; + +#define HID_KEYBOARD_REPORT_LENGTH 63 +static UCHAR hid_keyboard_report[HID_KEYBOARD_REPORT_LENGTH] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; + + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* @BUG_FIX_PENDING: ux_dcd_sim_slave_function.c doesn't support transfer aborts, which happen during device unregistration of a class. */ + if (error_code != UX_FUNCTION_NOT_SUPPORTED) + { + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } +} + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + switch(a) + { + + case UX_HID_CLIENT_INSERTION: + hid_client = (UX_HOST_CLASS_HID_CLIENT *)c; + keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)hid_client -> ux_host_class_hid_client_local_instance; + break; + + case UX_HID_CLIENT_REMOVAL: + if ((VOID *)hid_client == c) + { + keyboard = UX_NULL; + hid_client = UX_NULL; + } + break; + + default: + break; + } + return 0; +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_test_USBX_141_keyboard_layout_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + /* Inform user. */ + printf("Running USBX-141 HID Keyboard Decode Layout 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_system_host_change_function); + 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\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 on line %d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the hid class parameters for a keyboard. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_keyboard_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_KEYBOARD_REPORT_LENGTH; + hid_parameter.ux_device_class_hid_parameter_callback = 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); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_DONT_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT demo_class_hid_get(void) +{ + +UINT status; +UX_HOST_CLASS *class; + + /* Find the main HID container */ + status = ux_host_stack_class_get(_ux_system_host_class_hid_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* We get the first instance of the hid device */ + do + { + + status = ux_host_stack_class_instance_get(class, 0, (void **) &hid); + tx_thread_sleep(10); + } while (status != UX_SUCCESS); + + /* We still need to wait for the hid status to be live */ + while (hid -> ux_host_class_hid_state != UX_HOST_CLASS_INSTANCE_LIVE) + tx_thread_sleep(10); + + return(UX_SUCCESS); +} + +static UINT _wait_key(UX_HOST_CLASS_HID_KEYBOARD *keyboard, ULONG *keyboard_key, ULONG *keyboard_state) +{ + +UINT i; + + + for(i = 0; i < 50; i ++) + { + if (ux_host_class_hid_keyboard_key_get(keyboard, keyboard_key, keyboard_state) == UX_SUCCESS) + { + return UX_SUCCESS; + } + _ux_utility_delay_ms(1); + } + return UX_ERROR; +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +#define N_TEST 3 +#define N_KEY 4 + +UINT status; +ULONG keyboard_key; +ULONG keyboard_state; +UINT i, j; +UCHAR decode_disable[N_TEST] = {UX_FALSE, UX_FALSE, UX_TRUE}; +UX_HOST_CLASS_HID_KEYBOARD_LAYOUT *layouts[N_TEST] = {&test_layout_jp_0_9, UX_NULL, &test_layout_jp_0_9}; +UCHAR expected_keys[N_TEST][N_KEY] = { + /* 4 (a) + * SHIFT 4 (A) + * 31 (2) + * SHIFT 31 (@) (") + */ + {'a', 'A', '2', '"'}, + {'a', 'A', '2', '@'}, + { 4 , 4 , 31, 31} +}; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + /* HID Keyboard basic test error. */ + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Check if the instance of the keyboard is live */ + while (hid_client == UX_NULL && keyboard == UX_NULL) + tx_thread_sleep(10); + + for (i = 0; i < N_TEST; i ++) + { + /* Set up decode & layout. */ + status = ux_host_class_hid_keyboard_ioctl(keyboard, + UX_HID_KEYBOARD_IOCTL_SET_LAYOUT, (VOID *)layouts[i]); + status |= ux_host_class_hid_keyboard_ioctl(keyboard, + decode_disable[i] ? UX_HID_KEYBOARD_IOCTL_DISABLE_KEYS_DECODE : + UX_HID_KEYBOARD_IOCTL_ENABLE_KEYS_DECODE, + UX_NULL); + + /* Enable device to send keys. */ + ux_utility_thread_resume(&tx_demo_thread_slave_simulation); + + /* Wait keys. */ + for (j = 0; j < N_KEY; j ++) + { + status = _wait_key(keyboard, &keyboard_key, &keyboard_state); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d.%d: code 0x%x\n", __LINE__, i, j, status); + test_control_return(1); + } + if ((UCHAR)keyboard_key != expected_keys[i][j]) + { + printf("ERROR #%d.%d.%d: key 0x%x (%c) <> 0x%x (%c)\n", __LINE__, i, j, + (UCHAR)keyboard_key, (UCHAR)keyboard_key, + expected_keys[i][j], expected_keys[i][j]); + test_control_return(1); + } + printf("state: 0x%4lx, key: 0x%2lx (%c)\n", keyboard_state, keyboard_key, (char)keyboard_key); + } + } + + /* 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); +} + +static void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + +UX_SLAVE_DEVICE *device; +UX_SLAVE_INTERFACE *interface; +UX_SLAVE_CLASS_HID *hid; +UX_SLAVE_CLASS_HID_EVENT hid_event; +UCHAR modifiers[4]; +UCHAR keys[4]; +UINT i; + + /* Get the pointer to the device. */ + device = &_ux_system_slave -> ux_system_slave_device; + + /* Set the keys. */ + /* 4 (a) + * SHIFT 4 (A) + * 31 (2) + * SHIFT 31 (@) (") + */ + modifiers[0] = 0; + keys[0] = 4; /* a */ + modifiers[1] = 1u << 1; + keys[1] = 4; /* A */ + modifiers[2] = 0; + keys[2] = 31; /* 2 */ + modifiers[3] = 1u << 1; + keys[3] = 31; /* @/" */ + + /* reset the HID event structure. */ + ux_utility_memory_set(&hid_event, 0, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + + while(1) + { + /* Is the device configured ? */ + if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED) + { + + /* Then wait. */ + ux_utility_delay_ms(5); + continue; + } + + /* Get the interface. We use the first interface, this is a simple device. */ + interface = device -> ux_slave_device_first_interface; + + /* Form that interface, derive the HID owner. */ + hid = interface -> ux_slave_interface_class_instance; + + /* Send keys. */ + for (i = 0; i < sizeof(keys); i ++) + { + + /* Then insert a key into the keyboard event. Length is fixed to 8. */ + hid_event.ux_device_class_hid_event_length = 8; + + /* First byte is a modifier byte. */ + hid_event.ux_device_class_hid_event_buffer[0] = modifiers[i]; + + /* Second byte is reserved. */ + hid_event.ux_device_class_hid_event_buffer[1] = 0; + + /* The 6 next bytes are keys. We only have one key here. */ + hid_event.ux_device_class_hid_event_buffer[2] = keys[i]; + + /* Set the keyboard event. */ + ux_device_class_hid_event_set(hid, &hid_event); + + /* Next event has the key depressed. */ + hid_event.ux_device_class_hid_event_buffer[2] = 0; + + /* Length is fixed to 8. */ + hid_event.ux_device_class_hid_event_length = 8; + + /* Set the keyboard event. */ + ux_device_class_hid_event_set(hid, &hid_event); + } + + ux_utility_thread_suspend(&tx_demo_thread_slave_simulation); + } +} + diff --git a/test/regression/usbx_test_USBX_142_DTR_callback.c b/test/regression/usbx_test_USBX_142_DTR_callback.c new file mode 100644 index 00000000..8085f301 --- /dev/null +++ b/test/regression/usbx_test_USBX_142_DTR_callback.c @@ -0,0 +1,698 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" + +#include "ux_host_class_cdc_acm.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#include "ux_host_stack.h" + +/* Define constants. */ +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bmAttributes, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + (bmAttributes), 0x00, +#define CFG_DESC_LEN 9 + +#define IAD_DESC(bIfc) \ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (bIfc), 0x02, 0x02, 0x02, 0x00, 0x00, +#define IAD_DESC_LEN 8 + +#define CDC_IFC_DESC_ALL(bIfc, bIntIn, bBulkIn, bBulkOut)\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (bIfc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06, (bIfc), (bIfc + 1),\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03, (bIfc + 1),\ + /* Endpoint interrupt in descriptor 7 bytes */\ + 0x07, 0x05, (bIntIn), 0x03, 0x40, 0x00, 0x10,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (bIfc + 1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint bulk in descriptor 7 bytes */\ + 0x07, 0x05, (bBulkIn), 0x02, 0x40, 0x00, 0x01,\ + /* Endpoint bulk out descriptor 7 bytes */\ + 0x07, 0x05, (bBulkOut), 0x02, 0x40, 0x00, 0x01, +#define CDC_IFC_DESC_ALL1(bIfc, bIntIn, bBulkIn, bBulkOut)\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (bIfc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06, (bIfc), (bIfc + 1),\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03, (bIfc + 1),\ + /* Endpoint interrupt in descriptor 7 bytes */\ + 0x07, 0x05, (bIntIn), 0x03, 0x40, 0x00, 0x10,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (bIfc + 1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint bulk out descriptor 7 bytes */\ + 0x07, 0x05, (bBulkOut), 0x02, 0x40, 0x00, 0x01,\ + /* Endpoint bulk in descriptor 7 bytes */\ + 0x07, 0x05, (bBulkIn), 0x02, 0x40, 0x00, 0x01, +#define CDC_IFC_DESC_ALL_LEN (9+5+4+5+5+7+ 9+7+7) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); + +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control = UX_NULL; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data = UX_NULL; + +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control1 = UX_NULL; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data1 = UX_NULL; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave = UX_NULL; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave1 = UX_NULL; + +static UCHAR cdc_acm_slave_change; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; + +static ULONG error_counter; + +static ULONG error_callback_counter; +static UCHAR error_callback_ignore; + +static ULONG call_counter; + +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static UCHAR test_slave_code = 0; +static UCHAR test_slave_state = 0; + +/* Define device framework. */ + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Configuration 1 descriptor 9 bytes, total 75 bytes */ + CFG_DESC(CFG_DESC_LEN + (IAD_DESC_LEN + CDC_IFC_DESC_ALL_LEN) * 2, 4, 0x40, 1) + /* IAD 8 bytes */ + IAD_DESC(0) + /* CDC_ACM interfaces */ + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) + /* IAD 8 bytes */ + IAD_DESC(2) + /* CDC_ACM interfaces */ + CDC_IFC_DESC_ALL1(2, 0x86, 0x85, 0x04) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor 10 bytes */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor 9 bytes, total 75 bytes */ + CFG_DESC(CFG_DESC_LEN + IAD_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 0x60, 1) + /* IAD 8 bytes */ + IAD_DESC(0) + /* CDC_ACM interfaces */ + CDC_IFC_DESC_ALL1(0, 0x83, 0x81, 0x02) + /* IAD 8 bytes */ + IAD_DESC(2) + /* CDC_ACM interfaces */ + CDC_IFC_DESC_ALL(2, 0x86, 0x85, 0x04) +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT break_on_cdc_acm_all_ready(VOID) +{ + + if (cdc_acm_host_control == UX_NULL || cdc_acm_host_data == UX_NULL) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control1 == UX_NULL || cdc_acm_host_data1 == UX_NULL) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_host_data->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control1->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_host_data1->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_slave == UX_NULL || cdc_acm_slave1 == UX_NULL) + /* Do not break. */ + return 0; + + /* All found, break. */ + return 1; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + if (cdc_acm_host_control != UX_NULL || cdc_acm_host_data != UX_NULL) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control1 != UX_NULL || cdc_acm_host_data1 != UX_NULL) + /* Do not break. */ + return 0; + + if (cdc_acm_slave != UX_NULL || cdc_acm_slave1 != UX_NULL) + /* Do not break. */ + return 0; + + return 1; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + if (cdc_acm_host_control == UX_NULL) + cdc_acm_host_control = cdc_acm; + else + if (cdc_acm_host_control1 == UX_NULL) + cdc_acm_host_control1 = cdc_acm; + } + else + { + if (cdc_acm_host_data == UX_NULL) + cdc_acm_host_data = cdc_acm; + else + if (cdc_acm_host_data1 == UX_NULL) + cdc_acm_host_data1 = cdc_acm; + } + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + if (cdc_acm_host_control == cdc_acm) + cdc_acm_host_control = UX_NULL; + if (cdc_acm_host_control1 == cdc_acm) + cdc_acm_host_control1 = UX_NULL; + } + else + { + if (cdc_acm_host_data == cdc_acm) + cdc_acm_host_data = UX_NULL; + if (cdc_acm_host_data1 == cdc_acm) + cdc_acm_host_data1 = UX_NULL; + } + break; + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + if (cdc_acm_slave == UX_NULL) + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; + else + if (cdc_acm_slave1 == UX_NULL) + cdc_acm_slave1 = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + if ((VOID *)cdc_acm_slave == cdc_instance) + cdc_acm_slave = UX_NULL; + if ((VOID *)cdc_acm_slave1 == cdc_instance) + cdc_acm_slave1 = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + error_callback_counter ++; + + if (!error_callback_ignore) + { + /* Ignore UX_DEVICE_HANDLE_UNKNOWN. */ + if (UX_DEVICE_HANDLE_UNKNOWN == error_code) + return; + { + /* 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_parameter_change(VOID) +{ + + /* Break if cdc_acm_slave_change is TRUE. */ + return(cdc_acm_slave_change); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_test_USBX_142_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +ULONG test_n; + +ULONG mem_count; +ULONG sem_count; +ULONG thread_count; + + printf("Running USBX-142 device DTR callback Test........................... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register CDC ACM class */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_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); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,2, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,4, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#endif + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register HCD for test */ + 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(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_DONT_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_CDC_ACM_LINE_STATE line_state; +UX_SLAVE_CLASS_CDC_ACM_LINE_STATE_PARAMETER new_line_state; + + + /* Test connect. */ + stepinfo(">>>>>>>>>>>>>>>> Test connect (FS)\n"); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + ux_test_breakable_sleep(500, break_on_cdc_acm_all_ready); + if (!(cdc_acm_host_control + && cdc_acm_host_data + && cdc_acm_slave +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + && cdc_acm_host_control1 + && cdc_acm_host_data1 + && cdc_acm_slave1 +#endif + )) + { + + printf("ERROR #%d: connect fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test SET_LINE_STATE(DTR: true)\n"); + line_state.ux_host_class_cdc_acm_line_state_dtr = UX_TRUE; + cdc_acm_slave_change = UX_FALSE; + status = ux_host_class_cdc_acm_ioctl(cdc_acm_host_control, UX_HOST_CLASS_CDC_ACM_IOCTL_SET_LINE_STATE, (VOID *)&line_state); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: host_ioctl_set_line_state error 0x%x\n", __LINE__, status); + error_counter ++; + } + else if (cdc_acm_slave_change == UX_FALSE) + { + printf("ERROR #%d: no parameter change callback\n", __LINE__); + error_counter ++; + } + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_STATE, &new_line_state); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: ioctl_get_line_state error 0x%x\n", __LINE__, status); + error_counter ++; + } + else if (new_line_state.ux_slave_class_cdc_acm_parameter_dtr != line_state.ux_host_class_cdc_acm_line_state_dtr) + { + printf("ERROR #%d: DTR not modified, still %d\n", __LINE__, new_line_state.ux_slave_class_cdc_acm_parameter_dtr); + error_counter ++; + } + + stepinfo(">>>>>>>>>>>>>>>> Test SET_LINE_STATE(DTR: false)\n"); + line_state.ux_host_class_cdc_acm_line_state_dtr = UX_FALSE; + cdc_acm_slave_change = UX_FALSE; + status = ux_host_class_cdc_acm_ioctl(cdc_acm_host_control, UX_HOST_CLASS_CDC_ACM_IOCTL_SET_LINE_STATE, (VOID *)&line_state); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: host_ioctl_set_line_state error 0x%x\n", __LINE__, status); + error_counter ++; + } + else if (cdc_acm_slave_change == UX_FALSE) + { + printf("ERROR #%d: no parameter change callback\n", __LINE__); + error_counter ++; + } + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_STATE, &new_line_state); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: ioctl_get_line_state error 0x%x\n", __LINE__, status); + error_counter ++; + } + else if (new_line_state.ux_slave_class_cdc_acm_parameter_dtr != line_state.ux_host_class_cdc_acm_line_state_dtr) + { + printf("ERROR #%d: DTR not modified, still %d\n", __LINE__, new_line_state.ux_slave_class_cdc_acm_parameter_dtr); + error_counter ++; + } + + stepinfo(">>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + ux_test_breakable_sleep(100, break_on_removal); + + if (cdc_acm_host_control || cdc_acm_host_data || cdc_acm_slave) + { + + printf("ERROR #%d: disconnect fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Deinitialize\n"); + + /* Deinitialize the class. */ + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + + /* Deinitialize the device side of usbx. */ + _ux_device_stack_uninitialize(); + + /* And finally the usbx system resources. */ + _ux_system_uninitialize(); + + stepinfo(">>>>>>>>>>>>>>>> Dump results\n"); + + if (error_counter > 0) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + +void tx_test_thread_slave_simulation_entry(ULONG arg) +{ +UINT status; +ULONG actual_length; + + while(1) + { + switch (test_slave_code) + { + case 1: + stepinfo(">>>>>>>>>>>>>>>> Slave read START\n"); + test_slave_state ++; + status = ux_device_class_cdc_acm_read(cdc_acm_slave, buffer, 256, &actual_length); + stepinfo(">>>>>>>>>>>>>>>> Slave read END\n"); + if (status != UX_TRANSFER_BUS_RESET) + { + printf("ERROR #%d: read not abort 0x%x\n", __LINE__, status); + error_counter ++; + } + break; + case 2: + stepinfo(">>>>>>>>>>>>>>>> Slave write START\n"); + test_slave_state ++; + status = ux_device_class_cdc_acm_write(cdc_acm_slave, buffer, 1024, &actual_length); + stepinfo(">>>>>>>>>>>>>>>> Slave write END\n"); + if (status != UX_TRANSFER_BUS_RESET) + { + printf("ERROR #%d: write not abort 0x%x\n", __LINE__, status); + error_counter ++; + } + break; + default: + break; + } + test_slave_state = 0; + tx_thread_suspend(&tx_test_thread_slave_simulation); + } +} diff --git a/test/regression/usbx_test_USBX_6_ux_version_id.c b/test/regression/usbx_test_USBX_6_ux_version_id.c new file mode 100644 index 00000000..af092d68 --- /dev/null +++ b/test/regression/usbx_test_USBX_6_ux_version_id.c @@ -0,0 +1,164 @@ +/* This test is designed to test the ux_utility_timer_.... */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_MEMORY_SIZE (64*1024) + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +/* Define USBX test global variables. */ + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +/* Simulator actions. */ + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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); + } + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_test_USBX_6_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +CHAR *rpool_start; +CHAR *cpool_start; +ULONG rpool_free[2]; +ULONG cpool_free[2]; +VOID *ptr; +UINT n, i; +const CHAR flags[] = { + UX_REGULAR_MEMORY, UX_CACHE_SAFE_MEMORY, 0xFF +}; +const CHAR expect_error[] = { + UX_FALSE, UX_FALSE, UX_TRUE +}; + + /* Inform user. */ + printf("Running USBX-6 _ux_version_id Test.................................. "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_memory; + memory_pointer = stack_pointer + (UX_TEST_STACK_SIZE * 2); + + rpool_start = memory_pointer; + cpool_start = memory_pointer + UX_TEST_MEMORY_SIZE; + + /* Initialize USBX Memory. */ + status = ux_system_initialize(rpool_start, UX_TEST_MEMORY_SIZE, cpool_start, UX_TEST_MEMORY_SIZE); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + + if (_ux_version_id == UX_NULL) + { + printf("ERROR #%d: _ux_version_id is NULL\n", __LINE__); + error_counter ++; + } + else + { + + /* Use _ux_version_id so if there is compile problem we know it. */ + puts("\n_ux_version_id is: "); + puts(_ux_version_id); + } + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} \ No newline at end of file diff --git a/test/regression/usbx_test_common.h b/test/regression/usbx_test_common.h new file mode 100644 index 00000000..fbc75ea8 --- /dev/null +++ b/test/regression/usbx_test_common.h @@ -0,0 +1,29 @@ +#include + +/* This is how ux_utility_memory_allocate calculates the final memory size. */ +static UINT calculate_final_memory_request_size(UINT count, ...) +{ + +UINT original_memory_size_requested; +UINT memory_size_requested; +UINT total_final_memory_size = 0; + + + va_list args; + va_start(args, count); + + while(count-- > 0) + { + original_memory_size_requested = va_arg(args, UINT); + + memory_size_requested = (original_memory_size_requested + UX_ALIGN_MIN) & (UINT)~UX_ALIGN_MIN; + memory_size_requested += sizeof(UX_MEMORY_BLOCK); + + total_final_memory_size += memory_size_requested; + } + + total_final_memory_size += sizeof(UX_MEMORY_BLOCK); + total_final_memory_size += 1; + + return total_final_memory_size; +} diff --git a/test/regression/usbx_test_common_hid.h b/test/regression/usbx_test_common_hid.h new file mode 100644 index 00000000..a017dc1b --- /dev/null +++ b/test/regression/usbx_test_common_hid.h @@ -0,0 +1,161 @@ +#include +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_host_class_hid.h" +#include "ux_host_class_hid_keyboard.h" +#include "ux_host_class_hid_mouse.h" +#include "ux_host_class_hid_remote_control.h" +#include "ux_device_class_hid.h" +#include "ux_device_stack.h" + +#include "ux_test.h" +#include "usbx_test_common.h" + +#define ARRAY_COUNT(array) (sizeof(array)/sizeof(array[0])) +#define LSB(x) (x & 0xff) +#define MSB(x) ((x & 0xff00) >> 8) + +/* Define constants. */ +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_MEMORY_SIZE (96*1024) + +/* Define local/extern function prototypes. */ +static void demo_thread_entry(ULONG); +static UINT demo_thread_hid_callback(UX_SLAVE_CLASS_HID *, UX_SLAVE_CLASS_HID_EVENT *); +static UINT demo_thread_hid_set_callback(UX_SLAVE_CLASS_HID *, UX_SLAVE_CLASS_HID_EVENT *); +static UINT demo_thread_hid_get_callback(UX_SLAVE_CLASS_HID *, UX_SLAVE_CLASS_HID_EVENT *); +static void tx_demo_thread_host_simulation_entry(ULONG); +static void tx_demo_thread_slave_simulation_entry(ULONG); +static void tx_demo_thread_device_simulation_entry(ULONG); + +static void demo_device_hid_instance_activate(VOID *); +static void demo_device_hid_instance_deactivate(VOID *); + + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static TX_THREAD tx_demo_thread_device_simulation; +static UX_HOST_CLASS_HID *hid; +static UX_HOST_CLASS_HID_REPORT_CALLBACK hid_report_callback; +static UX_HOST_CLASS_HID_CLIENT *hid_client; +static UX_HOST_CLASS_HID_KEYBOARD *hid_keyboard; +static UX_HOST_CLASS_HID_MOUSE *hid_mouse; +static UX_HOST_CLASS_HID_REMOTE_CONTROL *hid_remote_control; +static UX_HOST_CLASS_HID_REPORT_GET_ID hid_report_id; +static UX_HOST_CLASS_HID_CLIENT_REPORT client_report; +static UX_SLAVE_CLASS_HID_PARAMETER hid_parameter; +static UX_SLAVE_CLASS_HID *device_hid; +static UX_SLAVE_CLASS_HID_EVENT device_hid_event; + + +/* Prototype for test control return. */ +void test_control_return(UINT status); + + +static UINT demo_class_hid_get(void) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Wait for enum thread to complete. */ + ux_test_wait_for_enum_thread_completion(); + + /* Find the main HID container */ + status = ux_host_stack_class_get(_ux_system_host_class_hid_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* We get the first instance of the hid device */ + status = ux_host_stack_class_instance_get(class, 0, (void **)&hid); + if (status != UX_SUCCESS) + return(status); + + if(hid -> ux_host_class_hid_state != UX_HOST_CLASS_INSTANCE_LIVE) + return(UX_ERROR); + + /* Get client. */ + hid_client = hid -> ux_host_class_hid_client; + return(UX_SUCCESS); +} + +static UINT demo_class_hid_keyboard_get(void) +{ +UINT status; + + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + return(status); + + /* Check client entry. */ + if (hid_client -> ux_host_class_hid_client_handler != ux_host_class_hid_keyboard_entry) + return(UX_ERROR); + + /* Get instance. */ + hid_keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)hid_client -> ux_host_class_hid_client_local_instance; + if (hid_keyboard == UX_NULL) + return(UX_ERROR); + + /* Check instance state. */ + if (hid_keyboard -> ux_host_class_hid_keyboard_state != UX_HOST_CLASS_INSTANCE_LIVE) + return(UX_ERROR); + + /* Instance is good. */ + return(UX_SUCCESS); +} + +static UINT demo_class_hid_mouse_get(void) +{ +UINT status; + + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + return(status); + + /* Check client entry. */ + if (hid_client -> ux_host_class_hid_client_handler != ux_host_class_hid_mouse_entry) + return(UX_ERROR); + + /* Get instance. */ + hid_mouse = (UX_HOST_CLASS_HID_MOUSE *)hid_client -> ux_host_class_hid_client_local_instance; + if (hid_mouse == UX_NULL) + return(UX_ERROR); + + /* Check instance state. */ + if (hid_mouse -> ux_host_class_hid_mouse_state != UX_HOST_CLASS_INSTANCE_LIVE) + return(UX_ERROR); + + /* Instance is good. */ + return(UX_SUCCESS); +} + +static UINT demo_class_hid_remote_control_get(void) +{ +UINT status; + + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + return(status); + + /* Check client entry. */ + if (hid_client -> ux_host_class_hid_client_handler != ux_host_class_hid_remote_control_entry) + return(UX_ERROR); + + /* Get instance. */ + hid_remote_control = (UX_HOST_CLASS_HID_REMOTE_CONTROL *)hid_client -> ux_host_class_hid_client_local_instance; + if (hid_remote_control == UX_NULL) + return(UX_ERROR); + + /* Check instance state. */ + if (hid_remote_control -> ux_host_class_hid_remote_control_state != UX_HOST_CLASS_INSTANCE_LIVE) + return(UX_ERROR); + + /* Instance is good. */ + return(UX_SUCCESS); +} diff --git a/test/regression/usbx_test_common_storage.h b/test/regression/usbx_test_common_storage.h new file mode 100644 index 00000000..bad19115 --- /dev/null +++ b/test/regression/usbx_test_common_storage.h @@ -0,0 +1,126 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_class_storage.h" + +#include "usbx_test_common.h" + +/* Define constants. */ +#define UX_DEMO_STACK_SIZE 2048 +#define UX_DEMO_BUFFER_SIZE 2048 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (256 * 1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +static UINT demo_device_state_change(ULONG event); +static void demo_thread_entry(ULONG); +static UINT default_device_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT default_device_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT default_device_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); + + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static ULONG error_counter; +static TX_THREAD demo_thread; +static UX_HOST_CLASS_STORAGE *global_storage; +static UX_HOST_CLASS_STORAGE_MEDIA *global_storage_media; +static FX_MEDIA *global_media; +static UINT status; +static UINT transfer_completed; +static ULONG requested_length; +static FX_FILE my_file; +static TX_SEMAPHORE demo_semaphore; +static CHAR file_name[64]; +static UCHAR global_buffer[UX_DEMO_FILE_BUFFER_SIZE]; +static UCHAR global_ram_disk_working_buffer[512]; +static FX_MEDIA global_ram_disk; +static CHAR global_ram_disk_memory[UX_RAM_DISK_SIZE]; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; +static TX_SEMAPHORE storage_instance_live_semaphore; + + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +/* Prototype for _ux_hcd_sim_host_entry */ +UINT _ux_hcd_sim_host_entry(UX_HCD *, UINT, VOID *); + +static UINT host_storage_instance_get(void) +{ + +UINT status; +UX_HOST_CLASS *host_class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &host_class); + if (status != UX_SUCCESS) + return(status); + + status = ux_utility_semaphore_get(&storage_instance_live_semaphore, 5000); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + status = ux_host_stack_class_instance_get(host_class, 0, (void **) &global_storage); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + if (global_storage -> ux_host_class_storage_state != UX_HOST_CLASS_INSTANCE_LIVE) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + if (host_class -> ux_host_class_media == UX_NULL) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Setup media pointer. */ + global_storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *) host_class -> ux_host_class_media; + global_media = &global_storage_media -> ux_host_class_storage_media; + + if (global_media == UX_NULL) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + return(UX_SUCCESS); +} diff --git a/test/regression/usbx_ux_api_tracex_id_test.c b/test/regression/usbx_ux_api_tracex_id_test.c new file mode 100644 index 00000000..a182557b --- /dev/null +++ b/test/regression/usbx_ux_api_tracex_id_test.c @@ -0,0 +1,162 @@ +/* This test is designed to test the ux_utility_thread_identify. */ + +#include +#include "tx_api.h" +#include "tx_thread.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +/* Define the counters used in the test application... */ + +static CHAR *stack_pointer; +static CHAR *memory_pointer; + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +/* Define USBX test global variables. */ + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +/* Simulator actions. */ + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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); + } + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_api_tracex_id_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; + + + /* Inform user. */ + printf("Running usbx_ux_api_tracex_id Test.................................. "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation 0", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d: thread create fail 0x%x\n", __LINE__, status); + error_counter ++; + } + + /* Reset threads. */ + _ux_utility_memory_set(&ux_test_thread_simulation_1, 0, sizeof(ux_test_thread_simulation_1)); +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + +TX_THREAD *this_thread; +UINT tracex_id = 0; +#if defined(TX_ENABLE_EVENT_TRACE) && defined(UX_TRACE_INSERT_MACROS) + /* The fix is to make sure below trace ID are different, if it is not fixed, the compile will fail*/ + switch(tracex_id){ + case UX_TRACE_DEVICE_STACK_CONFIGURATION_GET: + case UX_TRACE_DEVICE_STACK_CONFIGURATION_SET: + case UX_TRACE_DEVICE_CLASS_DPUMP_WRITE: + case UX_TRACE_DEVICE_CLASS_DPUMP_CHANGE: + default: + break; + } +#endif + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + diff --git a/test/regression/usbx_ux_device_class_cdc_acm_activate_test.c b/test/regression/usbx_ux_device_class_cdc_acm_activate_test.c new file mode 100644 index 00000000..7cf032f8 --- /dev/null +++ b/test/regression/usbx_ux_device_class_cdc_acm_activate_test.c @@ -0,0 +1,536 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" + +#include "ux_host_class_cdc_acm.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#include "ux_host_stack.h" + +/* Define constants. */ +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bmAttributes, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + (bmAttributes), 0x00, +#define CFG_DESC_LEN 9 + +#define IAD_DESC(bIfc) \ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (bIfc), 0x02, 0x02, 0x02, 0x00, 0x00, +#define IAD_DESC_LEN 8 + +#define CDC_IFC_DESC_ALL(bIfc, bIntIn, bBulkIn, bBulkOut)\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (bIfc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06, (bIfc), (bIfc + 1),\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03, (bIfc + 1),\ + /* Endpoint interrupt in descriptor 7 bytes */\ + 0x07, 0x05, (bIntIn), 0x03, 0x40, 0x00, 0x10,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (bIfc + 1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint bulk in descriptor 7 bytes */\ + 0x07, 0x05, (bBulkIn), 0x02, 0x40, 0x00, 0x01,\ + /* Endpoint bulk out descriptor 7 bytes */\ + 0x07, 0x05, (bBulkOut), 0x02, 0x40, 0x00, 0x01, +#define CDC_IFC_DESC_ALL_LEN (9+5+4+5+5+7+ 9+7+7) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +static UCHAR cdc_acm_slave_change; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; + +static ULONG error_counter; + +static ULONG error_callback_counter; +static UCHAR error_callback_ignore; + +static ULONG call_counter; + +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +/* Define device framework. */ + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Configuration 1 descriptor 9 bytes, total 75 bytes */ + CFG_DESC(CFG_DESC_LEN + IAD_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 0x40, 1) + /* IAD 8 bytes */ + IAD_DESC(0) + /* CDC_ACM interfaces */ + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor 10 bytes */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor 9 bytes, total 75-8=67 bytes */ + CFG_DESC(CFG_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 0x60, 1) + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT break_on_cdc_acm_all_ready(VOID) +{ +UINT status; +UINT i; +UX_HOST_CLASS *class; +UX_HOST_CLASS_CDC_ACM *cdc_acm; + + /* Find the main cdc_acm container */ + status = ux_host_stack_class_get(_ux_system_host_class_cdc_acm_name, &class); + if (status != UX_SUCCESS) + /* Do not break. */ + return 0; + + /* Find class instances. */ + for (i = 0; i < 2; i ++) + { + status = ux_host_stack_class_instance_get(class, i, (void **) &cdc_acm); + if (status != UX_SUCCESS) + /* Do not break. */ + return 0; + + switch(cdc_acm->ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass) + { + + case UX_HOST_CLASS_CDC_CONTROL_CLASS: + cdc_acm_host_control = cdc_acm; + break; + + case UX_HOST_CLASS_CDC_DATA_CLASS: + cdc_acm_host_data = cdc_acm; + break; + + default: + break; + } + } + + if (cdc_acm_host_control == UX_NULL || cdc_acm_host_data == UX_NULL) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_host_data->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (_ux_system_slave->ux_system_slave_class_array[0].ux_slave_class_instance == UX_NULL) + /* Do not break. */ + return 0; + + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *)_ux_system_slave->ux_system_slave_class_array[0].ux_slave_class_instance; + + /* All found, break. */ + return 1; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + if (_ux_system_slave->ux_system_slave_class_array[0].ux_slave_class_instance != UX_NULL) + /* Do not break. */ + return 0; + + cdc_acm_host_data = UX_NULL; + cdc_acm_host_control = UX_NULL; + cdc_acm_slave = UX_NULL; + + return 1; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; +} + +static VOID test_ux_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); + } + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_cdc_acm_activate_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + printf("Running ux_device_class_cdc_acm_activate 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register CDC ACM class */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_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); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = UX_NULL; + parameter.ux_slave_class_cdc_acm_instance_deactivate = UX_NULL; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 2,0, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 3,0, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#endif + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register HCD for test */ + 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(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UX_SLAVE_ENDPOINT *slave_interrupt_endpoint = UX_NULL; + + stepinfo("\n"); + + /* Test connect. */ + stepinfo(">>>>>>>>>>>>>>>> Test connect (FS)\n"); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + ux_test_breakable_sleep(100, break_on_cdc_acm_all_ready); + if (!(cdc_acm_host_control && cdc_acm_host_data && cdc_acm_slave)) + { + + printf("ERROR #%d: connect fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Deinitialize\n"); + + /* Deinitialize the class. */ + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + + /* Deinitialize the device side of usbx. */ + _ux_device_stack_uninitialize(); + + /* And finally the usbx system resources. */ + _ux_system_uninitialize(); + + stepinfo(">>>>>>>>>>>>>>>> Dump results\n"); + + if (error_counter > 0) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + +void tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Sleep so ThreadX on Win32 will delete this thread. */ + ux_utility_delay_ms(100); + } +} diff --git a/test/regression/usbx_ux_device_class_cdc_acm_bulkout_thread_test.c b/test/regression/usbx_ux_device_class_cdc_acm_bulkout_thread_test.c new file mode 100644 index 00000000..0346112f --- /dev/null +++ b/test/regression/usbx_ux_device_class_cdc_acm_bulkout_thread_test.c @@ -0,0 +1,731 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" + +#include "ux_host_class_cdc_acm.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#include "ux_host_stack.h" + +/* Define constants. */ +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +#define CDC_IFC_DESC_ALL(bIfc, bIntIn, bBulkIn, bBulkOut)\ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (bIfc), 0x02, 0x02, 0x02, 0x00, 0x00,\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (bIfc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06, (bIfc), (bIfc + 1),\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03, (bIfc + 1),\ + /* Endpoint interrupt in descriptor 7 bytes */\ + 0x07, 0x05, (bIntIn), 0x02, 0x40, 0x00, 0x00,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (bIfc + 1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint bulk out descriptor 7 bytes */\ + 0x07, 0x05, (bBulkOut), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint bulk in descriptor 7 bytes */\ + 0x07, 0x05, (bBulkIn), 0x02, 0x40, 0x00, 0x00, +#define CDC_IFC_DESC_ALL_LEN (8+ 9+5+4+5+5+7+ 9+7+7) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); + void tx_test_thread_dummy_entry(ULONG arg); +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +static UCHAR cdc_acm_slave_change; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; + +static ULONG error_counter; + +static ULONG error_callback_counter; +static UCHAR error_callback_ignore; + +static TX_SEMAPHORE slave_read_semaphore; +static UINT slave_read_status; +static ULONG slave_read_length; +static ULONG slave_read_counter; +static struct { + UCHAR *buffer; + UCHAR *save2; + ULONG length; + UINT status; +} slave_read_log[32]; +static TX_SEMAPHORE slave_write_semaphore; +static UINT slave_write_status; +static ULONG slave_write_length; + +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; +static UCHAR host_buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG actions_2_set_trigger = ~0; +static UX_TEST_HCD_SIM_ACTION *actions_2_set = UX_NULL; + +/* Define device framework. */ + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Configuration 1 descriptor 9 bytes, total 75 bytes */ + CFG_DESC(CFG_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 1) + CDC_IFC_DESC_ALL(0, 0x83, 0x02, 0x81) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor 9 bytes, total 75 bytes */ + CFG_DESC(CFG_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 1) + CDC_IFC_DESC_ALL(0, 0x83, 0x02, 0x81) +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +static UX_TEST_HCD_SIM_ACTION error_on_transfer0[] = { +/* 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_DCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER, 0, UX_NULL, 0, UX_ERROR, + UX_ERROR}, /* Error */ +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION error_on_transfer1[] = { +/* 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_DCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER, 0, UX_NULL, 0, UX_ERROR, + UX_SUCCESS}, /* Completion code error */ +{ UX_DCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER, 0, UX_NULL, 0, UX_ERROR, + UX_ERROR}, /* Error */ +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT break_on_cdc_acm_all_ready(VOID) +{ +UINT status; +UX_HOST_CLASS *class; + + /* Find the main cdc_acm container */ + status = ux_host_stack_class_get(_ux_system_host_class_cdc_acm_name, &class); + if (status != UX_SUCCESS) + /* Do not break. */ + return 0; + + /* Find class instance. */ + status = ux_host_stack_class_instance_get(class, 0, (void **) &cdc_acm_host_control); + if (status != UX_SUCCESS) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + /* Find class instance. */ + status = ux_host_stack_class_instance_get(class, 1, (void **) &cdc_acm_host_data); + if (status != UX_SUCCESS) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_slave == UX_NULL) + /* Do not break. */ + return 0; + + /* All found, break. */ + return 1; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; +} + +static VOID test_ux_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); + } + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_cdc_acm_bulkout_thread_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +ULONG rmem_free; + + + printf("Running ux_device_class_cdc_acm_bulkout_thread Test.................. "); +#ifdef UX_DEVICE_CLASS_CDC_ACM_TRANSMISSION_DISABLE + printf("Skipped\n"); + test_control_return(0); +#else + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register CDC ACM class */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_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); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1, 0, ¶meter); + + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register HCD for test */ + 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(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#endif +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_CDC_ACM_LINE_STATE line_state; +ULONG actual_length; + + stepinfo(">>>>>>>>>>>>>>>> Test host wait\n"); + _ux_utility_thread_suspend(&tx_test_thread_host_simulation); + + /* Test connect. */ + stepinfo(">>>>>>>>>>>>>>>> Test host connect\n"); + ux_test_breakable_sleep(100, break_on_cdc_acm_all_ready); + if (!(cdc_acm_host_control && cdc_acm_host_data && cdc_acm_slave)) + { + + printf("ERROR #%d: connect fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test host set DTR\n"); + line_state.ux_host_class_cdc_acm_line_state_dtr = 1; + line_state.ux_host_class_cdc_acm_line_state_rts = 1; + status = ux_host_class_cdc_acm_ioctl(cdc_acm_host_control, UX_HOST_CLASS_CDC_ACM_IOCTL_SET_LINE_STATE, &line_state); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_utility_thread_suspend(&tx_test_thread_host_simulation); + + stepinfo(">>>>>>>>>>>>>>>> Test host write 1, to move slave bulk OUT thread\n"); + host_buffer[0] = '1'; + status = ux_host_class_cdc_acm_write(cdc_acm_host_data, host_buffer, 1, &actual_length); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_utility_thread_suspend(&tx_test_thread_host_simulation); + + stepinfo(">>>>>>>>>>>>>>>> Test host read UX_DEMO_BUFFER_SIZE\n"); + status = ux_host_class_cdc_acm_read(cdc_acm_host_data, host_buffer, UX_DEMO_BUFFER_SIZE, &actual_length); + if (status != UX_SUCCESS && actual_length != UX_DEMO_BUFFER_SIZE) + { + printf("ERROR #%d: code 0x%x: actual_length %lu\n", __LINE__, status, actual_length); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Deinitialize\n"); + + /* Deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + + /* Deinitialize the device side of usbx. */ + _ux_device_stack_uninitialize(); + + /* And finally the usbx system resources. */ + _ux_system_uninitialize(); + + stepinfo(">>>>>>>>>>>>>>>> Dump results\n"); + + if (error_counter > 0) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + +UINT tx_demo_thread_slave_read_callback(UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave, UINT status, UCHAR *data_pointer, ULONG length) +{ + if (slave_read_counter < 32) + { + slave_read_log[slave_read_counter].buffer = data_pointer; + slave_read_log[slave_read_counter].length = length; + slave_read_log[slave_read_counter].status = status; + if (slave_read_log[slave_read_counter].save2) + ux_utility_memory_copy(slave_read_log[slave_read_counter].save2, data_pointer,length); + } + slave_read_counter ++; + + if (actions_2_set_trigger != (~0)) + { + if (slave_read_counter == actions_2_set_trigger) + { + ux_test_dcd_sim_slave_set_actions(actions_2_set); + slave_read_counter = 0; + actions_2_set = UX_NULL; + actions_2_set_trigger = ~0; + } + + } + + /* Save the status. */ + slave_read_status = status; + slave_read_length = length; + + /* Copy the data in local buffer. */ + ux_utility_memory_copy(buffer, data_pointer,length); + + /* Put a semaphore. This will wake up the host. */ + _ux_utility_semaphore_put(&slave_read_semaphore); + + /* Done here. */ + return(UX_SUCCESS); +} + + +UINT tx_demo_thread_slave_write_callback(UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave, UINT status, ULONG length) +{ + + /* Save the status. */ + slave_write_status = status; + slave_write_length = length; + + /* Confirmation of the end of transmission. */ + _ux_utility_semaphore_put(&slave_write_semaphore); + + /* Done here. */ + return(UX_SUCCESS); +} + +void tx_test_thread_dummy_entry(ULONG arg) +{ + _ux_utility_thread_suspend(_ux_utility_thread_identify()); +} + +void tx_test_thread_slave_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG actual_length; +UX_SLAVE_CLASS_CDC_ACM_LINE_STATE_PARAMETER line_state; +UX_SLAVE_CLASS_CDC_ACM_CALLBACK_PARAMETER callback; +UINT i; +ULONG rmem_free; +ALIGN_TYPE tmp; +UX_SLAVE_INTERFACE *interface; + + /* Test device. */ + stepinfo(">>>>>>>>>>>>>>>> Test device connect\n"); + ux_test_breakable_sleep(200, break_on_cdc_acm_all_ready); + if (!(cdc_acm_host_control && cdc_acm_host_data && cdc_acm_slave)) + { + printf("ERROR #%d: connect fail\n", __LINE__); + test_control_return(1); + } +#ifndef UX_DEVICE_CLASS_CDC_ACM_TRANSMISSION_DISABLE + stepinfo(">>>>>>>>>>>>>>>> Test device DTR state to start transmission\n"); + line_state.ux_slave_class_cdc_acm_parameter_dtr = 0; + line_state.ux_slave_class_cdc_acm_parameter_rts = 0; + ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_STATE, &line_state); + _ux_utility_thread_resume(&tx_test_thread_host_simulation); + for (i = 0; i < 20; i ++) + { + _ux_utility_delay_ms(25); + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_STATE, &line_state); + if (status != UX_SUCCESS) + break; + if (line_state.ux_slave_class_cdc_acm_parameter_dtr) + break; + } + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_STATE fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (line_state.ux_slave_class_cdc_acm_parameter_dtr != UX_TRUE) + { + + printf("ERROR #%d: DTR not set\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test device ioctl UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START\n"); + + /* Set the callback parameter. */ + callback.ux_device_class_cdc_acm_parameter_write_callback = tx_demo_thread_slave_write_callback; + callback.ux_device_class_cdc_acm_parameter_read_callback = tx_demo_thread_slave_read_callback; + + /* Create the semaphore to synchronize with reception. */ + status = _ux_utility_semaphore_create(&slave_read_semaphore, "slave_read_semaphore", 0); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: slave_read_semaphore fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Create the semaphore to synchronize with transmission. */ + status = _ux_utility_semaphore_create(&slave_write_semaphore, "slave_write_semaphore", 0); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: slave_write_semaphore fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + + error_callback_ignore = UX_TRUE; + rmem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + cdc_acm_slave->ux_slave_class_cdc_acm_transmission_status = UX_FALSE; + stepinfo(">>>>>>>>>>>>>>>> Test device ioctl UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START good\n"); + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START, &callback); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + + _ux_utility_thread_resume(&tx_test_thread_host_simulation); + ux_utility_delay_ms(100); + + stepinfo(">>>>>>>>>>>>>>>> Test ux_device_class_cdc_acm_bulkin_thread for case of 'total_length > UX_SLAVE_REQUEST_DATA_MAX_LENGTH'\n"); + status = ux_device_class_cdc_acm_write_with_callback(cdc_acm_slave, buffer, UX_DEMO_BUFFER_SIZE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } +#endif + stepinfo(">>>>>>>>>>>>>>>> Test device done\n"); + _ux_utility_thread_resume(&tx_test_thread_host_simulation); + while(1) + { + + /* Sleep so ThreadX on Win32 will delete this thread. */ + ux_utility_delay_ms(100); + } +} diff --git a/test/regression/usbx_ux_device_class_cdc_acm_deactivate_test.c b/test/regression/usbx_ux_device_class_cdc_acm_deactivate_test.c new file mode 100644 index 00000000..e8553e62 --- /dev/null +++ b/test/regression/usbx_ux_device_class_cdc_acm_deactivate_test.c @@ -0,0 +1,553 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" + +#include "ux_host_class_cdc_acm.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#include "ux_host_stack.h" + +/* Define constants. */ +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bmAttributes, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + (bmAttributes), 0x00, +#define CFG_DESC_LEN 9 + +#define IAD_DESC(bIfc) \ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (bIfc), 0x02, 0x02, 0x02, 0x00, 0x00, +#define IAD_DESC_LEN 8 + +#define CDC_IFC_DESC_ALL(bIfc, bIntIn, bBulkIn, bBulkOut)\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (bIfc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06, (bIfc), (bIfc + 1),\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03, (bIfc + 1),\ + /* Endpoint interrupt in descriptor 7 bytes */\ + 0x07, 0x05, (bIntIn), 0x03, 0x40, 0x00, 0x10,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (bIfc + 1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint bulk in descriptor 7 bytes */\ + 0x07, 0x05, (bBulkIn), 0x02, 0x40, 0x00, 0x01,\ + /* Endpoint bulk out descriptor 7 bytes */\ + 0x07, 0x05, (bBulkOut), 0x02, 0x40, 0x00, 0x01, +#define CDC_IFC_DESC_ALL_LEN (9+5+4+5+5+7+ 9+7+7) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +static UCHAR cdc_acm_slave_change; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; + +static ULONG error_counter; + +static ULONG error_callback_counter; +static UCHAR error_callback_ignore; + +static ULONG call_counter; + +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +/* Define device framework. */ + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Configuration 1 descriptor 9 bytes, total 75 bytes */ + CFG_DESC(CFG_DESC_LEN + IAD_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 0x40, 1) + /* IAD 8 bytes */ + IAD_DESC(0) + /* CDC_ACM interfaces */ + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor 10 bytes */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor 9 bytes, total 75-8=67 bytes */ + CFG_DESC(CFG_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 0x60, 1) + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT break_on_cdc_acm_all_ready(VOID) +{ +UINT status; +UINT i; +UX_HOST_CLASS *class; +UX_HOST_CLASS_CDC_ACM *cdc_acm; + + /* Find the main cdc_acm container */ + status = ux_host_stack_class_get(_ux_system_host_class_cdc_acm_name, &class); + if (status != UX_SUCCESS) + /* Do not break. */ + return 0; + + /* Find class instances. */ + for (i = 0; i < 2; i ++) + { + status = ux_host_stack_class_instance_get(class, i, (void **) &cdc_acm); + if (status != UX_SUCCESS) + /* Do not break. */ + return 0; + + switch(cdc_acm->ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass) + { + + case UX_HOST_CLASS_CDC_CONTROL_CLASS: + cdc_acm_host_control = cdc_acm; + break; + + case UX_HOST_CLASS_CDC_DATA_CLASS: + cdc_acm_host_data = cdc_acm; + break; + + default: + break; + } + } + + if (cdc_acm_host_control == UX_NULL || cdc_acm_host_data == UX_NULL) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_host_data->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (_ux_system_slave->ux_system_slave_class_array[0].ux_slave_class_instance == UX_NULL) + /* Do not break. */ + return 0; + + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *)_ux_system_slave->ux_system_slave_class_array[0].ux_slave_class_instance; + + /* All found, break. */ + return 1; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + if (_ux_system_slave->ux_system_slave_device.ux_slave_device_state > UX_DEVICE_RESET) + /* Do not break. */ + return 0; + + cdc_acm_host_data = UX_NULL; + cdc_acm_host_control = UX_NULL; + cdc_acm_slave = UX_NULL; + + return 1; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + error_callback_counter ++; + + if (!error_callback_ignore) + { + /* Ignore UX_DEVICE_HANDLE_UNKNOWN. */ + if (UX_DEVICE_HANDLE_UNKNOWN == error_code) + return; + { + /* 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); + } + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_cdc_acm_deactivate_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + printf("Running ux_device_class_cdc_acm_deactivate 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register CDC ACM class */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_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); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = UX_NULL; + parameter.ux_slave_class_cdc_acm_instance_deactivate = UX_NULL; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 2,0, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 3,0, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#endif + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register HCD for test */ + 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(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UX_SLAVE_ENDPOINT *slave_interrupt_endpoint = UX_NULL; + + stepinfo("\n"); + + /* Test connect. */ + stepinfo(">>>>>>>>>>>>>>>> Test connect (FS)\n"); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + ux_test_breakable_sleep(100, break_on_cdc_acm_all_ready); + if (!(cdc_acm_host_control && cdc_acm_host_data && cdc_acm_slave)) + { + + printf("ERROR #%d: connect fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + ux_test_breakable_sleep(100, break_on_removal); + + if (cdc_acm_host_control || cdc_acm_host_data || cdc_acm_slave) + { + + printf("ERROR #%d: disconnect fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Deinitialize\n"); + + /* Deinitialize the class. */ + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + + /* Deinitialize the device side of usbx. */ + _ux_device_stack_uninitialize(); + + /* And finally the usbx system resources. */ + _ux_system_uninitialize(); + + stepinfo(">>>>>>>>>>>>>>>> Dump results\n"); + + if (error_counter > 0) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + +void tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Sleep so ThreadX on Win32 will delete this thread. */ + ux_utility_delay_ms(100); + } +} diff --git a/test/regression/usbx_ux_device_class_cdc_acm_ioctl_test.c b/test/regression/usbx_ux_device_class_cdc_acm_ioctl_test.c new file mode 100644 index 00000000..a454456b --- /dev/null +++ b/test/regression/usbx_ux_device_class_cdc_acm_ioctl_test.c @@ -0,0 +1,763 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" + +#include "ux_host_class_cdc_acm.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#include "ux_host_stack.h" + +/* Define constants. */ +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (96*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bmAttributes, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + (bmAttributes), 0x00, +#define CFG_DESC_LEN 9 + +#define IAD_DESC(bIfc) \ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (bIfc), 0x02, 0x02, 0x02, 0x00, 0x00, +#define IAD_DESC_LEN 8 + +#define CDC_IFC_DESC_ALL(bIfc, bIntIn, bBulkIn, bBulkOut)\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (bIfc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06, (bIfc), (bIfc + 1),\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03, (bIfc + 1),\ + /* Endpoint interrupt in descriptor 7 bytes */\ + 0x07, 0x05, (bIntIn), 0x03, 0x40, 0x00, 0x10,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (bIfc + 1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint bulk in descriptor 7 bytes */\ + 0x07, 0x05, (bBulkIn), 0x02, 0x40, 0x00, 0x01,\ + /* Endpoint bulk out descriptor 7 bytes */\ + 0x07, 0x05, (bBulkOut), 0x02, 0x40, 0x00, 0x01, +#define CDC_IFC_DESC_ALL1(bIfc, bIntIn, bBulkIn, bBulkOut)\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (bIfc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06, (bIfc), (bIfc + 1),\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03, (bIfc + 1),\ + /* Endpoint interrupt in descriptor 7 bytes */\ + 0x07, 0x05, (bIntIn), 0x03, 0x40, 0x00, 0x10,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (bIfc + 1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint bulk out descriptor 7 bytes */\ + 0x07, 0x05, (bBulkOut), 0x02, 0x40, 0x00, 0x01,\ + /* Endpoint bulk in descriptor 7 bytes */\ + 0x07, 0x05, (bBulkIn), 0x02, 0x40, 0x00, 0x01, +#define CDC_IFC_DESC_ALL_LEN (9+5+4+5+5+7+ 9+7+7) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); + +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +/* Define global data structures. */ +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control = UX_NULL; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data = UX_NULL; + +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control1 = UX_NULL; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data1 = UX_NULL; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave = UX_NULL; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave1 = UX_NULL; + +static UCHAR cdc_acm_slave_change; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; + +static ULONG error_counter; + +static ULONG error_callback_counter; +static UCHAR error_callback_ignore; + +static ULONG call_counter; + +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static UCHAR test_slave_code = 0; +static UCHAR test_slave_state = 0; + +/* Define device framework. */ + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Configuration 1 descriptor 9 bytes, total 75 bytes */ + CFG_DESC(CFG_DESC_LEN + (IAD_DESC_LEN + CDC_IFC_DESC_ALL_LEN) * 2, 4, 0x40, 1) + /* IAD 8 bytes */ + IAD_DESC(0) + /* CDC_ACM interfaces */ + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) + /* IAD 8 bytes */ + IAD_DESC(2) + /* CDC_ACM interfaces */ + CDC_IFC_DESC_ALL1(2, 0x86, 0x85, 0x04) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor 10 bytes */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor 9 bytes, total 75 bytes */ + CFG_DESC(CFG_DESC_LEN + IAD_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 0x60, 1) + /* IAD 8 bytes */ + IAD_DESC(0) + /* CDC_ACM interfaces */ + CDC_IFC_DESC_ALL1(0, 0x83, 0x81, 0x02) + /* IAD 8 bytes */ + IAD_DESC(2) + /* CDC_ACM interfaces */ + CDC_IFC_DESC_ALL(2, 0x86, 0x85, 0x04) +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT break_on_cdc_acm_all_ready(VOID) +{ + + if (cdc_acm_host_control == UX_NULL || cdc_acm_host_data == UX_NULL) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control1 == UX_NULL || cdc_acm_host_data1 == UX_NULL) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_host_data->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control1->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_host_data1->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_slave == UX_NULL || cdc_acm_slave1 == UX_NULL) + /* Do not break. */ + return 0; + + /* All found, break. */ + return 1; +} + +static UINT break_on_removal(VOID) +{ + + if (cdc_acm_host_control != UX_NULL || cdc_acm_host_data != UX_NULL) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control1 != UX_NULL || cdc_acm_host_data1 != UX_NULL) + /* Do not break. */ + return 0; + + if (cdc_acm_slave != UX_NULL || cdc_acm_slave1 != UX_NULL) + /* Do not break. */ + return 0; + + return 1; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + if (cdc_acm_host_control == UX_NULL) + cdc_acm_host_control = cdc_acm; + else + if (cdc_acm_host_control1 == UX_NULL) + cdc_acm_host_control1 = cdc_acm; + } + else + { + if (cdc_acm_host_data == UX_NULL) + cdc_acm_host_data = cdc_acm; + else + if (cdc_acm_host_data1 == UX_NULL) + cdc_acm_host_data1 = cdc_acm; + } + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + if (cdc_acm_host_control == cdc_acm) + cdc_acm_host_control = UX_NULL; + if (cdc_acm_host_control1 == cdc_acm) + cdc_acm_host_control1 = UX_NULL; + } + else + { + if (cdc_acm_host_data == cdc_acm) + cdc_acm_host_data = UX_NULL; + if (cdc_acm_host_data1 == cdc_acm) + cdc_acm_host_data1 = UX_NULL; + } + break; + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + if (cdc_acm_slave == UX_NULL) + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; + else + if (cdc_acm_slave1 == UX_NULL) + cdc_acm_slave1 = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + if ((VOID *)cdc_acm_slave == cdc_instance) + cdc_acm_slave = UX_NULL; + if ((VOID *)cdc_acm_slave1 == cdc_instance) + cdc_acm_slave1 = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + error_callback_counter ++; + + if (!error_callback_ignore) + { + /* Ignore UX_DEVICE_HANDLE_UNKNOWN. */ + if (UX_DEVICE_HANDLE_UNKNOWN == error_code) + return; + { + /* 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); + } + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_cdc_acm_ioctl_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + printf("Running ux_device_class_cdc_acm_ioctl Test.......................... "); + + /* Initialize the free memory pointer */ + stack_pointer = (CHAR *) first_unused_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register CDC ACM class */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_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); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,2, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,4, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#else + error_callback_ignore = UX_TRUE; /* One of interface fail. */ +#endif + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register HCD for test */ + 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(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_DONT_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_SLAVE_CLASS_CDC_ACM_LINE_STATE_PARAMETER line_state; +UX_SLAVE_CLASS_CDC_ACM_LINE_STATE_PARAMETER new_line_state; +UX_SLAVE_CLASS_CDC_ACM *slaves[2]; +UINT i; + + stepinfo("\n"); + + /* Test connect. */ + stepinfo(">>>>>>>>>>>>>>>> Test connect (FS)\n"); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + ux_test_breakable_sleep(500, break_on_cdc_acm_all_ready); + if (!(cdc_acm_host_control + && cdc_acm_host_data + && cdc_acm_slave +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + && cdc_acm_host_control1 + && cdc_acm_host_data1 + && cdc_acm_slave1 +#endif + )) + { + + printf("ERROR #%d: connect fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_STATE\n"); + + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_STATE, &line_state); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: ioctl_get_line_state error 0x%x\n", __LINE__, status); + error_counter ++; + } + + new_line_state.ux_slave_class_cdc_acm_parameter_dtr = !line_state.ux_slave_class_cdc_acm_parameter_dtr; + new_line_state.ux_slave_class_cdc_acm_parameter_rts = !line_state.ux_slave_class_cdc_acm_parameter_rts; + + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_STATE, &new_line_state); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: ioctl_set_line_state error 0x%x\n", __LINE__, status); + error_counter ++; + } + + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_STATE, &line_state); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: ioctl_get_line_state error 0x%x\n", __LINE__, status); + error_counter ++; + } + if (line_state.ux_slave_class_cdc_acm_parameter_dtr != new_line_state.ux_slave_class_cdc_acm_parameter_dtr) + { + printf("ERROR #%d: dtr error\n", __LINE__); + error_counter ++; + } + if (line_state.ux_slave_class_cdc_acm_parameter_rts != new_line_state.ux_slave_class_cdc_acm_parameter_rts) + { + printf("ERROR #%d: rts error\n", __LINE__); + error_counter ++; + } + + slaves[0] = cdc_acm_slave; + slaves[1] = cdc_acm_slave1; + + stepinfo(">>>>>>>>>>>>>>>> Test UX_SLAVE_CLASS_CDC_ACM_IOCTL_ABORT_PIPE no pending transfer\n"); + for (i = 0; i < 2; i ++) + { + status = ux_device_class_cdc_acm_ioctl(slaves[i], UX_SLAVE_CLASS_CDC_ACM_IOCTL_ABORT_PIPE, (VOID*)UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_XMIT); + status |= ux_device_class_cdc_acm_ioctl(slaves[i], UX_SLAVE_CLASS_CDC_ACM_IOCTL_ABORT_PIPE, (VOID*)UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_RCV); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: abort fail 0x%x\n", __LINE__, status); + error_counter ++; + } + + status = ux_device_class_cdc_acm_ioctl(slaves[i], UX_SLAVE_CLASS_CDC_ACM_IOCTL_ABORT_PIPE, (VOID*)0xFF); + if (status != UX_ENDPOINT_HANDLE_UNKNOWN) + { + printf("ERROR #%d: abort code not expected 0x%x\n", __LINE__, status); + error_counter ++; + } + } + + stepinfo(">>>>>>>>>>>>>>>> Test UX_SLAVE_CLASS_CDC_ACM_IOCTL_ABORT_PIPE pending transfer\n"); + + /* Start read on another thread. */ + test_slave_code = 1; + tx_thread_resume(&tx_test_thread_slave_simulation); + for (i = 0; i < 20; i ++) + { + if (test_slave_state) + break; + _ux_utility_delay_ms(5); + } + if (test_slave_state) + { + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_ABORT_PIPE, (VOID*)UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_RCV); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: abort fail 0x%x\n", __LINE__, status); + error_counter ++; + } + for (i = 0; i < 20; i ++) + { + if (test_slave_state == 0) + break; + _ux_utility_delay_ms(5); + } + if (test_slave_state != 0) + { + printf("ERROR #%d: read not aborted\n", __LINE__); + error_counter ++; + } + } + else + { + printf("ERROR #%d: read not started\n", __LINE__); + error_counter ++; + } +#if 0 /* TODO: USBX-177 */ + /* Start write on another thread. */ + test_slave_code = 2; + tx_thread_resume(&tx_test_thread_slave_simulation); + for (i = 0; i < 20; i ++) + { + if (test_slave_state) + break; + _ux_utility_delay_ms(5); + } + if (test_slave_state) + { + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_ABORT_PIPE, (VOID*)UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_XMIT); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: abort fail 0x%x\n", __LINE__, status); + error_counter ++; + } + for (i = 0; i < 20; i ++) + { + if (test_slave_state == 0) + break; + _ux_utility_delay_ms(5); + } + if (test_slave_state != 0) + { + printf("ERROR #%d: write not aborted\n", __LINE__); + error_counter ++; + } + } + else + { + printf("ERROR #%d: write not started\n", __LINE__); + error_counter ++; + } +#endif + stepinfo(">>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + ux_test_breakable_sleep(100, break_on_removal); + + if (cdc_acm_host_control || cdc_acm_host_data || cdc_acm_slave) + { + + printf("ERROR #%d: disconnect fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Deinitialize\n"); + + /* Deinitialize the class. */ + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + + /* Deinitialize the device side of usbx. */ + _ux_device_stack_uninitialize(); + + /* And finally the usbx system resources. */ + _ux_system_uninitialize(); + + stepinfo(">>>>>>>>>>>>>>>> Dump results\n"); + + if (error_counter > 0) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + +void tx_test_thread_slave_simulation_entry(ULONG arg) +{ +UINT status; +ULONG actual_length; + + while(1) + { + switch (test_slave_code) + { + case 1: + stepinfo(">>>>>>>>>>>>>>>> Slave read START\n"); + test_slave_state ++; + status = ux_device_class_cdc_acm_read(cdc_acm_slave, buffer, 256, &actual_length); + stepinfo(">>>>>>>>>>>>>>>> Slave read END\n"); + if (status != UX_ABORTED) + { + printf("ERROR #%d: read not abort 0x%x\n", __LINE__, status); + error_counter ++; + } + break; + case 2: + stepinfo(">>>>>>>>>>>>>>>> Slave write START\n"); + test_slave_state ++; + status = ux_device_class_cdc_acm_write(cdc_acm_slave, buffer, 1024, &actual_length); + stepinfo(">>>>>>>>>>>>>>>> Slave write END\n"); + if (status != UX_ABORTED) + { + printf("ERROR #%d: write not abort 0x%x\n", __LINE__, status); + error_counter ++; + } + break; + default: + break; + } + test_slave_state = 0; + tx_thread_suspend(&tx_test_thread_slave_simulation); + } +} diff --git a/test/regression/usbx_ux_device_class_cdc_acm_timeout_test.c b/test/regression/usbx_ux_device_class_cdc_acm_timeout_test.c new file mode 100644 index 00000000..29073ba0 --- /dev/null +++ b/test/regression/usbx_ux_device_class_cdc_acm_timeout_test.c @@ -0,0 +1,843 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" + +#include "ux_host_class_cdc_acm.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#include "ux_host_stack.h" + +/* Define constants. */ +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (96*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bmAttributes, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + (bmAttributes), 0x00, +#define CFG_DESC_LEN 9 + +#define IAD_DESC(bIfc) \ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (bIfc), 0x02, 0x02, 0x02, 0x00, 0x00, +#define IAD_DESC_LEN 8 + +#define CDC_IFC_DESC_ALL(bIfc, bIntIn, bBulkIn, bBulkOut)\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (bIfc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06, (bIfc), (bIfc + 1),\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03, (bIfc + 1),\ + /* Endpoint interrupt in descriptor 7 bytes */\ + 0x07, 0x05, (bIntIn), 0x03, 0x40, 0x00, 0x10,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (bIfc + 1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint bulk in descriptor 7 bytes */\ + 0x07, 0x05, (bBulkIn), 0x02, 0x40, 0x00, 0x01,\ + /* Endpoint bulk out descriptor 7 bytes */\ + 0x07, 0x05, (bBulkOut), 0x02, 0x40, 0x00, 0x01, +#define CDC_IFC_DESC_ALL1(bIfc, bIntIn, bBulkIn, bBulkOut)\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (bIfc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06, (bIfc), (bIfc + 1),\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03, (bIfc + 1),\ + /* Endpoint interrupt in descriptor 7 bytes */\ + 0x07, 0x05, (bIntIn), 0x03, 0x40, 0x00, 0x10,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (bIfc + 1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint bulk out descriptor 7 bytes */\ + 0x07, 0x05, (bBulkOut), 0x02, 0x40, 0x00, 0x01,\ + /* Endpoint bulk in descriptor 7 bytes */\ + 0x07, 0x05, (bBulkIn), 0x02, 0x40, 0x00, 0x01, +#define CDC_IFC_DESC_ALL_LEN (9+5+4+5+5+7+ 9+7+7) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); + +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control = UX_NULL; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data = UX_NULL; + +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control1 = UX_NULL; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data1 = UX_NULL; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave = UX_NULL; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave1 = UX_NULL; + +static UCHAR cdc_acm_slave_change; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; + +static ULONG error_counter; + +static ULONG error_callback_counter; +static UCHAR error_callback_ignore; + +static ULONG call_counter; + +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static UCHAR test_slave_code = 0; +static UCHAR test_slave_state = 0; + +/* Define device framework. */ + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Configuration 1 descriptor 9 bytes, total 75 bytes */ + CFG_DESC(CFG_DESC_LEN + (IAD_DESC_LEN + CDC_IFC_DESC_ALL_LEN) * 2, 4, 0x40, 1) + /* IAD 8 bytes */ + IAD_DESC(0) + /* CDC_ACM interfaces */ + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) + /* IAD 8 bytes */ + IAD_DESC(2) + /* CDC_ACM interfaces */ + CDC_IFC_DESC_ALL1(2, 0x86, 0x85, 0x04) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor 10 bytes */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor 9 bytes, total 75 bytes */ + CFG_DESC(CFG_DESC_LEN + IAD_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 0x60, 1) + /* IAD 8 bytes */ + IAD_DESC(0) + /* CDC_ACM interfaces */ + CDC_IFC_DESC_ALL1(0, 0x83, 0x81, 0x02) + /* IAD 8 bytes */ + IAD_DESC(2) + /* CDC_ACM interfaces */ + CDC_IFC_DESC_ALL(2, 0x86, 0x85, 0x04) +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT break_on_cdc_acm_all_ready(VOID) +{ + + if (cdc_acm_host_control == UX_NULL || cdc_acm_host_data == UX_NULL) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control1 == UX_NULL || cdc_acm_host_data1 == UX_NULL) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_host_data->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control1->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_host_data1->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_slave == UX_NULL || cdc_acm_slave1 == UX_NULL) + /* Do not break. */ + return 0; + + /* All found, break. */ + return 1; +} + +static UINT break_on_removal(VOID) +{ + + if (cdc_acm_host_control != UX_NULL || cdc_acm_host_data != UX_NULL) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control1 != UX_NULL || cdc_acm_host_data1 != UX_NULL) + /* Do not break. */ + return 0; + + if (cdc_acm_slave != UX_NULL || cdc_acm_slave1 != UX_NULL) + /* Do not break. */ + return 0; + + return 1; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + if (cdc_acm_host_control == UX_NULL) + cdc_acm_host_control = cdc_acm; + else + if (cdc_acm_host_control1 == UX_NULL) + cdc_acm_host_control1 = cdc_acm; + } + else + { + if (cdc_acm_host_data == UX_NULL) + cdc_acm_host_data = cdc_acm; + else + if (cdc_acm_host_data1 == UX_NULL) + cdc_acm_host_data1 = cdc_acm; + } + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + if (cdc_acm_host_control == cdc_acm) + cdc_acm_host_control = UX_NULL; + if (cdc_acm_host_control1 == cdc_acm) + cdc_acm_host_control1 = UX_NULL; + } + else + { + if (cdc_acm_host_data == cdc_acm) + cdc_acm_host_data = UX_NULL; + if (cdc_acm_host_data1 == cdc_acm) + cdc_acm_host_data1 = UX_NULL; + } + break; + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + if (cdc_acm_slave == UX_NULL) + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; + else + if (cdc_acm_slave1 == UX_NULL) + cdc_acm_slave1 = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + if ((VOID *)cdc_acm_slave == cdc_instance) + cdc_acm_slave = UX_NULL; + if ((VOID *)cdc_acm_slave1 == cdc_instance) + cdc_acm_slave1 = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + error_callback_counter ++; + + if (!error_callback_ignore) + { + /* Ignore UX_DEVICE_HANDLE_UNKNOWN. */ + if (UX_DEVICE_HANDLE_UNKNOWN == error_code) + return; + { + /* Failed test. */ + printf("#%d, system_level: %d, system_context: %d, error_code: 0x%x\n", __LINE__, system_level, system_context, error_code); + // 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_device_class_cdc_acm_timeout_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + +#if UX_MAX_SLAVE_CLASS_DRIVER == 1 + printf("Running ux_device_class_cdc_acm_timeout Test....................SKIP SUCCESS!\n"); + test_control_return(0); + return; +#else + printf("Running ux_device_class_cdc_acm_timeout Test........................ "); +#endif + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register CDC ACM class */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_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); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,2, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,4, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#endif + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + error_callback_ignore = UX_TRUE; /* One of interface fail. */ +#endif + + /* Register HCD for test */ + 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(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_DONT_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UINT i; +UX_SLAVE_ENDPOINT *slave_endpoint; +ULONG actual_length; + + + stepinfo("\n"); + + /* Test connect. */ + stepinfo(">>>>>>>>>>>>>>>> Test connect (FS)\n"); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + ux_test_breakable_sleep(500, break_on_cdc_acm_all_ready); + if (!(cdc_acm_host_control + && cdc_acm_host_data + && cdc_acm_slave +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + && cdc_acm_host_control1 + && cdc_acm_host_data1 + && cdc_acm_slave1 +#endif + )) + { + + printf("ERROR #%d: connect fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test slave read without timeout\n"); + test_slave_code = 1; + _ux_utility_thread_resume(&tx_test_thread_slave_simulation); + _ux_utility_delay_ms(10); + if (test_slave_state > 1) + { + printf("ERROR #%d: read not pending\n", __LINE__); + test_control_return(1); + } + if (test_slave_state < 1) + { + printf("ERROR #%d: read not started\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test slave set read timeout (fail)\n"); + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_READ_TIMEOUT, (VOID *)10); + if (status != UX_ERROR) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test slave set read timeout (fail)\n"); + slave_endpoint = cdc_acm_slave->ux_slave_class_cdc_acm_interface->ux_slave_interface_first_endpoint; + cdc_acm_slave->ux_slave_class_cdc_acm_interface->ux_slave_interface_first_endpoint = slave_endpoint->ux_slave_endpoint_next_endpoint; + cdc_acm_slave->ux_slave_class_cdc_acm_interface->ux_slave_interface_first_endpoint->ux_slave_endpoint_next_endpoint = slave_endpoint; + slave_endpoint->ux_slave_endpoint_next_endpoint = UX_NULL; + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_READ_TIMEOUT, (VOID *)10); + if (status != UX_ERROR) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + slave_endpoint = cdc_acm_slave->ux_slave_class_cdc_acm_interface->ux_slave_interface_first_endpoint; + cdc_acm_slave->ux_slave_class_cdc_acm_interface->ux_slave_interface_first_endpoint = slave_endpoint->ux_slave_endpoint_next_endpoint; + cdc_acm_slave->ux_slave_class_cdc_acm_interface->ux_slave_interface_first_endpoint->ux_slave_endpoint_next_endpoint = slave_endpoint; + slave_endpoint->ux_slave_endpoint_next_endpoint = UX_NULL; + + stepinfo(">>>>>>>>>>>>>>>> Test slave read abort\n"); + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_ABORT_PIPE, (VOID *)UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_RCV); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_utility_delay_ms(10); + if (test_slave_state < 2) + { + printf("ERROR #%d: read not aborted\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test slave write without timeout\n"); + test_slave_code = 2; + _ux_utility_thread_resume(&tx_test_thread_slave_simulation); + _ux_utility_delay_ms(10); + if (test_slave_state > 1) + { + printf("ERROR #%d: write not pending\n", __LINE__); + test_control_return(1); + } + if (test_slave_state < 1) + { + printf("ERROR #%d: write not started\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test slave set write timeout (fail)\n"); + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_WRITE_TIMEOUT, (VOID *)10); + if (status != UX_ERROR) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test slave set write timeout (fail)\n"); + slave_endpoint = cdc_acm_slave->ux_slave_class_cdc_acm_interface->ux_slave_interface_first_endpoint; + cdc_acm_slave->ux_slave_class_cdc_acm_interface->ux_slave_interface_first_endpoint = slave_endpoint->ux_slave_endpoint_next_endpoint; + cdc_acm_slave->ux_slave_class_cdc_acm_interface->ux_slave_interface_first_endpoint->ux_slave_endpoint_next_endpoint = slave_endpoint; + slave_endpoint->ux_slave_endpoint_next_endpoint = UX_NULL; + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_WRITE_TIMEOUT, (VOID *)10); + if (status != UX_ERROR) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + slave_endpoint = cdc_acm_slave->ux_slave_class_cdc_acm_interface->ux_slave_interface_first_endpoint; + cdc_acm_slave->ux_slave_class_cdc_acm_interface->ux_slave_interface_first_endpoint = slave_endpoint->ux_slave_endpoint_next_endpoint; + cdc_acm_slave->ux_slave_class_cdc_acm_interface->ux_slave_interface_first_endpoint->ux_slave_endpoint_next_endpoint = slave_endpoint; + slave_endpoint->ux_slave_endpoint_next_endpoint = UX_NULL; + + stepinfo(">>>>>>>>>>>>>>>> Test slave write abort\n"); + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_ABORT_PIPE, (VOID *)UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_XMIT); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: fail, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_utility_delay_ms(10); + if (test_slave_state < 2) + { + printf("ERROR #%d: write not aborted\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test slave read/write with timeout\n"); + test_slave_code = 3; + _ux_utility_thread_resume(&tx_test_thread_slave_simulation); + for (i = 0; i < 100; i ++) + { + _ux_utility_delay_ms(10); + if (test_slave_state >= 1) + break; + } + stepinfo(" Step after %d x 10 ms\n", i); + for (i = 0; i < 100; i ++) + { + _ux_utility_delay_ms(10); + if (test_slave_state >= 2) + break; + } + stepinfo(" Step after %d x 10 ms\n", i); + for (i = 0; i < 100; i ++) + { + _ux_utility_delay_ms(10); + if (test_slave_state >= 3) + break; + } + stepinfo(" Step after %d x 10 ms\n", i); + if (test_slave_state < 3) + { + printf("ERROR #%d: slave operation not end\n", __LINE__); + error_counter ++; + } + + stepinfo(">>>>>>>>>>>>>>>> Test slave read with timeout success\n"); + test_slave_code = 4; + _ux_utility_thread_resume(&tx_test_thread_slave_simulation); + status = ux_host_class_cdc_acm_write(cdc_acm_host_data, buffer, 1, &actual_length); + test_slave_code = 4; + _ux_utility_thread_resume(&tx_test_thread_slave_simulation); + status = ux_host_class_cdc_acm_write(cdc_acm_host_data, buffer, 256, &actual_length); + test_slave_code = 4; + _ux_utility_thread_resume(&tx_test_thread_slave_simulation); + status = ux_host_class_cdc_acm_write(cdc_acm_host_data, buffer, 250, &actual_length); + + stepinfo(">>>>>>>>>>>>>>>> Test slave write with timeout success\n"); + test_slave_code = 5; + _ux_utility_thread_resume(&tx_test_thread_slave_simulation); + status = ux_host_class_cdc_acm_read(cdc_acm_host_data, buffer, 1, &actual_length); + test_slave_code = 5; + _ux_utility_thread_resume(&tx_test_thread_slave_simulation); + status = ux_host_class_cdc_acm_read(cdc_acm_host_data, buffer, 1023, &actual_length); + test_slave_code = 5; + _ux_utility_thread_resume(&tx_test_thread_slave_simulation); +#if !defined(UX_DEVICE_CLASS_CDC_ACM_WRITE_AUTO_ZLP) + status = ux_host_class_cdc_acm_read(cdc_acm_host_data, buffer, 1024, &actual_length); +#else + /* Read as much as we can, device pending ZLP to terminate. */ + status = ux_host_class_cdc_acm_read(cdc_acm_host_data, buffer, sizeof(buffer), &actual_length); +#endif + + stepinfo(">>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + ux_test_breakable_sleep(100, break_on_removal); + + if (cdc_acm_host_control || cdc_acm_host_data || cdc_acm_slave) + { + + printf("ERROR #%d: disconnect fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Deinitialize\n"); + + /* Deinitialize the class. */ + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + + /* Deinitialize the device side of usbx. */ + _ux_device_stack_uninitialize(); + + /* And finally the usbx system resources. */ + _ux_system_uninitialize(); + + stepinfo(">>>>>>>>>>>>>>>> Dump results\n"); + + if (error_counter > 0) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + +void tx_test_thread_slave_simulation_entry(ULONG arg) +{ +UINT status; +ULONG actual_length; + + while(1) + { + switch (test_slave_code) + { + case 1: + case 4: + stepinfo(">>>>>>>>>>>>>>>> Slave read START%s\n", test_slave_code == 1 ? "(no timeout)" : ""); + test_slave_state ++; + status = ux_device_class_cdc_acm_read(cdc_acm_slave, buffer, 256, &actual_length); + test_slave_state ++; + stepinfo(">>>>>>>>>>>>>>>> Slave read END: 0x%x, %ld\n", status, actual_length); + if (status != (test_slave_code == 1 ? UX_ABORTED : UX_SUCCESS)) + { + printf("ERROR #%d: read code 0x%x\n", __LINE__, status); + error_counter ++; + } + break; + + case 2: + case 5: + stepinfo(">>>>>>>>>>>>>>>> Slave write START%s\n", test_slave_code == 2 ? "(no timeout)" : ""); + test_slave_state ++; + status = ux_device_class_cdc_acm_write(cdc_acm_slave, buffer, 1024, &actual_length); + test_slave_state ++; + stepinfo(">>>>>>>>>>>>>>>> Slave write END: 0x%x, %ld\n", status, actual_length); + if (status != (test_slave_code == 2 ? UX_ABORTED : UX_SUCCESS)) + { + printf("ERROR #%d: test %x, write code 0x%x\n", __LINE__, test_slave_code, status); + error_counter ++; + } + break; + + case 3: + stepinfo(">>>>>>>>>>>>>>>> Slave set read/write timeout\n"); + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_READ_TIMEOUT, (VOID *)10); + status |= ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_WRITE_TIMEOUT, (VOID *)10); + test_slave_state ++; + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + error_counter ++; + } + + stepinfo(">>>>>>>>>>>>>>>> Slave write START\n"); + status = ux_device_class_cdc_acm_write(cdc_acm_slave, buffer, 1024, &actual_length); + test_slave_state ++; + stepinfo(">>>>>>>>>>>>>>>> Slave write END\n"); + if (status == UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + error_counter ++; + } + stepinfo(">>>>>>>>>>>>>>>> Slave read START\n"); + status = ux_device_class_cdc_acm_read(cdc_acm_slave, buffer, 1024, &actual_length); + test_slave_state ++; + stepinfo(">>>>>>>>>>>>>>>> Slave read END\n"); + if (status == UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + error_counter ++; + } + break; + + default: + break; + } + tx_thread_suspend(&tx_test_thread_slave_simulation); + test_slave_state = 0; + } +} diff --git a/test/regression/usbx_ux_device_class_cdc_acm_transmission_test.c b/test/regression/usbx_ux_device_class_cdc_acm_transmission_test.c new file mode 100644 index 00000000..d393e80a --- /dev/null +++ b/test/regression/usbx_ux_device_class_cdc_acm_transmission_test.c @@ -0,0 +1,1293 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" + +#include "ux_host_class_cdc_acm.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#include "ux_host_stack.h" + +/* Define constants. */ +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +#define CDC_IFC_DESC_ALL(bIfc, bIntIn, bBulkIn, bBulkOut)\ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (bIfc), 0x02, 0x02, 0x02, 0x00, 0x00,\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (bIfc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06, (bIfc), (bIfc + 1),\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03, (bIfc + 1),\ + /* Endpoint interrupt in descriptor 7 bytes */\ + 0x07, 0x05, (bIntIn), 0x02, 0x40, 0x00, 0x00,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (bIfc + 1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint bulk out descriptor 7 bytes */\ + 0x07, 0x05, (bBulkOut), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint bulk in descriptor 7 bytes */\ + 0x07, 0x05, (bBulkIn), 0x02, 0x40, 0x00, 0x00, +#define CDC_IFC_DESC_ALL_LEN (8+ 9+5+4+5+5+7+ 9+7+7) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); + void tx_test_thread_dummy_entry(ULONG arg); +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +static UCHAR cdc_acm_slave_change; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; + +static ULONG error_counter; + +static ULONG error_callback_counter; +static UCHAR error_callback_ignore; + +static TX_SEMAPHORE slave_read_semaphore; +static UINT slave_read_status; +static ULONG slave_read_length; +static ULONG slave_read_counter; +static struct { + UCHAR *buffer; + UCHAR *save2; + ULONG length; + UINT status; +} slave_read_log[32]; +static TX_SEMAPHORE slave_write_semaphore; +static UINT slave_write_status; +static ULONG slave_write_length; + +static UCHAR buffer[1024]; +static UCHAR host_buffer[1024]; + +static ULONG actions_2_set_trigger = ~0; +static UX_TEST_HCD_SIM_ACTION *actions_2_set = UX_NULL; + +/* Define device framework. */ + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Configuration 1 descriptor 9 bytes, total 75 bytes */ + CFG_DESC(CFG_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 1) + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor 9 bytes, total 75 bytes */ + CFG_DESC(CFG_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 1) + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +static UX_TEST_HCD_SIM_ACTION error_on_transfer0[] = { +/* 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_DCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER, 0, UX_NULL, 0, UX_ERROR, + UX_ERROR}, /* Error */ +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION error_on_transfer1[] = { +/* 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_DCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER, 0, UX_NULL, 0, UX_ERROR, + UX_SUCCESS}, /* Completion code error */ +{ UX_DCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER, 0, UX_NULL, 0, UX_ERROR, + UX_ERROR}, /* Error */ +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT break_on_cdc_acm_all_ready(VOID) +{ +UINT status; +UX_HOST_CLASS *class; + + /* Find the main cdc_acm container */ + status = ux_host_stack_class_get(_ux_system_host_class_cdc_acm_name, &class); + if (status != UX_SUCCESS) + /* Do not break. */ + return 0; + + /* Find class instance. */ + status = ux_host_stack_class_instance_get(class, 0, (void **) &cdc_acm_host_control); + if (status != UX_SUCCESS) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + /* Find class instance. */ + status = ux_host_stack_class_instance_get(class, 1, (void **) &cdc_acm_host_data); + if (status != UX_SUCCESS) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_slave == UX_NULL) + /* Do not break. */ + return 0; + + /* All found, break. */ + return 1; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; +} + +static VOID test_ux_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); + } + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_cdc_acm_transmission_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +ULONG rmem_free; + + + printf("Running ux_device_class_cdc_acm_ transmission Test.................. "); +#ifdef UX_DEVICE_CLASS_CDC_ACM_TRANSMISSION_DISABLE + printf("Skipped\n"); + test_control_return(0); + return; +#endif + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register CDC ACM class */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_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); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + +#if 1 /* Resources management moved to initialize/uninitialize */ + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1, 0, ¶meter); + if(status!=UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + if(status!=UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + error_callback_ignore = UX_TRUE; + rmem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + stepinfo(">>>>>>>>>>>>>>>> Test device init TRANSMISSION stack fail\n"); + ux_test_utility_sim_mem_allocate_until_flagged(sizeof(UX_SLAVE_CLASS_CDC_ACM) + UX_THREAD_STACK_SIZE, UX_REGULAR_MEMORY); + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1, 0, ¶meter); + UX_TEST_ASSERT(status == UX_MEMORY_INSUFFICIENT); + ux_test_utility_sim_mem_free_all(); + + stepinfo(">>>>>>>>>>>>>>>> Test device init TRANSMISSION flag fail\n"); + ux_test_utility_sim_event_create_count_reset(); + ux_test_utility_sim_event_error_generation_start(0); + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1, 0, ¶meter); + if (status != UX_EVENT_ERROR) + { + printf("ERROR #%d: stack alloc fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + ux_test_utility_sim_event_error_generation_stop(); + + stepinfo(">>>>>>>>>>>>>>>> Test device init TRANSMISSION bulkin thread fail\n"); + ux_test_utility_sim_thread_create_count_reset(); + ux_test_utility_sim_thread_error_generation_start(0); + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1, 0, ¶meter); + if (status != UX_THREAD_ERROR) + { + printf("ERROR #%d: thread create fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test device init TRANSMISSION bulkout thread fail\n"); + ux_test_utility_sim_thread_create_count_reset(); + ux_test_utility_sim_thread_error_generation_start(1); + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1, 0, ¶meter); + if (status != UX_THREAD_ERROR) + { + printf("ERROR #%d: thread create fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + ux_test_utility_sim_thread_error_generation_stop(); + + /* Check memory leak. */ + if (rmem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + printf("ERROR #%d: memory level changed %ld <> %ld\n", __LINE__, rmem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + error_callback_ignore = UX_TRUE; +#endif + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1, 0, ¶meter); + + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register HCD for test */ + 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(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_CDC_ACM_LINE_STATE line_state; +ULONG actual_length; + + + stepinfo(">>>>>>>>>>>>>>>> Test host wait\n"); + _ux_utility_thread_suspend(&tx_test_thread_host_simulation); + + /* Test connect. */ + stepinfo(">>>>>>>>>>>>>>>> Test host connect\n"); + ux_test_breakable_sleep(100, break_on_cdc_acm_all_ready); + if (!(cdc_acm_host_control && cdc_acm_host_data && cdc_acm_slave)) + { + + printf("ERROR #%d: connect fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test host set DTR\n"); + line_state.ux_host_class_cdc_acm_line_state_dtr = 1; + line_state.ux_host_class_cdc_acm_line_state_rts = 1; + status = ux_host_class_cdc_acm_ioctl(cdc_acm_host_control, UX_HOST_CLASS_CDC_ACM_IOCTL_SET_LINE_STATE, &line_state); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_utility_thread_suspend(&tx_test_thread_host_simulation); + + stepinfo(">>>>>>>>>>>>>>>> Test host write 1, to move slave bulk OUT thread\n"); + status = ux_host_class_cdc_acm_write(cdc_acm_host_data, host_buffer, 1, &actual_length); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_utility_thread_suspend(&tx_test_thread_host_simulation); + + stepinfo(">>>>>>>>>>>>>>>> Test host read 64, expect 1\n"); + status = ux_host_class_cdc_acm_read(cdc_acm_host_data, host_buffer, 64, &actual_length); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (actual_length != 1) + { + printf("ERROR #%d: length %ld\n", __LINE__, actual_length); + test_control_return(1); + } + if (_ux_utility_memory_compare(buffer, host_buffer, 1) != UX_SUCCESS) + { + printf("ERROR #%d: data error\n", __LINE__); + test_control_return(1); + } + _ux_utility_thread_suspend(&tx_test_thread_host_simulation); + + stepinfo(">>>>>>>>>>>>>>>> Test host read 512, expect 128 (ZLP)\n"); + status = ux_host_class_cdc_acm_read(cdc_acm_host_data, host_buffer, 512, &actual_length); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (actual_length != 128) + { + printf("ERROR #%d: length %ld\n", __LINE__, actual_length); + test_control_return(1); + } + if (_ux_utility_memory_compare(buffer, host_buffer, 128) != UX_SUCCESS) + { + printf("ERROR #%d: data error\n", __LINE__); + test_control_return(1); + } + _ux_utility_thread_suspend(&tx_test_thread_host_simulation); + + stepinfo(">>>>>>>>>>>>>>>> Test host write 64+1\n"); + _ux_utility_memory_set(host_buffer, 64+1, 64+1); + _ux_utility_memory_set(buffer, 0, 64+1); + status = ux_host_class_cdc_acm_write(cdc_acm_host_data, host_buffer, 64+1, &actual_length); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (actual_length != 64+1) + { + printf("ERROR #%d: length %ld\n", __LINE__, actual_length); + test_control_return(1); + } + _ux_utility_thread_suspend(&tx_test_thread_host_simulation); + + stepinfo(">>>>>>>>>>>>>>>> Test host write 1\n"); + ux_host_class_cdc_acm_write(cdc_acm_host_data, host_buffer, 1, &actual_length); + _ux_utility_thread_suspend(&tx_test_thread_host_simulation); + + stepinfo(">>>>>>>>>>>>>>>> Test host write 1\n"); + ux_host_class_cdc_acm_write(cdc_acm_host_data, host_buffer, 1, &actual_length); + _ux_utility_thread_suspend(&tx_test_thread_host_simulation); + + stepinfo(">>>>>>>>>>>>>>>> Deinitialize\n"); + + /* Deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + + /* Deinitialize the device side of usbx. */ + _ux_device_stack_uninitialize(); + + /* And finally the usbx system resources. */ + _ux_system_uninitialize(); + + stepinfo(">>>>>>>>>>>>>>>> Dump results\n"); + + if (error_counter > 0) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + +UINT tx_demo_thread_slave_read_callback(UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave, UINT status, UCHAR *data_pointer, ULONG length) +{ + if (slave_read_counter < 32) + { + slave_read_log[slave_read_counter].buffer = data_pointer; + slave_read_log[slave_read_counter].length = length; + slave_read_log[slave_read_counter].status = status; + if (slave_read_log[slave_read_counter].save2) + ux_utility_memory_copy(slave_read_log[slave_read_counter].save2, data_pointer,length); + } + slave_read_counter ++; + + if (actions_2_set_trigger != (~0)) + { + if (slave_read_counter == actions_2_set_trigger) + { + ux_test_dcd_sim_slave_set_actions(actions_2_set); + slave_read_counter = 0; + actions_2_set = UX_NULL; + actions_2_set_trigger = ~0; + } + + } + + /* Save the status. */ + slave_read_status = status; + slave_read_length = length; + + /* Copy the data in local buffer. */ + ux_utility_memory_copy(buffer, data_pointer,length); + + /* Put a semaphore. This will wake up the host. */ + _ux_utility_semaphore_put(&slave_read_semaphore); + + /* Done here. */ + return(UX_SUCCESS); +} + + +UINT tx_demo_thread_slave_write_callback(UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave, UINT status, ULONG length) +{ + + /* Save the status. */ + slave_write_status = status; + slave_write_length = length; + + /* Confirmation of the end of transmission. */ + _ux_utility_semaphore_put(&slave_write_semaphore); + + /* Done here. */ + return(UX_SUCCESS); +} + +void tx_test_thread_dummy_entry(ULONG arg) +{ + _ux_utility_thread_suspend(_ux_utility_thread_identify()); +} + +void tx_test_thread_slave_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG actual_length; +UX_SLAVE_CLASS_CDC_ACM_LINE_STATE_PARAMETER line_state; +UX_SLAVE_CLASS_CDC_ACM_CALLBACK_PARAMETER callback; +UINT i; +ULONG rmem_free; +ALIGN_TYPE tmp; +UX_SLAVE_INTERFACE *interface; + + + /* Test device. */ + stepinfo(">>>>>>>>>>>>>>>> Test device connect\n"); + ux_test_breakable_sleep(200, break_on_cdc_acm_all_ready); + if (!(cdc_acm_host_control && cdc_acm_host_data && cdc_acm_slave)) + { + printf("ERROR #%d: connect fail\n", __LINE__); + test_control_return(1); + } + +#ifndef UX_DEVICE_CLASS_CDC_ACM_TRANSMISSION_DISABLE + + stepinfo(">>>>>>>>>>>>>>>> Test device DTR state to start transmission\n"); + line_state.ux_slave_class_cdc_acm_parameter_dtr = 0; + line_state.ux_slave_class_cdc_acm_parameter_rts = 0; + ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_STATE, &line_state); + _ux_utility_thread_resume(&tx_test_thread_host_simulation); + for (i = 0; i < 20; i ++) + { + _ux_utility_delay_ms(25); + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_STATE, &line_state); + if (status != UX_SUCCESS) + break; + if (line_state.ux_slave_class_cdc_acm_parameter_dtr) + break; + } + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_STATE fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (line_state.ux_slave_class_cdc_acm_parameter_dtr != UX_TRUE) + { + + printf("ERROR #%d: DTR not set\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test device ioctl UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START\n"); + + /* Set the callback parameter. */ + callback.ux_device_class_cdc_acm_parameter_write_callback = tx_demo_thread_slave_write_callback; + callback.ux_device_class_cdc_acm_parameter_read_callback = tx_demo_thread_slave_read_callback; + + /* Create the semaphore to synchronize with reception. */ + status = _ux_utility_semaphore_create(&slave_read_semaphore, "slave_read_semaphore", 0); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: slave_read_semaphore fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Create the semaphore to synchronize with transmission. */ + status = _ux_utility_semaphore_create(&slave_write_semaphore, "slave_write_semaphore", 0); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: slave_write_semaphore fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + + error_callback_ignore = UX_TRUE; + rmem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + stepinfo(">>>>>>>>>>>>>>>> Test device ioctl UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START status fail\n"); + cdc_acm_slave->ux_slave_class_cdc_acm_transmission_status = UX_TRUE; + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START, &callback); + if (status != UX_ERROR) + { + printf("ERROR #%d: stack alloc fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + cdc_acm_slave->ux_slave_class_cdc_acm_transmission_status = UX_FALSE; + +#if 0 /* Resources management moved to initialize/uninitialize */ + stepinfo(">>>>>>>>>>>>>>>> Test device ioctl UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START bulkout stack fail\n"); + ux_test_utility_sim_mem_allocate_until_flagged(UX_THREAD_STACK_SIZE, UX_REGULAR_MEMORY); + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START, &callback); + if (status != UX_MEMORY_INSUFFICIENT) + { + printf("ERROR #%d: stack alloc fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + ux_test_utility_sim_mem_free_all(); + + stepinfo(">>>>>>>>>>>>>>>> Test device ioctl UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START bulkin stack fail\n"); + ux_test_utility_sim_mem_allocate_until_flagged(2 * UX_THREAD_STACK_SIZE, UX_REGULAR_MEMORY); + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START, &callback); + if (status != UX_MEMORY_INSUFFICIENT) + { + printf("ERROR #%d: stack alloc fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + ux_test_utility_sim_mem_free_all(); + + stepinfo(">>>>>>>>>>>>>>>> Test device ioctl UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START flag fail\n"); + _ux_utility_event_flags_create(&cdc_acm_slave->ux_slave_class_cdc_acm_event_flags_group, "test"); + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START, &callback); + if (status != UX_EVENT_ERROR) + { + printf("ERROR #%d: stack alloc fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_utility_event_flags_delete(&cdc_acm_slave->ux_slave_class_cdc_acm_event_flags_group); + + stepinfo(">>>>>>>>>>>>>>>> Test device ioctl UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START bulkin thread fail\n"); + _ux_utility_thread_create(&cdc_acm_slave->ux_slave_class_cdc_acm_bulkin_thread, "test", + tx_test_thread_dummy_entry, + (ULONG)(ALIGN_TYPE)cdc_acm_slave, (VOID *)buffer, + UX_THREAD_STACK_SIZE, UX_THREAD_PRIORITY_CLASS, + UX_THREAD_PRIORITY_CLASS, UX_NO_TIME_SLICE, TX_DONT_START); + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START, &callback); + if (status != UX_THREAD_ERROR) + { + printf("ERROR #%d: thread create fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_utility_thread_delete(&cdc_acm_slave->ux_slave_class_cdc_acm_bulkin_thread); + + stepinfo(">>>>>>>>>>>>>>>> Test device ioctl UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START bulkout thread fail\n"); + _ux_utility_thread_create(&cdc_acm_slave->ux_slave_class_cdc_acm_bulkout_thread, "test", + tx_test_thread_dummy_entry, + (ULONG)(ALIGN_TYPE)cdc_acm_slave, (VOID *)buffer, + UX_THREAD_STACK_SIZE, UX_THREAD_PRIORITY_CLASS, + UX_THREAD_PRIORITY_CLASS, UX_NO_TIME_SLICE, TX_DONT_START); + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START, &callback); + if (status != UX_THREAD_ERROR) + { + printf("ERROR #%d: thread create fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_utility_thread_delete(&cdc_acm_slave->ux_slave_class_cdc_acm_bulkout_thread); +#endif + + /* Check memory leak. */ + if (rmem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + printf("ERROR #%d: memory level changed %ld <> %ld\n", __LINE__, rmem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + error_callback_ignore = UX_TRUE; + + stepinfo(">>>>>>>>>>>>>>>> Test device ioctl UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START good\n"); + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START, &callback); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test device read/write on transmission mode\n"); + + status = ux_device_class_cdc_acm_read(cdc_acm_slave, buffer, 64, &actual_length); + if (status != UX_ERROR) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + status = ux_device_class_cdc_acm_write(cdc_acm_slave, buffer, 64, &actual_length); + if (status != UX_ERROR) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test device write_with_callback\n"); + status = ux_device_class_cdc_acm_write_with_callback(cdc_acm_slave, buffer, 64); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test device write_with_callback busy\n"); + status = ux_device_class_cdc_acm_write_with_callback(cdc_acm_slave, buffer, 64); + if (status != UX_ERROR) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test device write_with_callback state fail\n"); + error_callback_ignore = UX_TRUE; + tmp = _ux_system_slave->ux_system_slave_device.ux_slave_device_state; + _ux_system_slave->ux_system_slave_device.ux_slave_device_state = UX_DEVICE_ADDRESSED; + status = ux_device_class_cdc_acm_write_with_callback(cdc_acm_slave, buffer, 64); + if (status != UX_CONFIGURATION_HANDLE_UNKNOWN) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Wait a while to let threads run. */ + _ux_utility_delay_ms(20); + + /* Push the bulkout thread so it runs to check status. */ + _ux_utility_thread_resume(&tx_test_thread_host_simulation); + _ux_utility_thread_resume(&cdc_acm_slave->ux_slave_class_cdc_acm_bulkout_thread); + _ux_utility_delay_ms(20); + _ux_utility_thread_resume(&cdc_acm_slave->ux_slave_class_cdc_acm_bulkout_thread); + + _ux_system_slave->ux_system_slave_device.ux_slave_device_state = (ULONG)tmp; + error_callback_ignore = UX_FALSE; + + /* Wait a while to let threads run. */ + _ux_utility_delay_ms(20); + + stepinfo(">>>>>>>>>>>>>>>> Test device ioctl UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_STOP\n"); + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_STOP, UX_NULL); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_STOP fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test device ioctl UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_STOP when stopped\n"); + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_STOP, UX_NULL); + if (status != UX_ERROR) + { + printf("ERROR #%d: UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_STOP fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test device write_with_callback wrong mode\n"); + status = ux_device_class_cdc_acm_write_with_callback(cdc_acm_slave, buffer, 64); + if (status != UX_ERROR) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test device transmission\n"); + + /* Swap endpoints. */ + interface = cdc_acm_slave->ux_slave_class_cdc_acm_interface; + tmp = (ALIGN_TYPE)interface->ux_slave_interface_first_endpoint; + interface->ux_slave_interface_first_endpoint = interface->ux_slave_interface_first_endpoint->ux_slave_endpoint_next_endpoint; + interface->ux_slave_interface_first_endpoint->ux_slave_endpoint_next_endpoint = (UX_SLAVE_ENDPOINT*)tmp; + interface->ux_slave_interface_first_endpoint->ux_slave_endpoint_next_endpoint->ux_slave_endpoint_next_endpoint = UX_NULL; + + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START, &callback); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test device transmission unconfigued\n"); + tmp = _ux_system_slave->ux_system_slave_device.ux_slave_device_state; + _ux_system_slave->ux_system_slave_device.ux_slave_device_state = UX_DEVICE_ADDRESSED; + _ux_utility_thread_resume(&cdc_acm_slave->ux_slave_class_cdc_acm_bulkin_thread); + _ux_utility_thread_resume(&cdc_acm_slave->ux_slave_class_cdc_acm_bulkout_thread); + _ux_utility_delay_ms(10); + _ux_system_slave->ux_system_slave_device.ux_slave_device_state = (ULONG)tmp; + + stepinfo(">>>>>>>>>>>>>>>> Test device transmission event flags error\n"); + _ux_utility_event_flags_delete(&cdc_acm_slave->ux_slave_class_cdc_acm_event_flags_group); + _ux_utility_thread_resume(&cdc_acm_slave->ux_slave_class_cdc_acm_bulkin_thread); + _ux_utility_delay_ms(10); + _ux_utility_event_flags_create(&cdc_acm_slave->ux_slave_class_cdc_acm_event_flags_group, "ux_device_class_cdc_acm_event_flag"); + + stepinfo(">>>>>>>>>>>>>>>> Test device transmission event flags not expected\n"); + _ux_utility_thread_resume(&cdc_acm_slave->ux_slave_class_cdc_acm_bulkin_thread); + _ux_utility_event_flags_set(&cdc_acm_slave->ux_slave_class_cdc_acm_event_flags_group, UX_DEVICE_CLASS_CDC_ACM_WRITE_EVENT << 1, TX_OR); + _ux_utility_event_flags_set(&cdc_acm_slave->ux_slave_class_cdc_acm_event_flags_group, UX_DEVICE_CLASS_CDC_ACM_WRITE_EVENT, TX_OR); + _ux_utility_delay_ms(10); + + stepinfo(">>>>>>>>>>>>>>>> Test device ioctl UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION _STOP & _START\n"); + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_STOP, UX_NULL); + status |= ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START, &callback); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION _STOP or _START fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_utility_delay_ms(10); + status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_STOP, UX_NULL); + status |= ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_START, &callback); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION _STOP or _START fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + while(slave_write_semaphore.tx_semaphore_count) + _ux_utility_semaphore_get(&slave_write_semaphore, 0); + + stepinfo(">>>>>>>>>>>>>>>> Test device _ux_device_class_cdc_acm_write_with_callback 1\n"); + host_buffer[0] = 0; + buffer[0] = '1'; + _ux_utility_thread_resume(&tx_test_thread_host_simulation); + status = ux_device_class_cdc_acm_write_with_callback(cdc_acm_slave, buffer, 1); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _ux_utility_semaphore_get(&slave_write_semaphore, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (slave_write_status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, slave_write_status); + test_control_return(1); + } + if (slave_write_length != 1) + { + printf("ERROR #%d: length %ld\n", __LINE__, slave_write_length); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test device _ux_device_class_cdc_acm_write_with_callback 128\n"); + _ux_utility_memory_set(buffer, 128, 128); + _ux_utility_memory_set(host_buffer, 0, 512); + _ux_utility_memory_set(&buffer[128], '1', 512-128); + _ux_utility_thread_resume(&tx_test_thread_host_simulation); + status = ux_device_class_cdc_acm_write_with_callback(cdc_acm_slave, buffer, 128); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _ux_utility_semaphore_get(&slave_write_semaphore, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (slave_write_status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, slave_write_status); + test_control_return(1); + } + if (slave_write_length != 128) + { + printf("ERROR #%d: length %ld\n", __LINE__, slave_write_length); + test_control_return(1); + } + +#if !defined(UX_DEVICE_CLASS_CDC_ACM_WRITE_AUTO_ZLP) /* ZLP auto appended in autoZLP case. */ + stepinfo(">>>>>>>>>>>>>>>> Test device _ux_device_class_cdc_acm_write_with_callback ZLP\n"); + status = ux_device_class_cdc_acm_write_with_callback(cdc_acm_slave, UX_NULL, 0); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _ux_utility_semaphore_get(&slave_write_semaphore, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (slave_write_status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, slave_write_status); + test_control_return(1); + } + if (slave_write_length != 0) + { + printf("ERROR #%d: length %ld\n", __LINE__, slave_write_length); + test_control_return(1); + } +#endif + + stepinfo(">>>>>>>>>>>>>>>> Test device _ux_device_class_cdc_acm_write_with_callback error\n"); + ux_test_dcd_sim_slave_set_actions(error_on_transfer0); + status = ux_device_class_cdc_acm_write_with_callback(cdc_acm_slave, buffer, 12); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _ux_utility_semaphore_get(&slave_write_semaphore, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (slave_write_status != UX_ERROR) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, slave_write_status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test device _ux_device_class_cdc_acm_write_with_callback no callback\n"); + cdc_acm_slave->ux_device_class_cdc_acm_write_callback = UX_NULL; + ux_test_dcd_sim_slave_set_actions(error_on_transfer0); + status = ux_device_class_cdc_acm_write_with_callback(cdc_acm_slave, buffer, 12); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _ux_utility_semaphore_get(&slave_write_semaphore, 100); + if (status == UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + cdc_acm_slave->ux_device_class_cdc_acm_write_callback = callback.ux_device_class_cdc_acm_parameter_write_callback; + + /* Flush read semaphore. */ + while(UX_SUCCESS == _ux_utility_semaphore_get(&slave_read_semaphore, 0)); + + stepinfo(">>>>>>>>>>>>>>>> Test device _read_callback, expect 64+1+error >>>\n"); + actions_2_set_trigger = 2; + actions_2_set = error_on_transfer1; + slave_read_counter = 0; + slave_read_log[0].save2 = &buffer[512]; + slave_read_log[1].save2 = &buffer[512+64]; + slave_read_log[2].save2 = UX_NULL; + slave_read_log[3].save2 = UX_NULL; + slave_read_log[4].save2 = UX_NULL; + _ux_utility_thread_resume(&tx_test_thread_host_simulation); + + stepinfo(">>>>>>>>>>>>>>>> Test device _read_callback, expect 64\n"); + status = _ux_utility_semaphore_get(&slave_read_semaphore, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (slave_read_log[0].status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (slave_read_log[0].length != 64) + { + printf("ERROR #%d: length %ld\n", __LINE__, slave_read_log[0].length); + test_control_return(1); + } + if (_ux_utility_memory_compare(host_buffer, slave_read_log[0].save2, 64) != UX_SUCCESS) + { + printf("ERROR #%d: data error\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test device _read_callback, expect 1\n"); + status = _ux_utility_semaphore_get(&slave_read_semaphore, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (slave_read_log[1].status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (slave_read_log[1].length != 1) + { + printf("ERROR #%d: length %ld\n", __LINE__, slave_read_log[1].length); + test_control_return(1); + } + if (_ux_utility_memory_compare(host_buffer, slave_read_log[1].save2, 1) != UX_SUCCESS) + { + printf("ERROR #%d: data error\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test device _read_callback, expect ZL\n"); + status = _ux_utility_semaphore_get(&slave_read_semaphore, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (slave_read_log[2].status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (slave_read_log[2].length != 0) + { + printf("ERROR #%d: length %ld\n", __LINE__, slave_read_log[1].length); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test device _read_callback, expect timeout\n"); + status = _ux_utility_semaphore_get(&slave_read_semaphore, 100); + if (status == UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test device _read_ no callback, expect timeout >>>\n"); + cdc_acm_slave->ux_device_class_cdc_acm_read_callback = UX_NULL; + _ux_utility_thread_resume(&tx_test_thread_host_simulation); + + stepinfo(">>>>>>>>>>>>>>>> Test device _read_ no callback, expect timeout\n"); + status = _ux_utility_semaphore_get(&slave_read_semaphore, 100); + if (status == UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test device _read_ request error no callback, expect timeout\n"); + ux_test_dcd_sim_slave_set_actions(error_on_transfer1); + _ux_utility_thread_resume(&tx_test_thread_host_simulation); + status = _ux_utility_semaphore_get(&slave_read_semaphore, 500); + if (status == UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + cdc_acm_slave->ux_device_class_cdc_acm_read_callback = callback.ux_device_class_cdc_acm_parameter_read_callback; + +#endif + + /* End */ + stepinfo(">>>>>>>>>>>>>>>> Test device done\n"); + _ux_utility_thread_resume(&tx_test_thread_host_simulation); + while(1) + { + + /* Sleep so ThreadX on Win32 will delete this thread. */ + ux_utility_delay_ms(100); + } +} diff --git a/test/regression/usbx_ux_device_class_cdc_acm_write_test.c b/test/regression/usbx_ux_device_class_cdc_acm_write_test.c new file mode 100644 index 00000000..802175b9 --- /dev/null +++ b/test/regression/usbx_ux_device_class_cdc_acm_write_test.c @@ -0,0 +1,589 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" + +#include "ux_host_class_cdc_acm.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#include "ux_host_stack.h" + +/* Define constants. */ +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bmAttributes, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + (bmAttributes), 0x00, +#define CFG_DESC_LEN 9 + +#define IAD_DESC(bIfc) \ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (bIfc), 0x02, 0x02, 0x02, 0x00, 0x00, +#define IAD_DESC_LEN 8 + +#define CDC_IFC_DESC_ALL(bIfc, bIntIn, bBulkIn, bBulkOut)\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (bIfc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06, (bIfc), (bIfc + 1),\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03, (bIfc + 1),\ + /* Endpoint interrupt in descriptor 7 bytes */\ + 0x07, 0x05, (bIntIn), 0x03, 0x40, 0x00, 0x10,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (bIfc + 1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint bulk in descriptor 7 bytes */\ + 0x07, 0x05, (bBulkIn), 0x02, 0x40, 0x00, 0x01,\ + /* Endpoint bulk out descriptor 7 bytes */\ + 0x07, 0x05, (bBulkOut), 0x02, 0x40, 0x00, 0x01, +#define CDC_IFC_DESC_ALL_LEN (9+5+4+5+5+7+ 9+7+7) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_simulation_0; +static TX_THREAD tx_test_thread_simulation_1; +static VOID tx_test_thread_simulation_0_entry(ULONG); +static VOID tx_test_thread_simulation_1_entry(ULONG); +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +static UCHAR cdc_acm_slave_change; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; + +static ULONG error_counter; + +static ULONG error_callback_counter; +static UCHAR error_callback_ignore; + +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG test_thread_action; + +/* Define device framework. */ + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Configuration 1 descriptor 9 bytes, total 75 bytes */ + CFG_DESC(CFG_DESC_LEN + IAD_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 0x40, 1) + /* IAD 8 bytes */ + IAD_DESC(0) + /* CDC_ACM interfaces */ + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor 10 bytes */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor 9 bytes, total 75-8=67 bytes */ + CFG_DESC(CFG_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 0x60, 1) + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +static VOID disconnect_after_mutex_on_action_func(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + _ux_system_slave->ux_system_slave_device.ux_slave_device_state = UX_DEVICE_ADDRESSED; +} + +static UX_TEST_HCD_SIM_ACTION disconnect_after_mutex_on[] = { + { + .do_after = UX_TRUE, + .usbx_function = UX_TEST_OVERRIDE_TX_MUTEX_GET, + .wait_option = TX_WAIT_FOREVER, + .action_func = disconnect_after_mutex_on_action_func, + }, + { 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT break_on_cdc_acm_all_ready(VOID) +{ +UINT status; +UINT i; +UX_HOST_CLASS *class; +UX_HOST_CLASS_CDC_ACM *cdc_acm; + + /* Find the main cdc_acm container */ + status = ux_host_stack_class_get(_ux_system_host_class_cdc_acm_name, &class); + if (status != UX_SUCCESS) + /* Do not break. */ + return 0; + + /* Find class instances. */ + for (i = 0; i < 2; i ++) + { + status = ux_host_stack_class_instance_get(class, i, (void **) &cdc_acm); + if (status != UX_SUCCESS) + /* Do not break. */ + return 0; + + switch(cdc_acm->ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass) + { + + case UX_HOST_CLASS_CDC_CONTROL_CLASS: + cdc_acm_host_control = cdc_acm; + break; + + case UX_HOST_CLASS_CDC_DATA_CLASS: + cdc_acm_host_data = cdc_acm; + break; + + default: + break; + } + } + + if (cdc_acm_host_control == UX_NULL || cdc_acm_host_data == UX_NULL) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_host_data->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (_ux_system_slave->ux_system_slave_class_array[0].ux_slave_class_instance == UX_NULL) + /* Do not break. */ + return 0; + + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *)_ux_system_slave->ux_system_slave_class_array[0].ux_slave_class_instance; + + /* All found, break. */ + return 1; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + if (_ux_system_slave->ux_system_slave_class_array[0].ux_slave_class_instance != UX_NULL) + /* Do not break. */ + return 0; + + cdc_acm_host_data = UX_NULL; + cdc_acm_host_control = UX_NULL; + cdc_acm_slave = UX_NULL; + + return 1; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; +} + +static VOID test_ux_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); + } + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_cdc_acm_write_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + printf("Running ux_device_class_cdc_acm_write Test.......................... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register CDC ACM class */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_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); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = UX_NULL; + parameter.ux_slave_class_cdc_acm_instance_deactivate = UX_NULL; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 2,0, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 3,0, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#endif + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register HCD for test */ + 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(&tx_test_thread_simulation_0, "tx test host simulation", tx_test_thread_simulation_0_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_simulation_1, "tx test slave simulation", tx_test_thread_simulation_1_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_NO_ACTIVATE); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +void tx_test_thread_simulation_0_entry(ULONG arg) +{ + +UINT i; + + /* Test connect. */ + stepinfo(">>>>>>>>>>>>>>>> Test connect (FS)\n"); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + ux_test_breakable_sleep(100, break_on_cdc_acm_all_ready); + if (!(cdc_acm_host_control && cdc_acm_host_data && cdc_acm_slave)) + { + + printf("ERROR #%d: connect fail\n", __LINE__); + test_control_return(1); + } + if (_ux_system_slave->ux_system_slave_device.ux_slave_device_state != UX_DEVICE_CONFIGURED) + { + + printf("ERROR %d: device state fail 0x%lx\n", __LINE__, _ux_system_slave->ux_system_slave_device.ux_slave_device_state); + test_control_return(1); + } + + /* Test write. */ + stepinfo(">>>>>>>>>>>>>>>> Test write disconnect after mutex_on\n"); + + test_thread_action = 1; + tx_thread_resume(&tx_test_thread_simulation_1); + + for (i = 0; i < 10; i ++) + { + if (test_thread_action < 2) + _ux_utility_delay_ms(10); + } + if (test_thread_action < 2) + { + printf("ERROR %d: test no progress\n", __LINE__); + error_counter ++; + } + + /* Restore state. */ + _ux_system_slave->ux_system_slave_device.ux_slave_device_state = UX_DEVICE_CONFIGURED; + + stepinfo(">>>>>>>>>>>>>>>> Deinitialize\n"); + + /* Deinitialize the class. */ + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + + /* Deinitialize the device side of usbx. */ + _ux_device_stack_uninitialize(); + + /* And finally the usbx system resources. */ + _ux_system_uninitialize(); + + stepinfo(">>>>>>>>>>>>>>>> Dump results\n"); + + if (error_counter > 0) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + +void tx_test_thread_simulation_1_entry(ULONG arg) +{ + +UINT status; +ULONG actual_length; + + while(1) + { + if (test_thread_action == 1) + { + ux_test_set_main_action_list_from_array(disconnect_after_mutex_on); + status = ux_device_class_cdc_acm_write(cdc_acm_slave, buffer, 128, &actual_length); + if (status == UX_SUCCESS) + { + printf("ERROR %d: expect fail\n", __LINE__); + error_counter ++; + } + test_thread_action ++; + } + tx_thread_suspend(&tx_test_thread_simulation_1); + } +} diff --git a/test/regression/usbx_ux_device_class_cdc_ecm_activate_test.c b/test/regression/usbx_ux_device_class_cdc_ecm_activate_test.c new file mode 100644 index 00000000..67cee5cb --- /dev/null +++ b/test/regression/usbx_ux_device_class_cdc_ecm_activate_test.c @@ -0,0 +1,265 @@ +/* Include necessary system files. */ + +#include "usbx_ux_test_cdc_ecm.h" + +#define CFG_DESC_POS (0x12) + +#define DATA_IF_DESC_POS0 (DEFAULT_FRAMEWORK_LENGTH - 2*7 - 9 - 9) +#define DATA_IF_DESC_POS1 (DEFAULT_FRAMEWORK_LENGTH - 2*7 - 9) + +#define INT_EP_DESC_POS (0x12+0x09+0x08+0x09+0x05+0x0d+0x05) + +#define BULK_EP_DESC_POS1 (_ux_system_slave -> ux_system_slave_device_framework_length - 14) +#define BULK_EP_DESC_POS2 (_ux_system_slave -> ux_system_slave_device_framework_length - 7) + +static ULONG error_callback_counter; +static UCHAR framework_backup[DEFAULT_FRAMEWORK_LENGTH]; +static UX_SLAVE_CLASS_CDC_ECM *cdc_ecm_device_bak; + +static void framework_rm_data_if_alt(void) +{ + // printf("Remove alternate setting of interface 1 (CDC DATA)\n"); + _ux_utility_memory_copy(default_device_framework + DATA_IF_DESC_POS0, + framework_backup + DATA_IF_DESC_POS1, 9 + 7 + 7); + default_device_framework[CFG_DESC_POS + 2] -= 9; + default_device_framework[DATA_IF_DESC_POS0 + 3] = 0; + _ux_system_slave -> ux_system_slave_device_framework_length -= 9; + _ux_system_slave -> ux_system_slave_device_framework_length_full_speed -= 9; + _ux_system_slave -> ux_system_slave_device_framework_length_high_speed -= 9; +} + +static void framework_copy(void) +{ + _ux_utility_memory_copy(framework_backup, default_device_framework, DEFAULT_FRAMEWORK_LENGTH); +} + +static void framework_restore(void) +{ + // printf("Restore framework\n"); + _ux_utility_memory_copy(default_device_framework, framework_backup, DEFAULT_FRAMEWORK_LENGTH); +} + +static void device_framework_restore(void) +{ + framework_restore(); + _ux_system_slave -> ux_system_slave_device_framework_length = DEFAULT_FRAMEWORK_LENGTH; + _ux_system_slave -> ux_system_slave_device_framework_length_full_speed = DEFAULT_FRAMEWORK_LENGTH; + _ux_system_slave -> ux_system_slave_device_framework_length_high_speed = DEFAULT_FRAMEWORK_LENGTH; +} + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; +static UX_TEST_SETUP _GetCfgDescr = UX_TEST_SETUP_GetCfgDescr; +static UX_TEST_SETUP _SetAddress = UX_TEST_SETUP_SetAddress; +static UX_TEST_SETUP _GetDeviceDescriptor = UX_TEST_SETUP_GetDevDescr; +static UX_TEST_SETUP _GetConfigDescriptor = UX_TEST_SETUP_GetCfgDescr; + +static void count_error_callback(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ +UX_TEST_ERROR_CALLBACK_PARAMS *error = (UX_TEST_ERROR_CALLBACK_PARAMS *)params; + + // printf("error trap #%d: 0x%x, 0x%x, 0x%x\n", __LINE__, error->system_level, error->system_context, error->error_code); + error_callback_counter ++; +} + +static UX_TEST_HCD_SIM_ACTION count_on_error_trap[] = { +{ .usbx_function = UX_TEST_OVERRIDE_ERROR_CALLBACK, + .action_func = count_error_callback, +}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION replace_configuration_descriptor[] = { +{ .usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + .function = UX_HCD_TRANSFER_REQUEST, + .req_setup = &_GetConfigDescriptor, + .req_action = UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, + .req_ep_address = 0, + .req_data = (framework_backup + CFG_DESC_POS), + .req_actual_len = 9, + .req_status = UX_SUCCESS, + .status = UX_SUCCESS, + .action_func = UX_NULL, + .no_return = UX_FALSE +}, +{ .usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + .function = UX_HCD_TRANSFER_REQUEST, + .req_setup = &_GetConfigDescriptor, + .req_action = UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, + .req_ep_address = 0, + .req_data = (framework_backup + CFG_DESC_POS), + .req_actual_len = DEFAULT_FRAMEWORK_LENGTH - CFG_DESC_POS, + .req_status = UX_SUCCESS, + .status = UX_SUCCESS, + .action_func = UX_NULL, + .no_return = UX_FALSE +}, +{ 0 } +}; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_cdc_ecm_activate_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running ux_device_class_cdc_ecm_activate Test....................... "); + + stepinfo("\n"); + + /* Keep a copy of framework data. */ + framework_copy(); + + /* Override error trap. */ + ux_test_link_hooks_from_array(count_on_error_trap); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static UINT _wait_host_inst_change_to(ULONG loop, UCHAR available) +{ + while(loop --) + { + _ux_utility_delay_ms(10); + if (available) + { + if (cdc_ecm_host_from_system_change_function != UX_NULL) + return UX_SUCCESS; + } + else + { + if (cdc_ecm_host_from_system_change_function == UX_NULL) + return UX_SUCCESS; + } + } + return UX_ERROR; +} + +static void post_init_host() +{ + +UCHAR tmp_byte; + + + stepinfo(">>>>>>>>>>>>>>>>>>> Test modify ux_slave_class_cdc_ecm_instance_ activate/deactivate\n"); + UX_TEST_ASSERT(cdc_ecm_device != UX_NULL); + cdc_ecm_device_bak = cdc_ecm_device; + + // ux_test_device_class_cdc_ecm_set_link_state(cdc_ecm_device, UX_DEVICE_CLASS_CDC_ECM_LINK_STATE_UP); + cdc_ecm_device_bak -> ux_slave_class_cdc_ecm_parameter.ux_slave_class_cdc_ecm_instance_activate = UX_NULL; + cdc_ecm_device_bak -> ux_slave_class_cdc_ecm_parameter.ux_slave_class_cdc_ecm_instance_deactivate = UX_NULL; + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_disconnect_slave(); + ux_test_disconnect_host_wait_for_enum_completion(); + UX_TEST_CHECK_SUCCESS(_wait_host_inst_change_to(100, 0)); + + stepinfo(">>>>>>>>>>>>>>>>>>> Test connect with control IF INT OUT endpoint\n"); + // printf("epAddr: %x\n", default_device_framework[INT_EP_DESC_POS + 2]); + default_device_framework[INT_EP_DESC_POS + 2] = 0x03; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + UX_TEST_CHECK_SUCCESS(_wait_host_inst_change_to(100, 1)); + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_disconnect_slave(); + ux_test_disconnect_host_wait_for_enum_completion(); + UX_TEST_CHECK_SUCCESS(_wait_host_inst_change_to(100, 0)); + + stepinfo(">>>>>>>>>>>>>>>>>>> Test connect with control IF BULK IN endpoint\n"); + default_device_framework[INT_EP_DESC_POS + 2] = 0x83; + default_device_framework[INT_EP_DESC_POS + 3] = 0x02; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + UX_TEST_CHECK_SUCCESS(_wait_host_inst_change_to(100, 1)); + default_device_framework[INT_EP_DESC_POS + 3] = 0x03; + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_disconnect_slave(); + ux_test_disconnect_host_wait_for_enum_completion(); + UX_TEST_CHECK_SUCCESS(_wait_host_inst_change_to(100, 0)); + + stepinfo(">>>>>>>>>>>>>>>>>>> Test connect with data IF bulk endpoints swapped\n"); + // printf("epAddr: %x, %x\n", default_device_framework[BULK_EP_DESC_POS1 + 2], default_device_framework[BULK_EP_DESC_POS2 + 2]); + tmp_byte = default_device_framework[BULK_EP_DESC_POS1 + 2]; + default_device_framework[BULK_EP_DESC_POS1 + 2] = default_device_framework[BULK_EP_DESC_POS2 + 2]; + default_device_framework[BULK_EP_DESC_POS2 + 2] = tmp_byte; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + UX_TEST_CHECK_SUCCESS(_wait_host_inst_change_to(100, 1)); + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_disconnect_slave(); + ux_test_disconnect_host_wait_for_enum_completion(); + UX_TEST_CHECK_SUCCESS(_wait_host_inst_change_to(100, 0)); + + /* Modify data interface for testing. */ + framework_rm_data_if_alt(); + + stepinfo(">>>>>>>>>>>>>>>>>>> Test connect with data IF BULK & BULK endpoint\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_set_actions(replace_configuration_descriptor); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + UX_TEST_CHECK_SUCCESS(_wait_host_inst_change_to(100, 1)); + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_disconnect_slave(); + ux_test_disconnect_host_wait_for_enum_completion(); + UX_TEST_CHECK_SUCCESS(_wait_host_inst_change_to(100, 0)); + + stepinfo(">>>>>>>>>>>>>>>>>>> Test connect with data IF INT & BULK endpoint\n"); + default_device_framework[BULK_EP_DESC_POS1 + 3] = 0x3; + default_device_framework[BULK_EP_DESC_POS1 + 6] = 0x1; /* avoid creation crush! */ + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_set_actions(replace_configuration_descriptor); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + UX_TEST_CHECK_NOT_SUCCESS(_wait_host_inst_change_to(100, 1)); + default_device_framework[BULK_EP_DESC_POS1 + 3] = 0x2; + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_disconnect_slave(); + ux_test_disconnect_host_wait_for_enum_completion(); + UX_TEST_CHECK_SUCCESS(_wait_host_inst_change_to(100, 0)); + + stepinfo(">>>>>>>>>>>>>>>>>>> Test connect with data IF BULK & INT endpoint\n"); + default_device_framework[BULK_EP_DESC_POS2 + 3] = 0x3; + default_device_framework[BULK_EP_DESC_POS2 + 6] = 0x1; /* avoid creation crush! */ + ux_test_hcd_sim_host_set_actions(replace_configuration_descriptor); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + UX_TEST_CHECK_NOT_SUCCESS(_wait_host_inst_change_to(100, 1)); + default_device_framework[BULK_EP_DESC_POS2 + 3] = 0x2; + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_disconnect_slave(); + ux_test_disconnect_host_wait_for_enum_completion(); + UX_TEST_CHECK_SUCCESS(_wait_host_inst_change_to(100, 0)); + + /* Restore framework. */ + device_framework_restore(); + ux_test_hcd_sim_host_set_actions(UX_NULL); + + stepinfo(">>>>>>>>>>>>>>>>>>> Test connect to avoid post post operation\n"); + /* Connect. */ + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + // class_cdc_ecm_get_host(); + + stepinfo(">>>>>>>>>>>>>>>>>>> post_init_host done\n"); +} + +static void post_init_device() +{ + stepinfo(">>>>>>>>>>>>>>>>>>> post_init_device empty\n"); +} \ No newline at end of file diff --git a/test/regression/usbx_ux_device_class_cdc_ecm_bulkin_thread_test.c b/test/regression/usbx_ux_device_class_cdc_ecm_bulkin_thread_test.c new file mode 100644 index 00000000..8f582686 --- /dev/null +++ b/test/regression/usbx_ux_device_class_cdc_ecm_bulkin_thread_test.c @@ -0,0 +1,154 @@ +/* Include necessary system files. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static ULONG error_callback_counter; + +static void count_error_callback(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ +UX_TEST_ERROR_CALLBACK_PARAMS *error = (UX_TEST_ERROR_CALLBACK_PARAMS *)params; + + // printf("error trap #%d: 0x%x, 0x%x, 0x%x\n", __LINE__, error->system_level, error->system_context, error->error_code); + error_callback_counter ++; +} + +static UX_TEST_HCD_SIM_ACTION count_on_error_trap[] = { +{ .usbx_function = UX_TEST_OVERRIDE_ERROR_CALLBACK, + .action_func = count_error_callback, +}, +{ 0 } +}; + +static UX_TEST_ACTION bulk_transfer_replace[] = +{ + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP | UX_TEST_SIM_REQ_ANSWER, + .req_ep_address = 0x81, + .req_actual_len = 0, + .req_status = UX_SUCCESS, + .status = UX_SUCCESS, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP | UX_TEST_SIM_REQ_ANSWER, + .req_ep_address = 0x81, + .req_actual_len = 0, + .req_status = UX_SUCCESS, + .status = UX_SUCCESS, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, +{ 0 }, +}; + + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_cdc_ecm_bulkin_thread_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running ux_device_class_cdc_ecm_bulkin_thread Test.................. "); + + stepinfo("\n"); + + /* Override error trap. */ + ux_test_link_hooks_from_array(count_on_error_trap); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static void post_init_host() +{ + +ULONG link_state[] = {0,1,2,3,0,1}; +UINT i; +UCHAR buffer[64]; +NX_PACKET packet = {0}; + + /* Point the prepend ptr to some valid memory so there's no crash. */ + packet.nx_packet_prepend_ptr = buffer; + + stepinfo(">>>>>>>>>>>>>>>>>>> Test activate check\n"); + UX_TEST_ASSERT(cdc_ecm_device != UX_NULL); + + /* Disable the other threads. */ + // _ux_utility_thread_suspend(&cdc_ecm_device->ux_slave_class_cdc_ecm_bulkin_thread); + _ux_utility_thread_suspend(&cdc_ecm_device->ux_slave_class_cdc_ecm_bulkout_thread); + _ux_utility_thread_suspend(&cdc_ecm_device->ux_slave_class_cdc_ecm_interrupt_thread); + +#if 0 + stepinfo(">>>>>>>>>>>>>>>>>>> Test endpoint closed\n"); + ep = cdc_ecm_device->ux_slave_class_cdc_ecm_bulkin_endpoint; + cdc_ecm_device->ux_slave_class_cdc_ecm_bulkin_endpoint = UX_NULL; + _ux_utility_event_flags_set(&cdc_ecm_device -> ux_slave_class_cdc_ecm_event_flags_group, UX_DEVICE_CLASS_CDC_ECM_NEW_DEVICE_STATE_CHANGE_EVENT, TX_OR); + _ux_utility_thread_sleep(2); + cdc_ecm_device->ux_slave_class_cdc_ecm_bulkin_endpoint = ep; + _ux_utility_thread_resume(&cdc_ecm_device->ux_slave_class_cdc_ecm_bulkin_thread); +#endif + + i = (cdc_ecm_device -> ux_slave_class_cdc_ecm_link_state == 0) ? 1 : 0; + for (;i < 5; i ++) + { + + stepinfo(">>>>>>>>>>>>>>>>>>> Test %d write length overflow\n", i); + packet.nx_packet_length = 1 + UX_SLAVE_REQUEST_DATA_MAX_LENGTH; + ux_device_class_cdc_ecm_write(cdc_ecm_device, &packet); + + stepinfo(">>>>>>>>>>>>>>>>>>> Test %d bulkin UX_ERROR\n", i); + bulk_transfer_replace[0].req_status = UX_ERROR; + bulk_transfer_replace[0].status = UX_ERROR; + bulk_transfer_replace[1].req_status = UX_ERROR; + bulk_transfer_replace[1].status = UX_ERROR; + ux_test_dcd_sim_slave_set_actions(bulk_transfer_replace); + error_callback_counter = 0; + packet.nx_packet_length = 1; + ux_device_class_cdc_ecm_write(cdc_ecm_device, &packet); + _ux_utility_thread_sleep(2); + if (cdc_ecm_device -> ux_slave_class_cdc_ecm_link_state == UX_DEVICE_CLASS_CDC_ECM_LINK_STATE_UP) + UX_TEST_ASSERT(error_callback_counter); + + stepinfo(">>>>>>>>>>>>>>>>>>> Test %d bulkin UX_TRANSFER_BUS_RESET\n", i); + bulk_transfer_replace[0].req_status = UX_TRANSFER_BUS_RESET; + bulk_transfer_replace[0].status = UX_TRANSFER_BUS_RESET; + bulk_transfer_replace[1].req_status = UX_TRANSFER_BUS_RESET; + bulk_transfer_replace[1].status = UX_TRANSFER_BUS_RESET; + ux_test_dcd_sim_slave_set_actions(bulk_transfer_replace); + packet.nx_packet_length = 1; + ux_device_class_cdc_ecm_write(cdc_ecm_device, &packet); + _ux_utility_thread_sleep(2); + + stepinfo(">>>>>>>>>>>>>>>>>>> Test %d link state change\n", i); + cdc_ecm_device -> ux_slave_class_cdc_ecm_link_state = link_state[i]; + if (i & 1) + cdc_ecm_device -> ux_slave_class_cdc_ecm_xmit_queue = &packet; + _ux_utility_event_flags_set(&cdc_ecm_device -> ux_slave_class_cdc_ecm_event_flags_group, UX_DEVICE_CLASS_CDC_ECM_NEW_BULKIN_EVENT, TX_OR); + if (i & 1) + cdc_ecm_device -> ux_slave_class_cdc_ecm_xmit_queue = &packet; + _ux_utility_event_flags_set(&cdc_ecm_device -> ux_slave_class_cdc_ecm_event_flags_group, UX_DEVICE_CLASS_CDC_ECM_NEW_DEVICE_STATE_CHANGE_EVENT, TX_OR); + _ux_utility_thread_sleep(2); + } + + // stepinfo(">>>>>>>>>>>>>>>>>>> Test connect to avoid post post operation\n"); + // /* Connect. */ + // ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + // ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + // class_cdc_ecm_get_host(); + + stepinfo(">>>>>>>>>>>>>>>>>>> post_init_host done\n"); +} + +static void post_init_device() +{ + stepinfo(">>>>>>>>>>>>>>>>>>> post_init_device empty\n"); +} \ No newline at end of file diff --git a/test/regression/usbx_ux_device_class_cdc_ecm_bulkout_thread_test.c b/test/regression/usbx_ux_device_class_cdc_ecm_bulkout_thread_test.c new file mode 100644 index 00000000..eb61e930 --- /dev/null +++ b/test/regression/usbx_ux_device_class_cdc_ecm_bulkout_thread_test.c @@ -0,0 +1,158 @@ +/* Include necessary system files. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static ULONG error_callback_counter; +static UCHAR buffer[64]; +static ULONG error_header_sim; + +static void count_error_callback(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ +UX_TEST_ERROR_CALLBACK_PARAMS *error = (UX_TEST_ERROR_CALLBACK_PARAMS *)params; + + // printf("error trap #%d: 0x%x, 0x%x, 0x%x\n", __LINE__, error->system_level, error->system_context, error->error_code); + error_callback_counter ++; +} + +static UX_TEST_HCD_SIM_ACTION count_on_error_trap[] = { +{ .usbx_function = UX_TEST_OVERRIDE_ERROR_CALLBACK, + .action_func = count_error_callback, +}, +{ 0 } +}; + +static void simulate_ip_header_error(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *p = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *)params; +UX_TRANSFER *transfer = (UX_TRANSFER *)p->parameter; +UCHAR *pretend_ptr = transfer->ux_transfer_request_data_pointer; + + + if (error_header_sim & 1) + { + *(pretend_ptr + 12) = 0x08; + *(pretend_ptr + 13) = 0x01; + } + else + { + *(pretend_ptr + 12) = 0x00; + *(pretend_ptr + 13) = 0x00; + } + + error_header_sim ++; +} + +static UX_TEST_ACTION bulk_transfer_replace[] = +{ + { + .usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + .function = UX_HCD_TRANSFER_REQUEST, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x02, + .req_actual_len = 64, + .req_status = UX_SUCCESS, + .action_func = simulate_ip_header_error, + .status = UX_SUCCESS, + .do_after = UX_FALSE, + .no_return = UX_TRUE, + }, +{ 0 }, +}; + + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_cdc_ecm_bulkout_thread_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running ux_device_class_cdc_ecm_bulkout_thread Test................. "); + + stepinfo("\n"); + + /* Override error trap. */ + ux_test_link_hooks_from_array(count_on_error_trap); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static void post_init_host() +{ + +UINT i; +UX_SLAVE_ENDPOINT *endpoint; +USB_NETWORK_DEVICE_TYPE *ux_nx_device; +NX_IP *ip; + + + stepinfo(">>>>>>>>>>>>>>>>>>> Test activate check\n"); + UX_TEST_ASSERT(cdc_ecm_device != UX_NULL); + + /* Disable the other threads. */ + _ux_utility_thread_suspend(&cdc_ecm_device->ux_slave_class_cdc_ecm_bulkin_thread); + // _ux_utility_thread_suspend(&cdc_ecm_device->ux_slave_class_cdc_ecm_bulkout_thread); + _ux_utility_thread_suspend(&cdc_ecm_device->ux_slave_class_cdc_ecm_interrupt_thread); + + stepinfo(">>>>>>>>>>>>>>>>>>> Test UX allocate error\n"); + error_callback_counter = 0; + for (i = 0; i < 2000; i ++) + { + write_packet_udp(&udp_socket_host, &packet_pool_host, DEVICE_IP_ADDRESS, DEVICE_SOCKET_PORT_UDP, global_basic_test_num_writes_host++, "host"); + _ux_utility_thread_sleep(1); + if (error_callback_counter) + break; + } + UX_TEST_ASSERT(error_callback_counter); + for(;i ; i --) + { + read_packet_udp(&udp_socket_device, global_basic_test_num_reads_device++, "device"); + _ux_utility_thread_sleep(1); + } + + stepinfo(">>>>>>>>>>>>>>>>>>> Test packet header error\n"); + for (i = 0; i < 4; i ++) + { + ux_test_hcd_sim_host_set_actions(bulk_transfer_replace); + write_packet_udp(&udp_socket_host, &packet_pool_host, DEVICE_IP_ADDRESS, DEVICE_SOCKET_PORT_UDP, global_basic_test_num_writes_host++, "host"); + _ux_utility_thread_sleep(1); + } + + // stepinfo(">>>>>>>>>>>>>>>>>>> Test connect to avoid post post operation\n"); + // /* Connect. */ + // ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + // ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + // class_cdc_ecm_get_host(); + + stepinfo(">>>>>>>>>>>>>>>>>>> Test IP instance attach\n"); + ux_nx_device = (USB_NETWORK_DEVICE_TYPE *)cdc_ecm_device->ux_slave_class_cdc_ecm_network_handle; + ux_nx_device -> ux_network_device_link_status = UX_FALSE; + ip = ux_nx_device -> ux_network_device_ip_instance; + ux_nx_device -> ux_network_device_ip_instance = UX_NULL; + cdc_ecm_device -> ux_slave_class_cdc_ecm_packet_pool = UX_NULL; + write_packet_udp(&udp_socket_host, &packet_pool_host, DEVICE_IP_ADDRESS, DEVICE_SOCKET_PORT_UDP, global_basic_test_num_writes_host++, "host"); + _ux_utility_delay_ms(1); + ux_nx_device -> ux_network_device_ip_instance = ip; + ux_nx_device -> ux_network_device_link_status = UX_TRUE; + _ux_utility_delay_ms(UX_DEVICE_CLASS_CDC_ECM_PACKET_POOL_INST_WAIT + 10); + UX_TEST_ASSERT(cdc_ecm_device -> ux_slave_class_cdc_ecm_packet_pool == ip -> nx_ip_default_packet_pool); + + stepinfo(">>>>>>>>>>>>>>>>>>> Test endpoint not ready error\n"); + endpoint = cdc_ecm_device -> ux_slave_class_cdc_ecm_bulkout_endpoint; + cdc_ecm_device -> ux_slave_class_cdc_ecm_bulkout_endpoint = UX_NULL; + write_packet_udp(&udp_socket_host, &packet_pool_host, DEVICE_IP_ADDRESS, DEVICE_SOCKET_PORT_UDP, global_basic_test_num_writes_host++, "host"); + _ux_utility_delay_ms(1); + cdc_ecm_device -> ux_slave_class_cdc_ecm_bulkout_endpoint = endpoint; + _ux_utility_delay_ms(UX_DEVICE_CLASS_CDC_ECM_LINK_CHECK_WAIT + 10); + + stepinfo(">>>>>>>>>>>>>>>>>>> post_init_host done\n"); +} + +static void post_init_device() +{ + stepinfo(">>>>>>>>>>>>>>>>>>> post_init_device empty\n"); +} \ No newline at end of file diff --git a/test/regression/usbx_ux_device_class_cdc_ecm_change_test.c b/test/regression/usbx_ux_device_class_cdc_ecm_change_test.c new file mode 100644 index 00000000..c90c0b56 --- /dev/null +++ b/test/regression/usbx_ux_device_class_cdc_ecm_change_test.c @@ -0,0 +1,200 @@ +/* Include necessary system files. */ + +#include "usbx_ux_test_cdc_ecm.h" + +#define CFG_DESC_POS (0x12) + +#define DATA_IF_DESC_POS0 (DEFAULT_FRAMEWORK_LENGTH - 2*7 - 9 - 9) +#define DATA_IF_DESC_POS1 (DEFAULT_FRAMEWORK_LENGTH - 2*7 - 9) + +#define INT_EP_DESC_POS (0x12+0x09+0x08+0x09+0x05+0x0d+0x05) + +#define BULK_EP_DESC_POS1 (_ux_system_slave -> ux_system_slave_device_framework_length - 14) +#define BULK_EP_DESC_POS2 (_ux_system_slave -> ux_system_slave_device_framework_length - 7) + +static ULONG error_callback_counter; +static UCHAR framework_backup[DEFAULT_FRAMEWORK_LENGTH]; +static UX_SLAVE_CLASS_CDC_ECM *cdc_ecm_device_bak; + +static void framework_rm_data_if_alt(void) +{ + // printf("Remove alternate setting of interface 1 (CDC DATA)\n"); + _ux_utility_memory_copy(default_device_framework + DATA_IF_DESC_POS0, + framework_backup + DATA_IF_DESC_POS1, 9 + 7 + 7); + default_device_framework[CFG_DESC_POS + 2] -= 9; + default_device_framework[DATA_IF_DESC_POS0 + 3] = 0; + _ux_system_slave -> ux_system_slave_device_framework_length -= 9; + _ux_system_slave -> ux_system_slave_device_framework_length_full_speed -= 9; + _ux_system_slave -> ux_system_slave_device_framework_length_high_speed -= 9; +} + +static void framework_copy(void) +{ + _ux_utility_memory_copy(framework_backup, default_device_framework, DEFAULT_FRAMEWORK_LENGTH); +} + +static void framework_restore(void) +{ + // printf("Restore framework\n"); + _ux_utility_memory_copy(default_device_framework, framework_backup, DEFAULT_FRAMEWORK_LENGTH); +} + +static void device_framework_restore(void) +{ + framework_restore(); + _ux_system_slave -> ux_system_slave_device_framework_length = DEFAULT_FRAMEWORK_LENGTH; + _ux_system_slave -> ux_system_slave_device_framework_length_full_speed = DEFAULT_FRAMEWORK_LENGTH; + _ux_system_slave -> ux_system_slave_device_framework_length_high_speed = DEFAULT_FRAMEWORK_LENGTH; +} + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; +static UX_TEST_SETUP _GetCfgDescr = UX_TEST_SETUP_GetCfgDescr; +static UX_TEST_SETUP _SetAddress = UX_TEST_SETUP_SetAddress; +static UX_TEST_SETUP _GetDeviceDescriptor = UX_TEST_SETUP_GetDevDescr; +static UX_TEST_SETUP _GetConfigDescriptor = UX_TEST_SETUP_GetCfgDescr; + +static void count_error_callback(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ +UX_TEST_ERROR_CALLBACK_PARAMS *error = (UX_TEST_ERROR_CALLBACK_PARAMS *)params; + + // printf("error trap #%d: 0x%x, 0x%x, 0x%x\n", __LINE__, error->system_level, error->system_context, error->error_code); + error_callback_counter ++; +} + +static UX_TEST_HCD_SIM_ACTION count_on_error_trap[] = { +{ .usbx_function = UX_TEST_OVERRIDE_ERROR_CALLBACK, + .action_func = count_error_callback, +}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION replace_configuration_descriptor[] = { +{ .usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + .function = UX_HCD_TRANSFER_REQUEST, + .req_setup = &_GetConfigDescriptor, + .req_action = UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, + .req_ep_address = 0, + .req_data = (framework_backup + CFG_DESC_POS), + .req_actual_len = 9, + .req_status = UX_SUCCESS, + .status = UX_SUCCESS, + .action_func = UX_NULL, + .no_return = UX_FALSE +}, +{ .usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + .function = UX_HCD_TRANSFER_REQUEST, + .req_setup = &_GetConfigDescriptor, + .req_action = UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, + .req_ep_address = 0, + .req_data = (framework_backup + CFG_DESC_POS), + .req_actual_len = DEFAULT_FRAMEWORK_LENGTH - CFG_DESC_POS, + .req_status = UX_SUCCESS, + .status = UX_SUCCESS, + .action_func = UX_NULL, + .no_return = UX_FALSE +}, +{ 0 } +}; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_cdc_ecm_change_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running ux_device_class_cdc_ecm_change Test......................... "); + + stepinfo("\n"); + + /* Keep a copy of framework data. */ + framework_copy(); + + /* Override error trap. */ + ux_test_link_hooks_from_array(count_on_error_trap); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static UINT _wait_host_inst_change_to(ULONG loop, UCHAR available) +{ + while(loop --) + { + _ux_utility_delay_ms(10); + if (available) + { + if (cdc_ecm_host_from_system_change_function != UX_NULL) + return UX_SUCCESS; + } + else + { + if (cdc_ecm_host_from_system_change_function == UX_NULL) + return UX_SUCCESS; + } + } + return UX_ERROR; +} + +static void post_init_host() +{ + + stepinfo(">>>>>>>>>>>>>>>>>>> Test instance connect\n"); + UX_TEST_ASSERT(cdc_ecm_device != UX_NULL); + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_disconnect_slave(); + ux_test_disconnect_host_wait_for_enum_completion(); + UX_TEST_CHECK_SUCCESS(_wait_host_inst_change_to(100, 0)); + + stepinfo(">>>>>>>>>>>>>>>>>>> Test connect with data IF INT & BULK endpoint\n"); + default_device_framework[BULK_EP_DESC_POS1 + 3] = 0x3; + default_device_framework[BULK_EP_DESC_POS1 + 6] = 0x1; /* avoid creation crush! */ + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_set_actions(replace_configuration_descriptor); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + UX_TEST_CHECK_NOT_SUCCESS(_wait_host_inst_change_to(100, 1)); + default_device_framework[BULK_EP_DESC_POS1 + 3] = 0x2; + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_disconnect_slave(); + ux_test_disconnect_host_wait_for_enum_completion(); + UX_TEST_CHECK_SUCCESS(_wait_host_inst_change_to(100, 0)); + + stepinfo(">>>>>>>>>>>>>>>>>>> Test connect with data IF BULK & INT endpoint\n"); + default_device_framework[BULK_EP_DESC_POS2 + 3] = 0x3; + default_device_framework[BULK_EP_DESC_POS2 + 6] = 0x1; /* avoid creation crush! */ + ux_test_hcd_sim_host_set_actions(replace_configuration_descriptor); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + UX_TEST_CHECK_NOT_SUCCESS(_wait_host_inst_change_to(100, 1)); + default_device_framework[BULK_EP_DESC_POS2 + 3] = 0x2; + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_disconnect_slave(); + ux_test_disconnect_host_wait_for_enum_completion(); + UX_TEST_CHECK_SUCCESS(_wait_host_inst_change_to(100, 0)); + + /* Restore framework. */ + device_framework_restore(); + ux_test_hcd_sim_host_set_actions(UX_NULL); + + stepinfo(">>>>>>>>>>>>>>>>>>> Test connect to avoid post post operation\n"); + /* Connect. */ + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + // class_cdc_ecm_get_host(); + + stepinfo(">>>>>>>>>>>>>>>>>>> post_init_host done\n"); +} + +static void post_init_device() +{ + stepinfo(">>>>>>>>>>>>>>>>>>> post_init_device empty\n"); +} \ No newline at end of file diff --git a/test/regression/usbx_ux_device_class_cdc_ecm_control_request_test.c b/test/regression/usbx_ux_device_class_cdc_ecm_control_request_test.c new file mode 100644 index 00000000..5c812b86 --- /dev/null +++ b/test/regression/usbx_ux_device_class_cdc_ecm_control_request_test.c @@ -0,0 +1,134 @@ +/* Include necessary system files. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static ULONG error_callback_counter; +static UCHAR buffer[64]; + +static void count_error_callback(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ +UX_TEST_ERROR_CALLBACK_PARAMS *error = (UX_TEST_ERROR_CALLBACK_PARAMS *)params; + + // printf("error trap #%d: 0x%x, 0x%x, 0x%x\n", __LINE__, error->system_level, error->system_context, error->error_code); + error_callback_counter ++; +} + +static UX_TEST_HCD_SIM_ACTION count_on_error_trap[] = { +{ .usbx_function = UX_TEST_OVERRIDE_ERROR_CALLBACK, + .action_func = count_error_callback, +}, +{ 0 } +}; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_cdc_ecm_control_request_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running ux_device_class_cdc_ecm_control_request Test................ "); + + stepinfo("\n"); + + /* Override error trap. */ + ux_test_link_hooks_from_array(count_on_error_trap); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static void post_init_host() +{ + +UINT status; +UX_DEVICE *device; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; + + + stepinfo(">>>>>>>>>>>>>>>>>>> Test activate check\n"); + UX_TEST_ASSERT(cdc_ecm_device != UX_NULL); + + UX_TEST_CHECK_SUCCESS(ux_host_stack_device_get(0, &device)); + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_index = 0; + + stepinfo(">>>>>>>>>>>>>>>>>>> Test UX_DEVICE_CLASS_CDC_ECM_SET_ETHERNET_MULTICAST_FILTER\n"); + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_CDC_ECM_SET_ETHERNET_MULTICAST_FILTER; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_value = 1; + UX_TEST_CHECK_SUCCESS(ux_host_stack_transfer_request(transfer_request)); + + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_CDC_ECM_SET_ETHERNET_MULTICAST_FILTER; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_value = 0; + UX_TEST_CHECK_SUCCESS(ux_host_stack_transfer_request(transfer_request)); + + stepinfo(">>>>>>>>>>>>>>>>>>> Test UX_DEVICE_CLASS_CDC_ECM_SET_ETHERNET_POWER_MANAGEMENT_FILTER\n"); + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_CDC_ECM_SET_ETHERNET_POWER_MANAGEMENT_FILTER; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_value = 1; + UX_TEST_CHECK_SUCCESS(ux_host_stack_transfer_request(transfer_request)); + + stepinfo(">>>>>>>>>>>>>>>>>>> Test UX_DEVICE_CLASS_CDC_ECM_GET_ETHERNET_POWER_MANAGEMENT_FILTER\n"); + transfer_request -> ux_transfer_request_requested_length = 2; + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_CDC_ECM_GET_ETHERNET_POWER_MANAGEMENT_FILTER; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_value = 0; + status = (ux_host_stack_transfer_request(transfer_request)); + if (status == UX_SUCCESS) + { + UX_TEST_ASSERT(buffer[0] == 1); + } + else + { + UX_TEST_CHECK_CODE(UX_TRANSFER_STALLED, status); + } + + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_CDC_ECM_SET_ETHERNET_POWER_MANAGEMENT_FILTER; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_value = 0; + UX_TEST_CHECK_SUCCESS(ux_host_stack_transfer_request(transfer_request)); + + stepinfo(">>>>>>>>>>>>>>>>>>> Test UX_DEVICE_CLASS_CDC_ECM_SET_ETHERNET_PACKET_FILTER\n"); + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_CDC_ECM_SET_ETHERNET_PACKET_FILTER; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_value = 1; + UX_TEST_CHECK_SUCCESS(ux_host_stack_transfer_request(transfer_request)); + + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_CDC_ECM_SET_ETHERNET_PACKET_FILTER; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_value = 0; + UX_TEST_CHECK_SUCCESS(ux_host_stack_transfer_request(transfer_request)); + + stepinfo(">>>>>>>>>>>>>>>>>>> Test unknown request\n"); + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_DEVICE_CLASS_CDC_ECM_SET_ETHERNET_PACKET_FILTER + 7; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_value = 0; + UX_TEST_CHECK_CODE(UX_TRANSFER_STALLED, ux_host_stack_transfer_request(transfer_request)); + + // stepinfo(">>>>>>>>>>>>>>>>>>> Test connect to avoid post post operation\n"); + // /* Connect. */ + // ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + // ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + // class_cdc_ecm_get_host(); + + stepinfo(">>>>>>>>>>>>>>>>>>> post_init_host done\n"); +} + +static void post_init_device() +{ + stepinfo(">>>>>>>>>>>>>>>>>>> post_init_device empty\n"); +} \ No newline at end of file diff --git a/test/regression/usbx_ux_device_class_cdc_ecm_deactivate_test.c b/test/regression/usbx_ux_device_class_cdc_ecm_deactivate_test.c new file mode 100644 index 00000000..9cf5a3be --- /dev/null +++ b/test/regression/usbx_ux_device_class_cdc_ecm_deactivate_test.c @@ -0,0 +1,48 @@ +/* Include necessary system files. */ + +#include "usbx_ux_test_cdc_ecm.h" + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_cdc_ecm_deactivate_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running ux_device_class_cdc_ecm_deactivate Test..................... "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static void post_init_host() +{ + + + stepinfo(">>>>>>>>>>>>>>>>>>> Test modify ux_slave_class_cdc_ecm_instance_deactivate\n"); + UX_TEST_ASSERT(cdc_ecm_device != UX_NULL); + cdc_ecm_device -> ux_slave_class_cdc_ecm_parameter.ux_slave_class_cdc_ecm_instance_deactivate = UX_NULL; + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_disconnect_slave(); + ux_test_disconnect_host_wait_for_enum_completion(); + + UX_TEST_ASSERT(cdc_ecm_device != UX_NULL); + + stepinfo(">>>>>>>>>>>>>>>>>>> Test connect to avoid post post operation\n"); + /* Connect. */ + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + class_cdc_ecm_get_host(); + + stepinfo(">>>>>>>>>>>>>>>>>>> post_init_host done\n"); +} + +static void post_init_device() +{ + stepinfo(">>>>>>>>>>>>>>>>>>> post_init_device empty\n"); +} \ No newline at end of file diff --git a/test/regression/usbx_ux_device_class_cdc_ecm_entry_test.c b/test/regression/usbx_ux_device_class_cdc_ecm_entry_test.c new file mode 100644 index 00000000..5472299c --- /dev/null +++ b/test/regression/usbx_ux_device_class_cdc_ecm_entry_test.c @@ -0,0 +1,62 @@ +/* Include necessary system files. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static ULONG error_callback_counter; + +static void count_error_callback(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ +UX_TEST_ERROR_CALLBACK_PARAMS *error = (UX_TEST_ERROR_CALLBACK_PARAMS *)params; + + // printf("error trap #%d: 0x%x, 0x%x, 0x%x\n", __LINE__, error->system_level, error->system_context, error->error_code); + error_callback_counter ++; +} + +static UX_TEST_HCD_SIM_ACTION count_on_error_trap[] = { +{ .usbx_function = UX_TEST_OVERRIDE_ERROR_CALLBACK, + .action_func = count_error_callback, +}, +{ 0 } +}; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_cdc_ecm_entry_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running ux_device_class_cdc_ecm_entry Test.......................... "); + + stepinfo("\n"); + + /* Override error trap. */ + ux_test_link_hooks_from_array(count_on_error_trap); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static void post_init_host() +{ + +UX_SLAVE_CLASS_COMMAND command; + + + stepinfo(">>>>>>>>>>>>>>>>>>> Test device connect\n"); + UX_TEST_ASSERT(cdc_ecm_device != UX_NULL); + + stepinfo(">>>>>>>>>>>>>>>>>>> Test invalid entry command request\n"); + error_callback_counter = 0; + command.ux_slave_class_command_request = 0xFF; + UX_TEST_CHECK_CODE(UX_FUNCTION_NOT_SUPPORTED, _ux_device_class_cdc_ecm_entry(&command)); + UX_ASSERT(error_callback_counter); + + stepinfo(">>>>>>>>>>>>>>>>>>> post_init_host done\n"); +} + +static void post_init_device() +{ + stepinfo(">>>>>>>>>>>>>>>>>>> post_init_device empty\n"); +} \ No newline at end of file diff --git a/test/regression/usbx_ux_device_class_cdc_ecm_initialize_test.c b/test/regression/usbx_ux_device_class_cdc_ecm_initialize_test.c new file mode 100644 index 00000000..d8225400 --- /dev/null +++ b/test/regression/usbx_ux_device_class_cdc_ecm_initialize_test.c @@ -0,0 +1,244 @@ +/* Include necessary system files. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static ULONG rsc_cdc_thread_usage; +static ULONG rsc_cdc_mutex_usage; +static ULONG rsc_cdc_event_usage; +static ULONG rsc_cdc_sem_usage; + +static ULONG error_callback_counter; + +static void count_error_callback(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ +UX_TEST_ERROR_CALLBACK_PARAMS *error = (UX_TEST_ERROR_CALLBACK_PARAMS *)params; + + // printf("error trap #%d: 0x%x, 0x%x, 0x%x\n", __LINE__, error->system_level, error->system_context, error->error_code); + error_callback_counter ++; +} + +static UX_TEST_HCD_SIM_ACTION count_on_error_trap[] = { +{ .usbx_function = UX_TEST_OVERRIDE_ERROR_CALLBACK, + .action_func = count_error_callback, +}, +{ 0 } +}; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_cdc_ecm_initialize_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running ux_device_class_cdc_ecm_initialize Test..................... "); + + stepinfo("\n"); + + /* Override error trap. */ + ux_test_link_hooks_from_array(count_on_error_trap); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static void post_init_host() +{ + +UINT status; +ULONG mem_free; +ULONG test_n; + + + /* Test device deinit. */ + stepinfo(">>>>>>>>>>>>>>>>>>> Test class deinit\n"); + ux_test_disconnect_slave(); + ux_test_disconnect_host_wait_for_enum_completion(); + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_ecm_name, ux_device_class_cdc_ecm_entry); + + /* Reset testing counts. */ + ux_test_utility_sim_thread_create_count_reset(); + ux_test_utility_sim_mutex_create_count_reset(); + ux_test_utility_sim_event_create_count_reset(); + ux_test_utility_sim_sem_create_count_reset(); + + stepinfo(">>>>>>>>>>>>>>>>>>> Test class init\n"); + UX_TEST_CHECK_SUCCESS(ux_device_stack_class_register(_ux_system_slave_class_cdc_ecm_name, ux_device_class_cdc_ecm_entry, 1, 0, &cdc_ecm_parameter)); + + /* Log create counts for further tests. */ + rsc_cdc_thread_usage = ux_test_utility_sim_thread_create_count(); + rsc_cdc_mutex_usage = ux_test_utility_sim_mutex_create_count(); + rsc_cdc_event_usage = ux_test_utility_sim_event_create_count(); + rsc_cdc_sem_usage = ux_test_utility_sim_sem_create_count(); + + if (rsc_cdc_thread_usage) stepinfo(">>>>>>>>>>>>>>>>>>> Thread errors cdc_ecm init test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_cdc_thread_usage; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_cdc_thread_usage - 1); + + /* Deinit. */ + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_ecm_name, ux_device_class_cdc_ecm_entry); + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d.%ld: Memory level different after re-init %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Set thread error generation */ + ux_test_utility_sim_thread_error_generation_start(test_n); + + /* Init. */ + + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_ecm_name, ux_device_class_cdc_ecm_entry, 1, 0, &cdc_ecm_parameter); + + /* Check error */ + if (status != UX_THREAD_ERROR && status != NX_PTR_ERROR) + { + + printf("ERROR #%d.%ld: code 0x%x\n", __LINE__, test_n, status); + test_control_return(1); + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + } + ux_test_utility_sim_thread_error_generation_stop(); + if (rsc_cdc_thread_usage) stepinfo("\n"); + + if (rsc_cdc_mutex_usage) stepinfo(">>>>>>>>>>>>>>>>>>> Mutex errors cdc_ecm init test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_cdc_mutex_usage; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_cdc_mutex_usage - 1); + + /* Deinit. */ + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_ecm_name, ux_device_class_cdc_ecm_entry); + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d.%ld: Memory level different after re-init %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Set thread error generation */ + ux_test_utility_sim_mutex_error_generation_start(test_n); + + /* Init. */ + + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_ecm_name, ux_device_class_cdc_ecm_entry, 1, 0, &cdc_ecm_parameter); + + /* Check error */ + if (status != UX_MUTEX_ERROR) + { + + printf("ERROR #%d.%ld: code 0x%x\n", __LINE__, test_n, status); + test_control_return(1); + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + } + ux_test_utility_sim_mutex_error_generation_stop(); + if (rsc_cdc_mutex_usage) stepinfo("\n"); + + if (rsc_cdc_sem_usage) stepinfo(">>>>>>>>>>>>>>>>>>> Semaphore errors cdc_ecm init test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_cdc_sem_usage; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_cdc_sem_usage - 1); + + /* Deinit. */ + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_ecm_name, ux_device_class_cdc_ecm_entry); + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d.%ld: Memory level different after re-init %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Set thread error generation */ + ux_test_utility_sim_sem_error_generation_start(test_n); + + /* Init. */ + + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_ecm_name, ux_device_class_cdc_ecm_entry, 1, 0, &cdc_ecm_parameter); + + /* Check error */ + if (status != UX_SEMAPHORE_ERROR) + { + + printf("ERROR #%d.%ld: code 0x%x\n", __LINE__, test_n, status); + test_control_return(1); + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + } + ux_test_utility_sim_sem_error_generation_stop(); + if (rsc_cdc_sem_usage) stepinfo("\n"); + + if (rsc_cdc_event_usage) stepinfo(">>>>>>>>>>>>>>>>>>> EventFlag errors cdc_ecm init test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_cdc_event_usage; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_cdc_event_usage - 1); + + /* Deinit. */ + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_ecm_name, ux_device_class_cdc_ecm_entry); + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d.%ld: Memory level different after re-init %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Set thread error generation */ + ux_test_utility_sim_event_error_generation_start(test_n); + + /* Init. */ + + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_ecm_name, ux_device_class_cdc_ecm_entry, 1, 0, &cdc_ecm_parameter); + + /* Check error */ + if (status != UX_EVENT_ERROR) + { + + printf("ERROR #%d.%ld: code 0x%x\n", __LINE__, test_n, status); + test_control_return(1); + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + } + ux_test_utility_sim_event_error_generation_stop(); + if (rsc_cdc_event_usage) stepinfo("\n"); + + stepinfo(">>>>>>>>>>>>>>>>>>> Test connect to avoid post post operation\n"); + /* Connect. */ + UX_TEST_CHECK_SUCCESS(ux_device_stack_class_register(_ux_system_slave_class_cdc_ecm_name, ux_device_class_cdc_ecm_entry, 1, 0, &cdc_ecm_parameter)); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + class_cdc_ecm_get_host(); + + stepinfo(">>>>>>>>>>>>>>>>>>> post_init_host done\n"); +} + +static void post_init_device() +{ + stepinfo(">>>>>>>>>>>>>>>>>>> post_init_device empty\n"); +} \ No newline at end of file diff --git a/test/regression/usbx_ux_device_class_cdc_ecm_interrupt_thread_test.c b/test/regression/usbx_ux_device_class_cdc_ecm_interrupt_thread_test.c new file mode 100644 index 00000000..5ba6d331 --- /dev/null +++ b/test/regression/usbx_ux_device_class_cdc_ecm_interrupt_thread_test.c @@ -0,0 +1,110 @@ +/* Include necessary system files. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static ULONG error_callback_counter; + +static void count_error_callback(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ +UX_TEST_ERROR_CALLBACK_PARAMS *error = (UX_TEST_ERROR_CALLBACK_PARAMS *)params; + + // printf("error trap #%d: 0x%x, 0x%x, 0x%x\n", __LINE__, error->system_level, error->system_context, error->error_code); + error_callback_counter ++; +} + +static UX_TEST_HCD_SIM_ACTION count_on_error_trap[] = { +{ .usbx_function = UX_TEST_OVERRIDE_ERROR_CALLBACK, + .action_func = count_error_callback, +}, +{ 0 } +}; + +static UX_TEST_ACTION interrupt_transfer_replace[] = +{ + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP | UX_TEST_SIM_REQ_ANSWER, + .req_ep_address = 0x83, + .req_actual_len = UX_DEVICE_CLASS_CDC_ECM_INTERRUPT_RESPONSE_LENGTH, + .req_status = UX_SUCCESS, + .status = UX_SUCCESS, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, +{ 0 }, +}; + + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_cdc_ecm_interrupt_thread_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running ux_device_class_cdc_ecm_interrupt_thread Test............... "); + + stepinfo("\n"); + + /* Override error trap. */ + ux_test_link_hooks_from_array(count_on_error_trap); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static void post_init_host() +{ + + + stepinfo(">>>>>>>>>>>>>>>>>>> Test activate check\n"); + UX_TEST_ASSERT(cdc_ecm_device != UX_NULL); + + /* Disable the other threads. */ + _ux_utility_thread_suspend(&cdc_ecm_device->ux_slave_class_cdc_ecm_bulkin_thread); + _ux_utility_thread_suspend(&cdc_ecm_device->ux_slave_class_cdc_ecm_bulkout_thread); + +#if 0 + stepinfo(">>>>>>>>>>>>>>>>>>> Test get ux_slave_class_cdc_ecm_event_flags_group error\n"); + _ux_utility_event_flags_delete(&cdc_ecm_device -> ux_slave_class_cdc_ecm_event_flags_group); + _ux_utility_thread_sleep(1); +#endif +#if 0 + stepinfo(">>>>>>>>>>>>>>>>>>> Test get ux_slave_class_cdc_ecm_event_flags_group actual flag error\n"); + _ux_utility_event_flags_create(&cdc_ecm_device -> ux_slave_class_cdc_ecm_event_flags_group, "ux_device_class_cdc_ecm_event_flag"); + _ux_utility_event_flags_set(&cdc_ecm_device -> ux_slave_class_cdc_ecm_event_flags_group, UX_DEVICE_CLASS_CDC_ECM_NEW_INTERRUPT_EVENT, TX_OR); + _ux_utility_thread_sleep(1); +#endif + + stepinfo(">>>>>>>>>>>>>>>>>>> Test interrupt transfer UX_TRANSFER_BUS_RESET\n"); + interrupt_transfer_replace[0].req_status = UX_TRANSFER_BUS_RESET; + interrupt_transfer_replace[0].status = UX_TRANSFER_BUS_RESET; + ux_test_dcd_sim_slave_set_actions(interrupt_transfer_replace); + _ux_utility_event_flags_set(&cdc_ecm_device -> ux_slave_class_cdc_ecm_event_flags_group, UX_DEVICE_CLASS_CDC_ECM_NETWORK_NOTIFICATION_EVENT, TX_OR); + _ux_utility_thread_sleep(2); + + stepinfo(">>>>>>>>>>>>>>>>>>> Test interrupt transfer UX_ERROR\n"); + interrupt_transfer_replace[0].req_status = UX_ERROR; + interrupt_transfer_replace[0].status = UX_ERROR; + ux_test_dcd_sim_slave_set_actions(interrupt_transfer_replace); + error_callback_counter = 0; + _ux_utility_event_flags_set(&cdc_ecm_device -> ux_slave_class_cdc_ecm_event_flags_group, UX_DEVICE_CLASS_CDC_ECM_NETWORK_NOTIFICATION_EVENT, TX_OR); + _ux_utility_thread_sleep(2); + UX_TEST_ASSERT(error_callback_counter > 0); + + stepinfo(">>>>>>>>>>>>>>>>>>> Test connect to avoid post post operation\n"); + /* Connect. */ + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + class_cdc_ecm_get_host(); + + stepinfo(">>>>>>>>>>>>>>>>>>> post_init_host done\n"); +} + +static void post_init_device() +{ + stepinfo(">>>>>>>>>>>>>>>>>>> post_init_device empty\n"); +} \ No newline at end of file diff --git a/test/regression/usbx_ux_device_class_cdc_ecm_uninitialize_test.c b/test/regression/usbx_ux_device_class_cdc_ecm_uninitialize_test.c new file mode 100644 index 00000000..6071c3c6 --- /dev/null +++ b/test/regression/usbx_ux_device_class_cdc_ecm_uninitialize_test.c @@ -0,0 +1,384 @@ +/* Include necessary system files. */ + +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_network_driver.h" +#include "ux_host_class_cdc_ecm.h" +#include "ux_device_class_cdc_ecm.h" +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" +#include "ux_test.h" + +#define DEMO_IP_THREAD_STACK_SIZE (8*1024) +#define HOST_IP_ADDRESS IP_ADDRESS(192,168,1,176) +#define HOST_SOCKET_PORT_UDP 45054 +#define DEVICE_IP_ADDRESS IP_ADDRESS(192,168,1,175) +#define DEVICE_SOCKET_PORT_UDP 45055 + +#define PACKET_PAYLOAD 1400 +#define PACKET_POOL_SIZE (PACKET_PAYLOAD*20) +#define ARP_MEMORY_SIZE 1024 + +/* Define local constants. */ + +#define UX_DEMO_STACK_SIZE (4*1024) +#define UX_USBX_MEMORY_SIZE (128*1024) + +/* Host */ + +static CHAR global_buffer_write_host[128]; +static CHAR global_buffer_read_host[128]; +static ULONG global_basic_test_num_writes_host; +static ULONG global_basic_test_num_reads_host; +static UX_HOST_CLASS *class_driver_host; +static UX_HOST_CLASS_CDC_ECM *cdc_ecm_host; +static TX_THREAD thread_host; +static UCHAR thread_stack_host[UX_DEMO_STACK_SIZE]; +static NX_IP nx_ip_host; + +/* Device */ + +static CHAR global_buffer_write_device[128]; +static CHAR global_buffer_read_device[128]; +static ULONG global_basic_test_num_writes_device; +static ULONG global_basic_test_num_reads_device; +static TX_THREAD thread_device; +static UX_HOST_CLASS *class_driver_device; +static UX_SLAVE_CLASS_CDC_ECM *cdc_ecm_device; +static UX_SLAVE_CLASS_CDC_ECM_PARAMETER cdc_ecm_parameter; +static UCHAR thread_stack_device[UX_DEMO_STACK_SIZE]; +static NX_IP nx_ip_device; + +/* Define local prototypes and definitions. */ +static void thread_entry_host(ULONG arg); +static void thread_entry_device(ULONG arg); + +static UCHAR usbx_memory[UX_USBX_MEMORY_SIZE]; + +static unsigned char device_framework_high_speed[] = { + + /* Device Descriptor */ + 0x12, /* bLength */ + 0x01, /* bDescriptorType */ + 0x10, 0x01, /* bcdUSB */ + 0xef, /* bDeviceClass - Depends on bDeviceSubClass */ + 0x02, /* bDeviceSubClass - Depends on bDeviceProtocol */ + 0x01, /* bDeviceProtocol - There's an IAD */ + 0x40, /* bMaxPacketSize0 */ + 0x70, 0x07, /* idVendor */ + 0x42, 0x10, /* idProduct */ + 0x00, 0x01, /* bcdDevice */ + 0x01, /* iManufacturer */ + 0x02, /* iProduct */ + 0x03, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ + + /* Configuration Descriptor */ + 0x09, /* bLength */ + 0x02, /* bDescriptorType */ + + 0x58, 0x00, /* wTotalLength */ + 0x02, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xc0, /* bmAttributes - Self-powered */ + 0x00, /* bMaxPower */ + + /* Interface Association Descriptor */ + 0x08, /* bLength */ + 0x0b, /* bDescriptorType */ + 0x00, /* bFirstInterface */ + 0x02, /* bInterfaceCount */ + 0x02, /* bFunctionClass - CDC - Communication */ + 0x06, /* bFunctionSubClass - ECM */ + 0x00, /* bFunctionProtocol - No class specific protocol required */ + 0x00, /* iFunction */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x02, /* bInterfaceClass - CDC - Communication */ + 0x06, /* bInterfaceSubClass - ECM */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* CDC Header Functional Descriptor */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x00, /* bDescriptorSubType */ + 0x10, 0x01, /* bcdCDC */ + + /* CDC ECM Functional Descriptor */ + 0x0d, /* bLength */ + 0x24, /* bDescriptorType */ + 0x0f, /* bDescriptorSubType */ + 0x04, /* iMACAddress */ + 0x00, 0x00, 0x00, 0x00, /* bmEthernetStatistics */ + 0xea, 0x05, /* wMaxSegmentSize */ + 0x00, 0x00, /* wNumberMCFilters */ + 0x00, /* bNumberPowerFilters */ + + /* CDC Union Functional Descriptor */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x06, /* bDescriptorSubType */ + 0x00, /* bmMasterInterface */ + 0x01, /* bmSlaveInterface0 */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x83, /* bEndpointAddress */ + 0x03, /* bmAttributes - Interrupt */ + 0x08, 0x00, /* wMaxPacketSize */ + 0x08, /* bInterval */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x01, /* bAlternateSetting */ + 0x02, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x02, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x81, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + +}; + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL CDCECM Device" */ + 0x09, 0x04, 0x02, 0x10, + 0x45, 0x4c, 0x20, 0x43, 0x44, 0x43, 0x45, 0x43, + 0x4d, 0x20, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31, + + /* MAC Address string descriptor : Index 4 - "001E5841B879" */ + 0x09, 0x04, 0x04, 0x0C, + 0x30, 0x30, 0x31, 0x45, 0x35, 0x38, + 0x34, 0x31, 0x42, 0x38, 0x37, 0x39, + +}; + +static unsigned char *device_framework_full_speed = device_framework_high_speed; +#define FRAMEWORK_LENGTH sizeof(device_framework_high_speed) + + /* 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 + }; + +/* Define local variables. */ + +static void class_cdc_ecm_get_host(void) +{ + +UX_HOST_CLASS *class; + + /* Find the main storage container */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_class_get(_ux_system_host_class_cdc_ecm_name, &class)); + + /* We get the first instance of the storage device */ + UX_TEST_CHECK_SUCCESS(ux_test_host_stack_class_instance_get(class, 0, (void **) &cdc_ecm_host)); + + /* We still need to wait for the cdc-ecm status to be live */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uint(&cdc_ecm_host -> ux_host_class_cdc_ecm_state, UX_HOST_CLASS_INSTANCE_LIVE)); +} + +static VOID demo_cdc_ecm_instance_activate(VOID *cdc_ecm_instance) +{ + + /* Save the CDC instance. */ + cdc_ecm_device = (UX_SLAVE_CLASS_CDC_ECM *) cdc_ecm_instance; +} + +static VOID demo_cdc_ecm_instance_deactivate(VOID *cdc_ecm_instance) +{ + + /* Reset the CDC instance. */ + cdc_ecm_device = UX_NULL; +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_cdc_ecm_uninitialize_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running ux_device_class_cdc_ecm_uninitialize Test................... "); + + stepinfo("\n"); + + /* Initialize USBX Memory. */ + ux_system_initialize((CHAR *)usbx_memory, UX_USBX_MEMORY_SIZE, UX_NULL, 0); + + /* It looks weird if this doesn't have a comment! */ + ux_utility_error_callback_register(ux_test_error_callback); + + /* Perform the initialization of the network driver. */ + UX_TEST_CHECK_SUCCESS(ux_network_driver_init()); + + nx_system_initialize(); + + /* Create the slave thread. */ + UX_TEST_CHECK_SUCCESS(tx_thread_create(&thread_device, "device thread", thread_entry_device, 0, + thread_stack_device, UX_DEMO_STACK_SIZE, + 30, 30, 1, TX_AUTO_START)); +} + +static void thread_entry_device(ULONG input) +{ + +ULONG free_memory_pre_init; +ULONG free_memory_post_uninit; +UX_SLAVE_CLASS *class; +UX_SLAVE_CLASS_CDC_ECM *cdc_ecm; +UX_SLAVE_CLASS_COMMAND command; + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + UX_TEST_CHECK_SUCCESS(ux_device_stack_initialize(device_framework_high_speed, FRAMEWORK_LENGTH, + device_framework_full_speed, FRAMEWORK_LENGTH, + string_framework, sizeof(string_framework), + language_id_framework, sizeof(language_id_framework), + UX_NULL)); + + /* Set the parameters for callback when insertion/extraction of a CDC device. Set to NULL.*/ + cdc_ecm_parameter.ux_slave_class_cdc_ecm_instance_activate = demo_cdc_ecm_instance_activate; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_instance_deactivate = demo_cdc_ecm_instance_deactivate; + + /* Define a NODE ID. */ + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_local_node_id[0] = 0x00; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_local_node_id[1] = 0x1e; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_local_node_id[2] = 0x58; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_local_node_id[3] = 0x41; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_local_node_id[4] = 0xb8; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_local_node_id[5] = 0x78; + + /* Define a remote NODE ID. */ + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_remote_node_id[0] = 0x00; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_remote_node_id[1] = 0x1e; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_remote_node_id[2] = 0x58; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_remote_node_id[3] = 0x41; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_remote_node_id[4] = 0xb8; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_remote_node_id[5] = 0x79; + + /* Test. */ + { + /* Save the amount of free memory before initing. */ + free_memory_pre_init = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + /* Initialize the device cdc_ecm class. */ + UX_TEST_CHECK_SUCCESS(ux_device_stack_class_register(_ux_system_slave_class_cdc_ecm_name, ux_device_class_cdc_ecm_entry, 1, 0, &cdc_ecm_parameter)); + + /* And deinitialize the class. */ + UX_TEST_CHECK_SUCCESS(ux_device_stack_class_unregister(_ux_system_slave_class_cdc_ecm_name, ux_device_class_cdc_ecm_entry)); + + /* Save the amount of free memory after uniniting. */ + free_memory_post_uninit = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + /* Make sure they're the same. */ + UX_TEST_ASSERT(free_memory_pre_init == free_memory_post_uninit); + + } + + /* Test: class instance freed before invoking uninitialize. */ + { + /* Save the amount of free memory before initing. */ + free_memory_pre_init = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + /* Initialize the device cdc_ecm class. */ + UX_TEST_CHECK_SUCCESS(ux_device_stack_class_register(_ux_system_slave_class_cdc_ecm_name, ux_device_class_cdc_ecm_entry, 1, 0, &cdc_ecm_parameter)); + + /* Obtain class driver. */ + class = &_ux_system_slave -> ux_system_slave_class_array[0]; + + /* Confirm class registered. */ + UX_TEST_ASSERT(class -> ux_slave_class_status == UX_USED); + UX_TEST_ASSERT(class -> ux_slave_class_instance != UX_NULL); + + /* Modify class instance for test. */ + cdc_ecm = (UX_SLAVE_CLASS_CDC_ECM *)class -> ux_slave_class_instance; + class -> ux_slave_class_instance = UX_NULL; + + /* And deinitialize the class, unregister is not used since it may change class state. */ + command.ux_slave_class_command_request = UX_SLAVE_CLASS_COMMAND_UNINITIALIZE; + command.ux_slave_class_command_class_ptr = class; + UX_TEST_CHECK_SUCCESS(ux_device_class_cdc_ecm_entry(&command)); + + /* Memory still valid. */ + // UX_TEST_ASSERT(cdc_ecm -> ux_slave_class_cdc_ecm_pool_memory != UX_NULL); + + /* Restore normal data. */ + class -> ux_slave_class_instance = (VOID*)cdc_ecm; + + /* And deinitialize the class. */ + UX_TEST_CHECK_SUCCESS(ux_device_stack_class_unregister(_ux_system_slave_class_cdc_ecm_name, ux_device_class_cdc_ecm_entry)); + + /* Save the amount of free memory after uniniting. */ + free_memory_post_uninit = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + /* Make sure they're the same. */ + UX_TEST_ASSERT(free_memory_pre_init == free_memory_post_uninit); + } + + /* Deinitialize the device side of usbx. */ + UX_TEST_CHECK_SUCCESS(_ux_device_stack_uninitialize()); + + /* And finally the usbx system resources. */ + _ux_system_uninitialize(); + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} diff --git a/test/regression/usbx_ux_device_class_hid_activate_test.c b/test/regression/usbx_ux_device_class_hid_activate_test.c new file mode 100644 index 00000000..aa03a00e --- /dev/null +++ b/test/regression/usbx_ux_device_class_hid_activate_test.c @@ -0,0 +1,371 @@ +/* This file tests the ux_device_class_hid_activate API. */ + +#include "usbx_test_common_hid.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#include "ux_host_class_hid_mouse.h" +#include "ux_host_class_hid_keyboard.h" + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UINT was_instance_activate_callback_called; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#define HID_REPORT_LENGTH sizeof(hid_report_descriptor)/sizeof(hid_report_descriptor[0]) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* HID Mouse interface descriptors 9+9+7=25 bytes */ +#define HID_MOUSE_IFC_DESC_ALL(ifc, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 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, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_MOUSE_IFC_DESC_ALL_LEN 25 + +/* HID Mouse interface descriptors 9+9+7+7=32 bytes */ +#define HID_TEST_IFC_DESC_ALL(ifc, epa0, epa0_type, epa1, epa1_type) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x02, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_REPORT_LENGTH),\ + MSB(HID_REPORT_LENGTH),\ + /* Endpoint descriptor */\ + 0x07, 0x05, (epa0), (epa0_type), 0x08, 0x00, 0x08,\ + /* Endpoint descriptor */\ + 0x07, 0x05, (epa1), (epa1_type), 0x08, 0x00, 0x08, +#define HID_TEST_IFC_DESC_ALL_LEN 32 + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC(CFG_DESC_LEN+2*HID_TEST_IFC_DESC_ALL_LEN, 2, 1) + /* Interrupt IN @ 1st */ + HID_TEST_IFC_DESC_ALL(0, 0x81, 3, 0x02, 3) + /* HID interface but no interrupt IN */ + HID_TEST_IFC_DESC_ALL(1, 0x84, 2, 0x03, 3) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC(CFG_DESC_LEN+HID_MOUSE_IFC_DESC_ALL_LEN+HID_TEST_IFC_DESC_ALL_LEN, 2, 1) + /* Good HID interface. */ + HID_MOUSE_IFC_DESC_ALL(0, 0x81) + /* Interrupt IN @ 2nd. */ + HID_TEST_IFC_DESC_ALL(1, 0x03, 3, 0x84, 3) +}; +#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 + 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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID instance_activate_callback(VOID *parameter) +{ + + was_instance_activate_callback_called = 1; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + // printf("Error on line %d: 0x%x, 0x%x, 0x%x\n", __LINE__, system_level, system_context, error_code); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_hid_activate_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_hid_activate test .......................... "); + stepinfo("\n"); + + /* 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, error code: 0x%x\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } +#if 0 + /* Register the HID client(s). */ + status = ux_host_class_hid_client_register(_ux_system_host_class_hid_client_mouse_name, ux_host_class_hid_mouse_entry); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } +#endif + /* 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, error code: 0x%x\n", __LINE__, status); + 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; + hid_parameter.ux_slave_class_hid_instance_activate = instance_activate_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,0, (VOID *)&hid_parameter); + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,1, (VOID *)&hid_parameter); + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,2, (VOID *)&hid_parameter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if(status!=UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } +#endif + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_DEVICE *device; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; + + stepinfo(">>>>>>>>>> Thread start\n"); + + _ux_utility_delay_ms(500); + + /* Get device instance. */ + status = ux_host_stack_device_get(0, &device); + + if (status != UX_SUCCESS) + { + printf("ERROR #%d: get_device fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Get control endpoint. */ + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + stepinfo(">>>>>>>>>> Disconnect\n"); + + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + stepinfo(">>>>>>>>>> Connect\n"); + + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + _ux_utility_delay_ms(500); + + stepinfo(">>>>>>>>>> Test done\n"); + + /* 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_device_class_hid_activate_test2.c b/test/regression/usbx_ux_device_class_hid_activate_test2.c new file mode 100644 index 00000000..27efee8b --- /dev/null +++ b/test/regression/usbx_ux_device_class_hid_activate_test2.c @@ -0,0 +1,315 @@ +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 */ + 0x07, 0x05, + 0x02, /* Set direction to OUT, which is wrong. */ + 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 */ + 0x07, 0x05, + 0x02, /* Set direction to OUT, which is wrong. */ + 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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_hid_activate_test2_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_hid_activate Test 2....................... "); + + /* 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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); + } + + /* 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_device_class_hid_activate_test3.c b/test/regression/usbx_ux_device_class_hid_activate_test3.c new file mode 100644 index 00000000..17dc47f3 --- /dev/null +++ b/test/regression/usbx_ux_device_class_hid_activate_test3.c @@ -0,0 +1,315 @@ +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 */ + 0x07, 0x05, 0x82, + 0x02, /* Set type to non-interrupt (bulk), which is wrong. */ + 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 */ + 0x07, 0x05, 0x82, + 0x02, /* Set type to non-interrupt (bulk), which is wrong. */ + 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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_hid_activate_test3_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_hid_activate Test 3....................... "); + + /* 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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); + } + + /* 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_device_class_hid_basic_memory_test.c b/test/regression/usbx_ux_device_class_hid_basic_memory_test.c new file mode 100644 index 00000000..9f72b178 --- /dev/null +++ b/test/regression/usbx_ux_device_class_hid_basic_memory_test.c @@ -0,0 +1,834 @@ +/* This file tests the ux_device_class_hid API. */ + +#include "usbx_test_common_hid.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#include "ux_host_class_hid_mouse.h" +#include "ux_host_class_hid_keyboard.h" +#include "ux_host_class_hid_remote_control.h" + + +static UCHAR hid_keyboard_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0, // END_COLLECTION + + 0xa1, 0x01, // COLLECTION (Application) + 0x19, 0x01, // USAGE_MINIMUM (1) + 0x29, 0x04, // USAGE_MAXIMUM (4) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x04, // REPORT_COUNT (4) + 0xb1, 0x02, // FEATURE (Data,Var,Abs) + 0x85, 0x02, // REPORT_ID (2) + 0x19, 0x05, // USAGE_MINIMUM (5) + 0x29, 0x07, // USAGE_MAXIMUM (7) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x03, // REPORT_COUNT (3) + 0xb1, 0x02, // FEATURE (Data,Var,Abs) + 0x85, 0x04, // REPORT_ID (4) + 0x09, 0x08, // USAGE (8) + 0x75, 0x10, // REPORT_SIZE (16) + 0x95, 0x01, // REPORT_COUNT (1) + 0xb1, 0x02, // FEATURE (Data,Var,Abs) + 0xc0, // END_COLLECTION +}; +#define HID_KEYBOARD_REPORT_LENGTH sizeof(hid_keyboard_report)/sizeof(hid_keyboard_report[0]) + + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +static UCHAR hid_remote_control_report[] = { + + 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) + 0x09, 0x01, // USAGE (Consumer Control) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x02, // USAGE (Numeric Key Pad) + 0xa1, 0x02, // COLLECTION (Logical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x0a, // USAGE_MAXIMUM (Button 10) + 0x15, 0x01, // LOGICAL_MINIMUM (1) + 0x25, 0x0a, // LOGICAL_MAXIMUM (10) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0, // END_COLLECTION + 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) + 0x09, 0x86, // USAGE (Channel) + 0x09, 0xe0, // USAGE (Volume) + 0x15, 0xff, // LOGICAL_MINIMUM (-1) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x02, // REPORT_SIZE (2) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x46, // INPUT (Data,Var,Rel,Null) + 0xc0 // END_COLLECTION +}; +#define HID_REMOTE_CONTROL_REPORT_LENGTH (sizeof(hid_remote_control_report)/sizeof(hid_remote_control_report[0])) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN (9) + + +/* HID Mouse/Keyboard interface descriptors 9+9+7=25 bytes */ +#define HID_IFC_DESC_ALL(ifc, report_len, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(report_len),\ + MSB(report_len),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_IFC_DESC_ALL_LEN (9+9+7) + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC(CFG_DESC_LEN+3*HID_IFC_DESC_ALL_LEN, 2, 1) + /* Keyboard */ + HID_IFC_DESC_ALL(0, HID_KEYBOARD_REPORT_LENGTH, 0x82) + /* Mouse */ + HID_IFC_DESC_ALL(1, HID_MOUSE_REPORT_LENGTH, 0x81) + /* Remote control */ + HID_IFC_DESC_ALL(2, HID_REMOTE_CONTROL_REPORT_LENGTH, 0x83) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC(CFG_DESC_LEN+3*HID_IFC_DESC_ALL_LEN, 2, 1) + /* Keyboard */ + HID_IFC_DESC_ALL(0, HID_KEYBOARD_REPORT_LENGTH, 0x82) + /* Mouse */ + HID_IFC_DESC_ALL(1, HID_MOUSE_REPORT_LENGTH, 0x81) + /* Remote control */ + HID_IFC_DESC_ALL(2, HID_REMOTE_CONTROL_REPORT_LENGTH, 0x83) +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +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 +}; +#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. */ +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +static UX_HOST_CLASS_HID *hid = UX_NULL; +static UX_HOST_CLASS_HID_MOUSE *hid_mouse = UX_NULL; +static UX_HOST_CLASS_HID_KEYBOARD *hid_keyboard = UX_NULL; +static UX_HOST_CLASS_HID_REMOTE_CONTROL *hid_remote_control = UX_NULL; + +static UX_SLAVE_CLASS_HID *hid_mouse_slave = UX_NULL; +static UX_SLAVE_CLASS_HID *hid_keyboard_slave = UX_NULL; +static UX_SLAVE_CLASS_HID *hid_remote_control_slave = UX_NULL; + +static UX_SLAVE_CLASS_HID_PARAMETER hid_mouse_parameter; +static UX_SLAVE_CLASS_HID_PARAMETER hid_keyboard_parameter; +static UX_SLAVE_CLASS_HID_PARAMETER hid_remote_control_parameter; + +static ULONG rsc_mem_alloc_cnt_on_set_cfg; +static ULONG rsc_enum_mem_alloc_count; +static ULONG rsc_hid_mem_alloc_count; + +static ULONG error_callback_counter; +static UCHAR error_callback_ignore; + +static ULONG error_counter = 0; + +static UINT ux_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_HID_CLIENT *client = (UX_HOST_CLASS_HID_CLIENT *)inst; +UINT is_mouse = (UX_SUCCESS == _ux_utility_memory_compare(client->ux_host_class_hid_client_name, + _ux_system_host_class_hid_client_mouse_name, + _ux_utility_string_length_get(_ux_system_host_class_hid_client_mouse_name))); +UINT is_keyboard = (UX_SUCCESS == _ux_utility_memory_compare(client->ux_host_class_hid_client_name, + _ux_system_host_class_hid_client_keyboard_name, + _ux_utility_string_length_get(_ux_system_host_class_hid_client_keyboard_name))); + + // if(event >= UX_HID_CLIENT_INSERTION) printf("hChg: ev %lx, cls %p, inst %p, %s\n", event, cls, inst, is_mouse ? "Mouse" : "Keyboard"); + switch(event) + { + + case UX_HID_CLIENT_INSERTION: + if (is_mouse) + hid_mouse = (UX_HOST_CLASS_HID_MOUSE *)client->ux_host_class_hid_client_local_instance; + else + { + if (is_keyboard) + hid_keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)client->ux_host_class_hid_client_local_instance; + else + hid_remote_control = (UX_HOST_CLASS_HID_REMOTE_CONTROL *)client->ux_host_class_hid_client_local_instance; + } + break; + + case UX_HID_CLIENT_REMOVAL: + if (is_mouse) + hid_mouse = UX_NULL; + else + { + if (is_keyboard) + hid_keyboard = UX_NULL; + else + hid_remote_control = UX_NULL; + } + break; + + default: + break; + } + return 0; +} + +static VOID mouse_instance_activate_callback(VOID *parameter) +{ + // printf("dMouse: %p\n", parameter); + hid_mouse_slave = (UX_SLAVE_CLASS_HID *)parameter; +} + +static VOID keyboard_instance_activate_callback(VOID *parameter) +{ + // printf("dKeyboard: %p\n", parameter); + hid_keyboard_slave = (UX_SLAVE_CLASS_HID *)parameter; +} + +static VOID remote_control_instance_activate_callback(VOID *parameter) +{ + // printf("dKeyboard: %p\n", parameter); + hid_remote_control_slave = (UX_SLAVE_CLASS_HID *)parameter; +} + +static VOID instance_deactivate_callback(VOID *parameter) +{ + // printf("dRm: %p\n", parameter); + if ((VOID *)hid_mouse_slave == parameter) + hid_mouse_slave = UX_NULL; + + if ((VOID *)hid_keyboard_slave == parameter) + hid_keyboard_slave = UX_NULL; + + if ((VOID *)hid_remote_control_slave == parameter) + hid_remote_control_slave = UX_NULL; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (error_code == UX_MEMORY_INSUFFICIENT) + error_callback_counter ++; + // printf("ERROR #%d: 0x%x, 0x%x, 0x%x\n", __LINE__, system_level, system_context, error_code); +} + +static UINT break_on_all_activated(VOID) +{ + + if (hid_mouse_slave == UX_NULL) + return 0; + if (hid_keyboard_slave == UX_NULL) + return 0; + if (hid_remote_control_slave == UX_NULL) + return 0; + if (hid_mouse == UX_NULL) + return 0; + if (hid_keyboard == UX_NULL) + return 0; + if (hid_remote_control == UX_NULL) + return 0; + + return 1; +} + + +static UINT break_on_all_removed(VOID) +{ + if (hid_mouse_slave || hid_keyboard_slave || hid_remote_control_slave) + return 0; + if (hid_mouse || hid_keyboard || hid_remote_control) + return 0; + + return 1; +} + + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *_params) +{ + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); +} + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_hid_basic_memory_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +ULONG mem_free; +ULONG alloc_count; +ULONG test_n; + + /* Inform user. */ + printf("Running ux_device_class_hid Basic Memory test ...................... "); + stepinfo("\n"); + + /* Initialize memory logger. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + + /* 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 #%d, code 0x%x\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + 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 #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Register the HID client(s). */ + status |= ux_host_class_hid_client_register(_ux_system_host_class_hid_client_mouse_name, ux_host_class_hid_mouse_entry); + status |= ux_host_class_hid_client_register(_ux_system_host_class_hid_client_keyboard_name, ux_host_class_hid_keyboard_entry); + status |= ux_host_class_hid_client_register(_ux_system_host_class_hid_client_remote_control_name, ux_host_class_hid_remote_control_entry); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if (status != UX_SUCCESS) + { + + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } +#endif + + /* 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, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Initialize the hid class parameters for mouse and keyboard. */ + hid_mouse_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_mouse_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_REPORT_LENGTH; + hid_mouse_parameter.ux_device_class_hid_parameter_callback = demo_thread_hid_callback; + hid_mouse_parameter.ux_slave_class_hid_instance_activate = mouse_instance_activate_callback; + hid_mouse_parameter.ux_slave_class_hid_instance_deactivate = instance_deactivate_callback; + + hid_keyboard_parameter.ux_device_class_hid_parameter_report_address = hid_keyboard_report; + hid_keyboard_parameter.ux_device_class_hid_parameter_report_length = HID_KEYBOARD_REPORT_LENGTH; + hid_keyboard_parameter.ux_device_class_hid_parameter_callback = demo_thread_hid_callback; + hid_keyboard_parameter.ux_slave_class_hid_instance_activate = keyboard_instance_activate_callback; + hid_keyboard_parameter.ux_slave_class_hid_instance_deactivate = instance_deactivate_callback; + + hid_remote_control_parameter.ux_device_class_hid_parameter_report_address = hid_remote_control_report; + hid_remote_control_parameter.ux_device_class_hid_parameter_report_length = HID_REMOTE_CONTROL_REPORT_LENGTH; + hid_remote_control_parameter.ux_device_class_hid_parameter_callback = demo_thread_hid_callback; + hid_remote_control_parameter.ux_slave_class_hid_instance_activate = remote_control_instance_activate_callback; + hid_remote_control_parameter.ux_slave_class_hid_instance_deactivate = instance_deactivate_callback; + + stepinfo(">>>>>>>>>> Test HID Class Initialize/deinitialize memory\n"); + + stepinfo(">>>>>>>>>> - Reset counts\n"); + ux_test_utility_sim_mem_alloc_count_reset(); + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + stepinfo(">>>>>>>>>> - _class_register\n"); + + /* Initilize the device hid class. */ + status = ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,1, (VOID *)&hid_mouse_parameter); + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,0, (VOID *)&hid_keyboard_parameter); + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,2, (VOID *)&hid_remote_control_parameter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } +#endif +#if 1 + /* Log create counts when instances active for further tests. */ + alloc_count = ux_test_utility_sim_mem_alloc_count(); + + /* Lock log base for tests. */ + ux_test_utility_sim_mem_alloc_log_lock(); + + stepinfo("init & uninit alloc : %ld\n", alloc_count); + stepinfo("mem free : %ld, %ld\n", _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); + + if (alloc_count) stepinfo(">>>>>>>>>> - Init/deinit memory errors test\n"); + mem_free = (~0); + for (test_n = 0; test_n < alloc_count; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, alloc_count - 1); + + /* Unregister. */ + ux_device_stack_class_unregister(_ux_system_slave_class_hid_name, ux_device_class_hid_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_hid_name, ux_device_class_hid_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_hid_name, ux_device_class_hid_entry); + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + error_counter ++; + test_control_return(1); + } + + /* Set memory error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n); + + /* Register. */ + status = ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,1, (VOID *)&hid_mouse_parameter); + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,0, (VOID *)&hid_keyboard_parameter); + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,2, (VOID *)&hid_remote_control_parameter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + /* Check error */ + if (status == UX_SUCCESS) + { + + printf("ERROR #%d.%ld: registered when there is memory error\n", __LINE__, test_n); + error_counter ++; + } +#endif + + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + } + ux_test_utility_sim_mem_alloc_error_generation_stop(); + if (alloc_count) stepinfo("\n"); + + /* Unregister. */ + ux_device_stack_class_unregister(_ux_system_slave_class_hid_name, ux_device_class_hid_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_hid_name, ux_device_class_hid_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_hid_name, ux_device_class_hid_entry); + + /* Register. */ + status = ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,1, (VOID *)&hid_mouse_parameter); + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,0, (VOID *)&hid_keyboard_parameter); + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,2, (VOID *)&hid_remote_control_parameter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } +#endif +#endif + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + 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 #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + +#if defined(UX_DEVICE_STANDALONE) + + /* Create the main device simulation thread. */ + status = tx_thread_create(&tx_demo_thread_device_simulation, "tx demo device simulation", tx_demo_thread_device_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } +#endif +} + +#if defined(UX_DEVICE_STANDALONE) +static void tx_demo_thread_device_simulation_entry(ULONG arg) +{ + while(1) + { + ux_system_tasks_run(); + tx_thread_relinquish(); + } +} +#endif + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_DEVICE *device; +ULONG mem_free; +ULONG alloc_count; +ULONG test_n; +UX_HCD *hcd; + + + stepinfo(">>>>>>>>>> Thread start\n"); + + hcd = &_ux_system_host->ux_system_host_hcd_array[0]; + + ux_test_breakable_sleep(500, break_on_all_activated); + + /* Get device instance. */ + status = ux_host_stack_device_get(0, &device); + + if (status != UX_SUCCESS) + { + printf("ERROR #%d: get_device fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>> Disconnect\n"); + + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + if (hid_keyboard || hid_mouse) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>> Reset counts\n"); + + ux_test_utility_sim_mem_alloc_count_reset(); + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + rsc_mem_alloc_cnt_on_set_cfg = 0; + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + + stepinfo(">>>>>>>>>> Connect\n"); + + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + ux_test_breakable_sleep(500, break_on_all_activated); + + /* Log create counts for further tests. */ + rsc_enum_mem_alloc_count = rsc_mem_alloc_cnt_on_set_cfg; + + /* Log create counts when instances active for further tests. */ + alloc_count = ux_test_utility_sim_mem_alloc_count(); + + /* Lock log base for tests. */ + ux_test_utility_sim_mem_alloc_log_lock(); + + rsc_hid_mem_alloc_count = alloc_count - rsc_enum_mem_alloc_count; + + stepinfo("enum mem: %ld\n", rsc_enum_mem_alloc_count); + stepinfo("hid mem : %ld\n", rsc_hid_mem_alloc_count); + stepinfo("mem free: %ld, %ld\n", _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); + + if (hid_mouse == UX_NULL +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + || hid_keyboard == UX_NULL +#endif + ) + { + printf("ERROR #%d: %p %p\n", __LINE__, hid_keyboard, hid_mouse); + test_control_return(1); + } + + /* Simulate detach and attach for FS enumeration, + and test possible memory allocation error handlings. + */ + if (rsc_hid_mem_alloc_count) stepinfo(">>>>>>>>>> Memory errors enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_hid_mem_alloc_count; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_hid_mem_alloc_count - 1); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check number of devices. */ + if (hcd->ux_hcd_nb_devices != 0) + { + printf("ERROR #%d.%ld: number of devices (%d) must be 0\n", __LINE__, test_n, hcd->ux_hcd_nb_devices); + error_counter ++; + } + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + error_counter ++; + test_control_return(1); + } + + /* Set memory error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n + rsc_enum_mem_alloc_count); + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); +#if 1 /* @nick */ + ux_test_hcd_sim_host_connect_no_wait(UX_FULL_SPEED_DEVICE); + + /* Wait for enum thread to complete. */ + ux_test_wait_for_enum_thread_completion(); +#else + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on errors. */ + ux_test_breakable_sleep(400, sleep_break_on_error); +#endif + + /* Check error */ + if (hid_mouse && hid_keyboard && hid_mouse_slave && hid_keyboard_slave && hid_remote_control && hid_remote_control_slave) + { + + printf("ERROR #%d.%ld: device detected when there is memory error\n", __LINE__, test_n); + error_counter ++; + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + ux_test_utility_sim_mem_alloc_error_generation_stop(); + } + if (alloc_count) stepinfo("\n"); + + stepinfo(">>>>>>>>>> Test done\n"); + + /* 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(); + + if (error_counter) + { + printf("FAIL %ld errors!\n", error_counter); + test_control_return(1); + } + + /* 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_device_class_hid_control_request_test.c b/test/regression/usbx_ux_device_class_hid_control_request_test.c new file mode 100644 index 00000000..e8f90877 --- /dev/null +++ b/test/regression/usbx_ux_device_class_hid_control_request_test.c @@ -0,0 +1,677 @@ +/* This file tests _ux_device_class_hid_control_request(). Note that the 4 requests we're testing +(GET_IDLE, SET_IDLE, GET_PROTOCOL, and SET_PROTOCOL) have yet to be implemented on the device; +Therefore, right now, not much is done in the way of checking output. */ + +#include "usbx_test_common_hid.h" + +#include "ux_host_class_hid_keyboard.h" +#include "ux_device_class_hid.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UX_SLAVE_CLASS_HID * hid_device; + +static UCHAR event_buffer[8]; +static UCHAR dummy_report[7]; +static UCHAR buffer[64]; +static UINT set_report_test_started; +static UCHAR error_is_expected = UX_FALSE; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + if (!error_is_expected) + { + /* Ignore protocol errors. */ + if (error_code == UX_TRANSFER_STALLED) + return; + + printf("Error on line %d, system_level: %d, system_context: %d, error code: 0x%x\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } +} + +static VOID demo_hid_instance_activate(VOID *inst) +{ + hid_device = (UX_SLAVE_CLASS_HID *)inst; +} +static VOID demo_hid_instance_deactivate(VOID *inst) +{ + if ((VOID *)hid_device == inst) + hid_device = UX_NULL; +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_hid_control_request_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_hid_control_request 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, error code: 0x%x\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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: 0x%x\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, error code: 0x%x\n", __LINE__, status); + 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; + hid_parameter.ux_slave_class_hid_instance_activate = demo_hid_instance_activate; + hid_parameter.ux_slave_class_hid_instance_deactivate = demo_hid_instance_deactivate; + + /* 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + +#if defined(UX_DEVICE_STANDALONE) + + /* Create the main device simulation thread. */ + status = tx_thread_create(&tx_demo_thread_device_simulation, "tx demo device simulation", tx_demo_thread_device_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } +#endif +} + +#if defined(UX_DEVICE_STANDALONE) +static void tx_demo_thread_device_simulation_entry(ULONG arg) +{ + while(1) + { + ux_system_tasks_run(); + tx_thread_relinquish(); + } +} +#endif + +static UINT demo_thread_hid_callback(UX_SLAVE_CLASS_HID *class, UX_SLAVE_CLASS_HID_EVENT *event) +{ + +UINT status; + + + if (set_report_test_started == 1) + { + + status = ux_utility_memory_compare(event -> ux_device_class_hid_event_buffer, dummy_report, sizeof(dummy_report)); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + } + + return(UX_SUCCESS); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_HOST_CLASS_HID_KEYBOARD *keyboard; +UX_SLAVE_CLASS *slave_class; +ULONG idle_time; +ULONG report_id; +UX_SLAVE_CLASS_HID_EVENT hid_event; +UX_SLAVE_CLASS_HID *slave_hid; +UINT max_get_report_attempts = 5; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the keyboard instance */ + keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)hid_client -> ux_host_class_hid_client_local_instance; + + /* Set idle time and report id. */ + idle_time = 0; + report_id = 0; + + /* Get the slave hid class and hid instance. */ + slave_class = _ux_system_slave -> ux_system_slave_device.ux_slave_device_first_interface -> ux_slave_interface_class; + slave_hid = _ux_system_slave -> ux_system_slave_device.ux_slave_device_first_interface -> ux_slave_interface_class_instance; + + /* Get the endpoint and transfer request. */ + control_endpoint = &hid -> ux_host_class_hid_device -> ux_device_control_endpoint; + transfer_request = &control_endpoint -> ux_endpoint_transfer_request; + +#if !defined(UX_DEVICE_STANDALONE) + + /* Suspend the device interrupt thread so it doesn't get take reports, + thus preventing us from using a control transfer to get them. */ + status = ux_utility_thread_suspend(&slave_class -> ux_slave_class_thread); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } +#else + + /* Set HID state to EXIT, no IDLE/Event processing. */ + slave_hid -> ux_device_class_hid_event_state = UX_STATE_EXIT; + tx_thread_sleep(1); +#endif + + /* Set event buffer. */ + event_buffer[0] = 0x01; + event_buffer[1] = 0x02; + event_buffer[2] = 0x03; + event_buffer[3] = 0x04; + event_buffer[4] = 0x05; + event_buffer[5] = 0x06; + event_buffer[6] = 0x07; + event_buffer[7] = 0x08; + + /**************************************************/ + /** Test case: 'case UX_DEVICE_CLASS_HID_COMMAND_GET_REPORT:' **/ + /**************************************************/ + + /* Set the hid event. */ + hid_event.ux_device_class_hid_event_length = sizeof(event_buffer); + ux_utility_memory_copy(hid_event.ux_device_class_hid_event_buffer, event_buffer, hid_event.ux_device_class_hid_event_length); + + /* Add the event. */ + status = ux_device_class_hid_event_set(slave_hid, &hid_event); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Create a transfer request for the GET_REPORT request. */ + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_requested_length = hid_event.ux_device_class_hid_event_length; + transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_HID_GET_REPORT; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_value = (UINT)((UX_HOST_CLASS_HID_REPORT_TYPE_INPUT << 8) | report_id); + transfer_request -> ux_transfer_request_index = hid -> ux_host_class_hid_interface -> ux_interface_descriptor.bInterfaceNumber; + + /* Send request to HCD layer. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + status = ux_utility_memory_compare(buffer, event_buffer, hid_event.ux_device_class_hid_event_length); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: 'case UX_DEVICE_CLASS_HID_COMMAND_SET_REPORT:' **/ + /**************************************************/ + + /* Create a transfer request for the SET_REPORT request. */ + /* NOTE: Right now, the size of the dummy report must not be 8 bytes. This is due to a bug in sim_transaction_schedule(). Refer to bug file. */ + transfer_request -> ux_transfer_request_data_pointer = dummy_report; + transfer_request -> ux_transfer_request_requested_length = sizeof(dummy_report); + transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_HID_SET_REPORT; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_value = (UINT)((UX_HOST_CLASS_HID_REPORT_TYPE_OUTPUT << 8) | report_id); + transfer_request -> ux_transfer_request_index = hid -> ux_host_class_hid_interface -> ux_interface_descriptor.bInterfaceNumber; + + set_report_test_started = 1; + + /* Send request to HCD layer. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: 'case UX_DEVICE_CLASS_HID_COMMAND_GET_IDLE:' **/ + /**************************************************/ + + /* Create a transfer request for the GET_IDLE request. */ + transfer_request -> ux_transfer_request_data_pointer = UX_NULL; + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_HID_GET_IDLE; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_value = (UINT)((idle_time << 8) | report_id); + transfer_request -> ux_transfer_request_index = hid -> ux_host_class_hid_interface -> ux_interface_descriptor.bInterfaceNumber; + + /* Send request to HCD layer. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: 'case UX_DEVICE_CLASS_HID_COMMAND_SET_IDLE:' **/ + /**************************************************/ + + /* Create a transfer request for the SET_IDLE request. */ + transfer_request -> ux_transfer_request_data_pointer = UX_NULL; + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_HID_SET_IDLE; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_value = (UINT)((idle_time << 8) | report_id); + transfer_request -> ux_transfer_request_index = hid -> ux_host_class_hid_interface -> ux_interface_descriptor.bInterfaceNumber; + + /* Send request to HCD layer. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: 'case UX_DEVICE_CLASS_HID_COMMAND_GET_PROTOCOL:' **/ + /**************************************************/ + + /* Default protocol should be report protocol. */ + if (ux_device_class_hid_protocol_get(hid_device) != 1) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Create a transfer request for the GET_PROTOCOL request. */ + transfer_request -> ux_transfer_request_data_pointer = dummy_report; + transfer_request -> ux_transfer_request_requested_length = 1; + transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_HID_GET_PROTOCOL; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = hid -> ux_host_class_hid_interface -> ux_interface_descriptor.bInterfaceNumber; + + /* Send request to HCD layer. */ + dummy_report[0] = 0xFF; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS && status != UX_TRANSFER_STALLED) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Before protocol change it must be report protocol (1). */ + if (status == UX_SUCCESS && dummy_report[0] != 1) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: 'case UX_DEVICE_CLASS_HID_COMMAND_SET_PROTOCOL:' **/ + /**************************************************/ + + /* Create a transfer request for the SET_PROTOCOL request. */ + transfer_request -> ux_transfer_request_data_pointer = UX_NULL; + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_HID_SET_PROTOCOL; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_value = 0; /* boot report */ + transfer_request -> ux_transfer_request_index = hid -> ux_host_class_hid_interface -> ux_interface_descriptor.bInterfaceNumber; + + /* Send request to HCD layer. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS && status != UX_TRANSFER_STALLED) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Protocol should be boot protocol. */ + if (status == UX_SUCCESS && + ux_device_class_hid_protocol_get(hid_device) != 0) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Create a transfer request for the GET_PROTOCOL request. */ + transfer_request -> ux_transfer_request_data_pointer = dummy_report; + transfer_request -> ux_transfer_request_requested_length = 1; + transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_HID_GET_PROTOCOL; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = hid -> ux_host_class_hid_interface -> ux_interface_descriptor.bInterfaceNumber; + + /* Send request to HCD layer. */ + dummy_report[0] = 0xFF; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS && status != UX_TRANSFER_STALLED) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* After protocol change it must be boot device (0). */ + if (status == UX_SUCCESS && dummy_report[0] != 0) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: 'default:' (unknown request) **/ + /**************************************************/ + + /* Create a transfer request for the an unknown request. */ + transfer_request -> ux_transfer_request_data_pointer = UX_NULL; + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = 0xdeadbeef; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = hid -> ux_host_class_hid_interface -> ux_interface_descriptor.bInterfaceNumber; + + /* We expect error here */ + error_is_expected = UX_TRUE; + + /* Send request to HCD layer. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status == UX_SUCCESS) + { + + printf("Error on line %d, report error expected here\n", __LINE__); + test_control_return(1); + } + error_is_expected = UX_FALSE; + + /* 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); +} diff --git a/test/regression/usbx_ux_device_class_hid_deactivate_test.c b/test/regression/usbx_ux_device_class_hid_deactivate_test.c new file mode 100644 index 00000000..10f601f6 --- /dev/null +++ b/test/regression/usbx_ux_device_class_hid_deactivate_test.c @@ -0,0 +1,344 @@ +/* This file tests the ux_device_class_hid_deactivate API. */ + +#include "usbx_test_common_hid.h" + +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UINT was_instance_deactivate_callback_called; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID instance_deactivate_callback(VOID *parameter) +{ + + was_instance_deactivate_callback_called = 1; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + //if (error_code != ) + printf("hello"); + { + + /* 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_device_class_hid_deactivate_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_hid_deactivate 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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; + hid_parameter.ux_slave_class_hid_instance_deactivate = instance_deactivate_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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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); + } + + /* 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); + + /**************************************************/ + /** Test case: callback was invoked. **/ + /**************************************************/ + + if (was_instance_deactivate_callback_called != 1) { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /**************************************************/ + /** Test case end. **/ + /**************************************************/ + + /* 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_device_class_hid_descriptor_send_test.c b/test/regression/usbx_ux_device_class_hid_descriptor_send_test.c new file mode 100644 index 00000000..46235ab2 --- /dev/null +++ b/test/regression/usbx_ux_device_class_hid_descriptor_send_test.c @@ -0,0 +1,739 @@ +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#define HID_REPORT_LENGTH sizeof(hid_report_descriptor)/sizeof(hid_report_descriptor[0]) + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x85, 0x01, // REPORT_ID (1) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN (9) + +/* HID Mouse/Keyboard interface descriptors 9+9+7=25 bytes */ +#define HID_IFC_DESC_ALL(ifc, report_len, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(report_len),\ + MSB(report_len),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_IFC_DESC_ALL_LEN (9+9+7) + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + // /* Configuration descriptor */ + // 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0, + // 0x32, + CFG_DESC(CFG_DESC_LEN+2*HID_IFC_DESC_ALL_LEN, 2, 0x01) + + // /* 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 + HID_IFC_DESC_ALL(2, HID_REPORT_LENGTH, 0x82) + + HID_IFC_DESC_ALL(1, HID_MOUSE_REPORT_LENGTH, 0x81) + }; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + // /* Configuration descriptor */ + // 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0, + // 0x32, + CFG_DESC(CFG_DESC_LEN+2*HID_IFC_DESC_ALL_LEN, 2, 0x01) + + // /* 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 + HID_IFC_DESC_ALL(2, HID_REPORT_LENGTH, 0x82) + + HID_IFC_DESC_ALL(1, HID_MOUSE_REPORT_LENGTH, 0x81) + }; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + + +static UCHAR corrupted_device_framework[DEVICE_FRAMEWORK_LENGTH_FULL_SPEED] = { + + /* Device descriptor. Length (first byte) is too large. */ + 0xff, 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 + + }; + +static UCHAR corrupted_device_framework_hid[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 (length too long) */ + 0xff, 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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +static VOID set_hid_descriptor(UCHAR *descriptor, ULONG length) +{ + +UX_SLAVE_CLASS *class; +UX_SLAVE_CLASS_HID *hid_class; + + + device_framework_full_speed[DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 9] = LSB(length); + device_framework_full_speed[DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 8] = MSB(length); + device_framework_high_speed[DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 9] = LSB(length); + device_framework_high_speed[DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 8] = MSB(length); + + /* Modify class settings. */ + class = &_ux_system_slave->ux_system_slave_class_array[0]; + hid_class = (UX_SLAVE_CLASS_HID*)class->ux_slave_class_instance; + + hid_class->ux_device_class_hid_report_address = descriptor; + hid_class->ux_device_class_hid_report_length = length; +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_hid_descriptor_send_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_descriptor_send 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, error code: 0x%x\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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: 0x%x\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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_KEYBOARD *keyboard; +UX_ENDPOINT *endpoint; +UX_TRANSFER *transfer_request; +UCHAR descriptor[1024]; +UCHAR *hid_class_descriptor = device_framework_high_speed + 0x2E; +UCHAR *hid_class_descriptor_1 = device_framework_high_speed + 0x2E + 9 + 7 + 9; +ALIGN_TYPE tmp; + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the keyboard instance */ + keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)hid_client -> ux_host_class_hid_client_local_instance; + + /* Get default endpoint. */ + endpoint = &hid->ux_host_class_hid_device->ux_device_control_endpoint; + + /* Get the transfer request. */ + transfer_request = &endpoint->ux_endpoint_transfer_request; + + /**************************************************/ + /** Test case: 'case: UX_DEVICE_CLASS_HID_DESCRIPTOR_HID', index error **/ + /**************************************************/ + + /* Create a transfer request for the HID class descriptor. */ + transfer_request -> ux_transfer_request_data_pointer = descriptor; + transfer_request -> ux_transfer_request_requested_length = 0x09; + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = UX_HOST_CLASS_HID_DESCRIPTOR << 8; + transfer_request -> ux_transfer_request_index = 0x00; + + /* Send request to HCD layer. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: 'case: UX_DEVICE_CLASS_HID_DESCRIPTOR_HID' **/ + /**************************************************/ + + /* Create a transfer request for the HID class descriptor. */ + transfer_request -> ux_transfer_request_data_pointer = descriptor; + transfer_request -> ux_transfer_request_requested_length = 0x09; + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = UX_HOST_CLASS_HID_DESCRIPTOR << 8; + transfer_request -> ux_transfer_request_index = 0x02; + + /* Send request to HCD layer. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Make sure we received the correct number of bytes. */ + if(transfer_request->ux_transfer_request_actual_length != 0x09) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Make sure we received it correctly. */ + status = memcmp(transfer_request -> ux_transfer_request_data_pointer, hid_class_descriptor, transfer_request -> ux_transfer_request_actual_length); + if(status) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: 'case: UX_DEVICE_CLASS_HID_DESCRIPTOR_HID' **/ + /**************************************************/ + + /* Create a transfer request for the HID class descriptor. */ + transfer_request -> ux_transfer_request_data_pointer = descriptor; + transfer_request -> ux_transfer_request_requested_length = 0x09; + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = UX_HOST_CLASS_HID_DESCRIPTOR << 8; + transfer_request -> ux_transfer_request_index = 0x01; + + /* Send request to HCD layer. */ + status = _ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Make sure we received the correct number of bytes. */ + if(transfer_request->ux_transfer_request_actual_length != 0x09) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Make sure we received it correctly. */ + status = memcmp(transfer_request -> ux_transfer_request_data_pointer, hid_class_descriptor_1, transfer_request -> ux_transfer_request_actual_length); + if(status) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: 'if (descriptor_length < host_length)' in 'case: UX_DEVICE_CLASS_HID_DESCRIPTOR_HID' **/ + /**************************************************/ + + /* Create a transfer request for the HID class descriptor. */ + transfer_request -> ux_transfer_request_data_pointer = descriptor; + transfer_request -> ux_transfer_request_requested_length = 2*0x09; + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = UX_HOST_CLASS_HID_DESCRIPTOR << 8; + transfer_request -> ux_transfer_request_index = 0x02; + + /* Send request to HCD layer. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Make sure we received the correct number of bytes. */ + if(transfer_request->ux_transfer_request_actual_length != 0x09) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Make sure we received it correctly. */ + if(memcmp(transfer_request -> ux_transfer_request_data_pointer, hid_class_descriptor, transfer_request -> ux_transfer_request_actual_length)) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: 'if (descriptor_length < host_length)' in 'case UX_DEVICE_CLASS_HID_DESCRIPTOR_REPORT:' **/ + /**************************************************/ + + /* Create a transfer request for getting report descriptor. Make sure we request a length greater than it really is. */ + transfer_request -> ux_transfer_request_data_pointer = descriptor; + transfer_request -> ux_transfer_request_requested_length = 2*HID_REPORT_LENGTH; + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_value = UX_HOST_CLASS_HID_REPORT_DESCRIPTOR << 8; + transfer_request -> ux_transfer_request_index = 0x02; + + /* Send request to HCD layer. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Make sure we received the correct number of bytes. */ + if(transfer_request->ux_transfer_request_actual_length != HID_REPORT_LENGTH) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Make sure we received it correctly. */ + if (memcmp(transfer_request->ux_transfer_request_data_pointer, hid_report_descriptor, transfer_request->ux_transfer_request_actual_length)) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: 'if (device_framework_length <= descriptor_length)' **/ + /**************************************************/ + + /* Create a transfer request for the HID class descriptor. */ + transfer_request -> ux_transfer_request_data_pointer = descriptor; + transfer_request -> ux_transfer_request_requested_length = 0x09; + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = UX_HOST_CLASS_HID_DESCRIPTOR << 8; + transfer_request -> ux_transfer_request_index = 0x02; + + /* Corrupt the device framework. */ + tmp = (ALIGN_TYPE)_ux_system_slave -> ux_system_slave_device_framework; + _ux_system_slave -> ux_system_slave_device_framework = corrupted_device_framework; + + /* Send request to HCD layer. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Restore device framework. */ + _ux_system_slave -> ux_system_slave_device_framework = (UCHAR *)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 +#else + + /* Create a transfer request for the HID class descriptor. */ + transfer_request -> ux_transfer_request_data_pointer = descriptor; + transfer_request -> ux_transfer_request_requested_length = UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH + 1; + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = UX_HOST_CLASS_HID_DESCRIPTOR << 8; + transfer_request -> ux_transfer_request_index = 0x02; + + /* Corrupt the device framework. */ + tmp = (ALIGN_TYPE)_ux_system_slave -> ux_system_slave_device_framework; + _ux_system_slave -> ux_system_slave_device_framework = corrupted_device_framework_hid; + + /* Send request to HCD layer. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Restore device framework. */ + _ux_system_slave -> ux_system_slave_device_framework = (UCHAR *)tmp; +#endif + + /**************************************************/ + /** Test case: 'default:' **/ + /**************************************************/ + + /* Create a transfer request for an unknown request. */ + transfer_request -> ux_transfer_request_data_pointer = descriptor; + transfer_request -> ux_transfer_request_requested_length = 0x09; + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = 0xffff << 8; + transfer_request -> ux_transfer_request_index = 0x02; + + /* Send request to HCD layer. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: 'if (length > UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH)' in 'case UX_DEVICE_CLASS_HID_DESCRIPTOR_REPORT:' **/ + /**************************************************/ + + /* Specific "long" descriptor. */ + set_hid_descriptor(hid_report_descriptor, UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH + 1); + + /* Create a transfer request for getting report descriptor. Make sure we request a length greater than it really is. */ + transfer_request -> ux_transfer_request_data_pointer = descriptor; + transfer_request -> ux_transfer_request_requested_length = UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH + 1; + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_value = UX_HOST_CLASS_HID_REPORT_DESCRIPTOR << 8; + transfer_request -> ux_transfer_request_index = 0x02; + + /* Send request to HCD layer. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status == UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Revert "long" descriptor. */ + set_hid_descriptor(hid_report_descriptor, HID_REPORT_LENGTH); + + /* 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_device_class_hid_entry_test.c b/test/regression/usbx_ux_device_class_hid_entry_test.c new file mode 100644 index 00000000..78b529db --- /dev/null +++ b/test/regression/usbx_ux_device_class_hid_entry_test.c @@ -0,0 +1,365 @@ +/* This file tests the ux_device_class_hid_entry API. */ + +#include "usbx_test_common_hid.h" + +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + //if (error_code != ) + printf("hello"); + { + + /* 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_device_class_hid_entry_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_hid_entry 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_SLAVE_INTERFACE *interface; +UX_SLAVE_CLASS_COMMAND command; +UX_SLAVE_DEVICE *device; +UX_SLAVE_CLASS_HID *device_hid; + + + /* 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); + } + + /* Derive device hid class. */ + device = &_ux_system_slave -> ux_system_slave_device; + interface = device -> ux_slave_device_first_interface; + device_hid = interface -> ux_slave_interface_class_instance; + + /**************************************************/ + /** Test case: if (command -> ux_slave_class_command_class != UX_DEVICE_CLASS_HID_CLASS). **/ + /** Why direct: an error here would mean the user mismatched [the configuration and interface indices] **/ + /** and [the class] when registering the class; this is a user error. **/ + /**************************************************/ + + /* Set up. */ + command.ux_slave_class_command_request = UX_SLAVE_CLASS_COMMAND_QUERY; + command.ux_slave_class_command_class = ~UX_DEVICE_CLASS_HID_CLASS; + + status = _ux_device_class_hid_entry(&command); + if (status != UX_NO_CLASS_MATCH) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: unknown command. **/ + /**************************************************/ + + /* Set up. */ + command.ux_slave_class_command_request = 0xdeadbeef; + + status = _ux_device_class_hid_entry(&command); + if (status != UX_FUNCTION_NOT_SUPPORTED) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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_device_class_hid_event_get_AND_set_test.c b/test/regression/usbx_ux_device_class_hid_event_get_AND_set_test.c new file mode 100644 index 00000000..98172cc0 --- /dev/null +++ b/test/regression/usbx_ux_device_class_hid_event_get_AND_set_test.c @@ -0,0 +1,604 @@ +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + +#define TEST_HID_EVENTS_SIZE (UX_DEVICE_CLASS_HID_MAX_EVENTS_QUEUE + 1) + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x85, 0x00, // REPORT_ID (0) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_hid_event_get_AND_set_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_hid_event_get_AND_set 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, error code: 0x%x\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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: 0x%x\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, error code: 0x%x\n", __LINE__, status); + 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; + hid_parameter.ux_device_class_hid_parameter_report_id = UX_TRUE; + + /* 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_KEYBOARD *keyboard; +ULONG tmp; +UX_SLAVE_DEVICE *device; +UX_SLAVE_CLASS_HID *device_hid; +UX_SLAVE_CLASS_HID_EVENT hid_events[TEST_HID_EVENTS_SIZE]; +UX_SLAVE_CLASS_HID_EVENT hid_event; +UX_SLAVE_INTERFACE *interface; +UX_SLAVE_CLASS *slave_class; +UX_SLAVE_CLASS_HID slave_class_hid; +UINT report_id; + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the keyboard instance */ + keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)hid_client -> ux_host_class_hid_client_local_instance; + + /* Derive device hid class. */ + device = &_ux_system_slave -> ux_system_slave_device; + interface = device -> ux_slave_device_first_interface; + slave_class = interface -> ux_slave_interface_class; + device_hid = interface -> ux_slave_interface_class_instance; + + for (report_id = 0; report_id < 2; report_id ++) + { + + /* Modify report ID setting! */ + device_hid -> ux_device_class_hid_report_id = report_id; + + /* Initialize events. */ + for (int i = 0; i < TEST_HID_EVENTS_SIZE; i++) + { + + if (report_id == 0) + hid_events[i].ux_device_class_hid_event_length = UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH; + else + hid_events[i].ux_device_class_hid_event_length = UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH - 1; + + for (int j = 0; j < UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH; j++) + hid_events[i].ux_device_class_hid_event_buffer[j] = i; + } + + /* Suspend the device interrupt thread so it doesn't get take reports, + thus preventing us from using a control transfer to get them. */ + status = ux_utility_thread_suspend(&slave_class -> ux_slave_class_thread); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, test %d, error code: 0x%x\n", __LINE__, report_id, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: if (current_hid_event == UX_NULL). **/ + /**************************************************/ + + /* Nullify head of round robin buffer. */ + slave_class_hid.ux_device_class_hid_event_array_head = NULL; + + status = _ux_device_class_hid_event_set(&slave_class_hid, 0); + if (status != UX_ERROR) + { + + printf("Error on line %d, test %d, error code: 0x%x\n", __LINE__, report_id, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: get an event when the buffer is empty. **/ + /**************************************************/ + + status = _ux_device_class_hid_event_get(device_hid, &hid_event); + if (status == UX_SUCCESS) + { + + printf("Error on line %d, test %d, error code: 0x%x\n", __LINE__, report_id, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: add one. **/ + /**************************************************/ + + status = _ux_device_class_hid_event_set(device_hid, &hid_events[0]); + if (report_id & 1) + { + /* Branch case: if current_hid_event length too big. */ + device_hid->ux_device_class_hid_event_array_tail->ux_device_class_hid_event_length = UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH + 1; + } + if (status != UX_SUCCESS) + { + + printf("Error on line %d, test %d, error code: 0x%x\n", __LINE__, report_id, status); + test_control_return(1); + } + + status = _ux_device_class_hid_event_get(device_hid, &hid_event); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, test %d, error code: 0x%x\n", __LINE__, report_id, status); + test_control_return(1); + } + + status = ux_utility_memory_compare(&hid_event.ux_device_class_hid_event_buffer[report_id], + &hid_events[0].ux_device_class_hid_event_buffer[report_id], + UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH - report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, test %d, error code: 0x%x\n", __LINE__, report_id, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: fill halfway. **/ + /**************************************************/ + + for (int i = 0; i < UX_DEVICE_CLASS_HID_MAX_EVENTS_QUEUE / 2; i++) + { + + status = _ux_device_class_hid_event_set(device_hid, &hid_events[i]); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, test %d, error code: 0x%x\n", __LINE__, report_id, status); + test_control_return(1); + } + } + + for (int i = 0; i < UX_DEVICE_CLASS_HID_MAX_EVENTS_QUEUE / 2; i++) + { + + status = _ux_device_class_hid_event_get(device_hid, &hid_event); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, test %d, error code: 0x%x\n", __LINE__, report_id, status); + test_control_return(1); + } + + status = ux_utility_memory_compare(&hid_event.ux_device_class_hid_event_buffer[report_id], + &hid_events[i].ux_device_class_hid_event_buffer[report_id], + UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH - report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, test %d, error code: 0x%x\n", __LINE__, report_id, status); + test_control_return(1); + } + } + + /**************************************************/ + /** Test case: fill all the way. **/ + /**************************************************/ + + /* Note that with the way the buffer is set up, the maximum number of + events able to be added is one less. */ + for (int i = 0; i < (UX_DEVICE_CLASS_HID_MAX_EVENTS_QUEUE - 1); i++) + { + + status = _ux_device_class_hid_event_set(device_hid, &hid_events[i]); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, test %d, error code: 0x%x\n", __LINE__, report_id, status); + test_control_return(1); + } + } + + for (int i = 0; i < (UX_DEVICE_CLASS_HID_MAX_EVENTS_QUEUE - 1); i++) + { + + status = _ux_device_class_hid_event_get(device_hid, &hid_event); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, test %d, error code: 0x%x\n", __LINE__, report_id, status); + test_control_return(1); + } + + status = ux_utility_memory_compare(&hid_event.ux_device_class_hid_event_buffer[report_id], + &hid_events[i].ux_device_class_hid_event_buffer[report_id], + UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH - report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, test %d, error code: 0x%x\n", __LINE__, report_id, status); + test_control_return(1); + } + } + + /**************************************************/ + /** Test case: fill past max. **/ + /**************************************************/ + + /* Note that with the way the buffer is set up, the maximum number of + events able to be added is one less. */ + for (int i = 0; i < (UX_DEVICE_CLASS_HID_MAX_EVENTS_QUEUE - 1); i++) + { + + status = _ux_device_class_hid_event_set(device_hid, &hid_events[i]); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, test %d, error code: 0x%x\n", __LINE__, report_id, status); + test_control_return(1); + } + } + + status = _ux_device_class_hid_event_set(device_hid, &hid_events[UX_DEVICE_CLASS_HID_MAX_EVENTS_QUEUE - 1]); + if (status == UX_SUCCESS) + { + + printf("Error on line %d, test %d, error code: 0x%x\n", __LINE__, report_id, status); + test_control_return(1); + } + + for (int i = 0; i < (UX_DEVICE_CLASS_HID_MAX_EVENTS_QUEUE - 1); i++) + { + + status = _ux_device_class_hid_event_get(device_hid, &hid_event); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, test %d, error code: 0x%x\n", __LINE__, report_id, status); + test_control_return(1); + } + + status = ux_utility_memory_compare(&hid_event.ux_device_class_hid_event_buffer[report_id], + &hid_events[i].ux_device_class_hid_event_buffer[report_id], + UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH - report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, test %d, error code: 0x%x\n", __LINE__, report_id, status); + test_control_return(1); + } + } + + /**************************************************/ + /** Test case: if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED). **/ + /** Why direct: The host indirectly calls this via a report get request, however, in order to make this request to a device, **/ + /** the device must have been configured already. **/ + /**************************************************/ + + /* Put device in unconfigured state. */ + tmp = _ux_system_slave -> ux_system_slave_device.ux_slave_device_state; + _ux_system_slave -> ux_system_slave_device.ux_slave_device_state = ~UX_DEVICE_CONFIGURED; + + status = _ux_device_class_hid_event_get(device_hid, &hid_event); + if (status != UX_DEVICE_HANDLE_UNKNOWN) + { + + printf("Error on line %d, test %d, error code: 0x%x\n", __LINE__, report_id, status); + test_control_return(1); + } + + /* Restore state for next test. */ + _ux_system_slave -> ux_system_slave_device.ux_slave_device_state = tmp; + } + + /**************************************************/ + /** Test case: report ID is 1 and event length is max. **/ + /** Specific condition: if (hid_event -> ux_device_class_hid_event_length + 1 > UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH). **/ + /**************************************************/ + + hid_event.ux_device_class_hid_event_length = UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH; + hid_event.ux_device_class_hid_event_report_id = UX_TRUE; + status = _ux_device_class_hid_event_set(device_hid, &hid_event); + if (status == UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: device not connected.. */ + /**************************************************/ + + /* Now disconnect the device. */ + _ux_device_stack_disconnect(); + + status = ux_device_class_hid_event_get(device_hid, &hid_event); + if (status != UX_DEVICE_HANDLE_UNKNOWN) + { + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* 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_device_class_hid_idle_rate_test.c b/test/regression/usbx_ux_device_class_hid_idle_rate_test.c new file mode 100644 index 00000000..61bee745 --- /dev/null +++ b/test/regression/usbx_ux_device_class_hid_idle_rate_test.c @@ -0,0 +1,597 @@ +/* This file tests the + * _ux_device_class_hid_control_request + * _ux_device_class_hid_interrupt_thread + */ + +#include "usbx_test_common_hid.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#include "ux_host_class_hid_mouse.h" +#include "ux_host_class_hid_keyboard.h" + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) + +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UX_SLAVE_CLASS_HID *slave_hid = UX_NULL; +static UX_SLAVE_CLASS_HID_EVENT slave_hid_event; + +#define HOST_BUFFER_LENGTH 32 + +static UCHAR host_buffer[HOST_BUFFER_LENGTH]; +static ULONG host_buffer_length; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#define HID_REPORT_LENGTH sizeof(hid_report_descriptor)/sizeof(hid_report_descriptor[0]) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* HID Mouse interface descriptors 9+9+7=25 bytes */ +#define HID_MOUSE_IFC_DESC_ALL(ifc, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 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, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_MOUSE_IFC_DESC_ALL_LEN 25 + +/* HID Mouse interface descriptors 9+9+7+7=32 bytes */ +#define HID_TEST_IFC_DESC_ALL(ifc, epa0, epa0_type, epa1, epa1_type) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x02, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_REPORT_LENGTH),\ + MSB(HID_REPORT_LENGTH),\ + /* Endpoint descriptor */\ + 0x07, 0x05, (epa0), (epa0_type), 0x08, 0x00, 0x08,\ + /* Endpoint descriptor */\ + 0x07, 0x05, (epa1), (epa1_type), 0x08, 0x00, 0x08, +#define HID_TEST_IFC_DESC_ALL_LEN 32 + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC(CFG_DESC_LEN+2*HID_TEST_IFC_DESC_ALL_LEN, 2, 1) + /* Interrupt IN @ 1st */ + HID_TEST_IFC_DESC_ALL(0, 0x81, 3, 0x02, 3) + /* HID interface but no interrupt IN */ + HID_TEST_IFC_DESC_ALL(1, 0x84, 2, 0x03, 3) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC(CFG_DESC_LEN+HID_MOUSE_IFC_DESC_ALL_LEN+HID_TEST_IFC_DESC_ALL_LEN, 2, 1) + /* Good HID interface. */ + HID_MOUSE_IFC_DESC_ALL(0, 0x81) + /* Interrupt IN @ 2nd. */ + HID_TEST_IFC_DESC_ALL(1, 0x03, 3, 0x84, 3) +}; +#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 + 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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID instance_activate_callback(VOID *parameter) +{ + + slave_hid = (UX_SLAVE_CLASS_HID *)parameter; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + // printf("Error on line %d: 0x%x, 0x%x, 0x%x\n", __LINE__, system_level, system_context, error_code); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_hid_idle_rate_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_hid_ Idle Rate tests ....................... "); + stepinfo("\n"); + + /* 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, error code: 0x%x\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } +#if 0 + /* 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); + } +#endif + /* 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, error code: 0x%x\n", __LINE__, status); + 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; + hid_parameter.ux_slave_class_hid_instance_activate = instance_activate_callback; + + /* Initialize 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,0, (VOID *)&hid_parameter); + if(status!=UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static ULONG _report_count = 0; +static void _run_idle_rate_test(INT test, UCHAR idle_rate, UX_SLAVE_CLASS_HID_EVENT *event) +{ + +UINT status; +USHORT actual_rate; +ULONG count; +ULONG expected_count, actual_count; + + + if (event) + { + stepinfo(">>>>>>>>>> #%d - event set\n", test); + + status = ux_host_class_hid_idle_set(hid, 0, 0); + if (status != UX_SUCCESS) + { + + printf("#%d, Error on line %d, error code: %x\n", test, __LINE__, status); + test_control_return(1); + } + + _ux_utility_thread_suspend(&slave_hid -> ux_slave_class_hid_interface -> ux_slave_interface_class -> ux_slave_class_thread); + _ux_device_class_hid_event_set(slave_hid, event); + _ux_device_class_hid_event_set(slave_hid, event); + _ux_device_class_hid_event_set(slave_hid, event); + _ux_utility_thread_resume(&slave_hid -> ux_slave_class_hid_interface -> ux_slave_interface_class -> ux_slave_class_thread); + } + + stepinfo(">>>>>>>>>> #%d - Set_Idle : %d\n", test, idle_rate); + + status = ux_host_class_hid_idle_set(hid, idle_rate, 0); + if (status != UX_SUCCESS) + { + + printf("#%d, Error on line %d, error code: %x\n", test, __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>> #%d - Get_Idle : %d\n", test, idle_rate); + + status = ux_host_class_hid_idle_get(hid, &actual_rate, 0); + if (status != UX_SUCCESS) + { + + printf("#%d, Error on line %d, error code: %x\n", test, __LINE__, status); + test_control_return(1); + } + if (actual_rate != idle_rate) + { + + printf("#%d, Error on line %d, idle_rate: %d\n", test, __LINE__, actual_rate); + test_control_return(1); + } + + if (idle_rate > 0) + { + stepinfo(">>>>>>>>>> #%d - Wait %d for idle rate change\n", test, 1000); + count = _report_count; + _ux_utility_delay_ms(1000); + actual_count = _report_count - count; + + /* Expected count 1000 / (idle_rate * 4). */ + expected_count = 1000 / (idle_rate * 4); + stepinfo(">>>>>>>>>> #%d, report count expect %ld vs %ld\n", test, expected_count, actual_count); + if ((1000 / UX_PERIODIC_RATE) * 5 > (idle_rate * 4)) + { + stepinfo(">>>>>>>>>> #%d, count check skipped\n", test); + } + else + { + + /* ~30% area. */ + if (expected_count * 13 / 10 < actual_count || + expected_count * 7 / 10 > actual_count) + { + printf("#%d, Error on line %d, report count not expected: %ld\n", test, __LINE__, actual_count); + test_control_return(1); + } + } + + if (event) + { + stepinfo(">>>>>>>>>> #%d - check event data\n", test); + if (host_buffer_length != event->ux_device_class_hid_event_length) + { + printf("#%d, Error on line %d, report length not expected: %ld\n", test, __LINE__, host_buffer_length); + test_control_return(1); + } + if (_ux_utility_memory_compare(host_buffer, event->ux_device_class_hid_event_buffer, host_buffer_length)) + { + printf("#%d, Error on line %d, report data not expected\n", test, __LINE__); + printf("event:\n"); + for (count = 0; count < host_buffer_length; count ++) + printf(" %2x", event->ux_device_class_hid_event_buffer[count]); + printf("\n"); + printf("host buffer:\n"); + for (count = 0; count < host_buffer_length; count ++) + printf(" %2x", host_buffer[count]); + printf("\n"); + test_control_return(1); + } + } + } + else + { + stepinfo(">>>>>>>>>> #%d - Wait %d for idle rate to take action\n", test, 1000); + _ux_utility_delay_ms(1000); + + stepinfo(">>>>>>>>>> #%d - Wait %d to confirm there is no event\n", test, 1000); + count = _report_count; + _ux_utility_delay_ms(1000); + actual_count = _report_count - count; + if (count != _report_count) + { + printf("#%d, Error on line %d, report count changed %ld\n", test, __LINE__, actual_count); + test_control_return(1); + } + } +} + +static VOID _hid_report_callback(UX_HOST_CLASS_HID_REPORT_CALLBACK *callback) +{ + ULONG length; + _report_count ++; + length = callback->ux_host_class_hid_report_callback_actual_length; + if (length > HOST_BUFFER_LENGTH) + length = HOST_BUFFER_LENGTH; + _ux_utility_memory_copy(host_buffer, + callback->ux_host_class_hid_report_callback_buffer, + length); + host_buffer_length = length; +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_DEVICE *device; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; +UX_HOST_CLASS_HID_REPORT_CALLBACK call_back; +USHORT idle_rate; + + stepinfo(">>>>>>>>>> Thread start\n"); + + _ux_utility_delay_ms(500); + + /* Get device instance. */ + status = ux_host_stack_device_get(0, &device); + + if (status != UX_SUCCESS) + { + printf("ERROR #%d: get_device fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Get control endpoint. */ + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + stepinfo(">>>>>>>>>> Get HID class instance\n"); + + /* 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); + } + if (slave_hid == UX_NULL) + { + printf("Error on line %d, HID slave instance error\n", __LINE__); + test_control_return(1); + } + + /* Get the report ID for the keyboard. The keyboard is a INPUT report. + This should be 0 but in case. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = _ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: get_report_id fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Initialize the report callback. */ + call_back.ux_host_class_hid_report_callback_id = report_id.ux_host_class_hid_report_get_id; + call_back.ux_host_class_hid_report_callback_function = _hid_report_callback; + call_back.ux_host_class_hid_report_callback_buffer = UX_NULL; + call_back.ux_host_class_hid_report_callback_flags = UX_HOST_CLASS_HID_REPORT_RAW; + call_back.ux_host_class_hid_report_callback_length = 0; + + /* Register the report call back when data comes it on this report. */ + status = _ux_host_class_hid_report_callback_register(hid, &call_back); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: report_callback_register fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Start periodic report (to poll reports). */ + status = _ux_host_class_hid_periodic_report_start(hid); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: report_start fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>> Get_Idle : 0\n"); + + status = ux_host_class_hid_idle_get(hid, &idle_rate, 0); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %x\n", __LINE__, status); + test_control_return(1); + } + if (idle_rate != 0) + { + + printf("Error on line %d, idle_rate: %d\n", __LINE__, idle_rate); + test_control_return(1); + } + + _run_idle_rate_test(__LINE__, 4/4, 0); + + slave_hid_event.ux_device_class_hid_event_report_id = 0; + slave_hid_event.ux_device_class_hid_event_report_type = 0; + + slave_hid_event.ux_device_class_hid_event_length = 8; + slave_hid_event.ux_device_class_hid_event_buffer[0] = 1; + slave_hid_event.ux_device_class_hid_event_buffer[1] = 1; + slave_hid_event.ux_device_class_hid_event_buffer[2] = 1; + slave_hid_event.ux_device_class_hid_event_buffer[3] = 1; + slave_hid_event.ux_device_class_hid_event_buffer[4] = 1; + slave_hid_event.ux_device_class_hid_event_buffer[5] = 1; + slave_hid_event.ux_device_class_hid_event_buffer[6] = 1; + slave_hid_event.ux_device_class_hid_event_buffer[7] = 1; + _run_idle_rate_test(__LINE__, 200/4, &slave_hid_event); + + slave_hid_event.ux_device_class_hid_event_length = 6; + slave_hid_event.ux_device_class_hid_event_buffer[0] = 2; + slave_hid_event.ux_device_class_hid_event_buffer[1] = 4; + slave_hid_event.ux_device_class_hid_event_buffer[2] = 1; + slave_hid_event.ux_device_class_hid_event_buffer[3] = 3; + slave_hid_event.ux_device_class_hid_event_buffer[4] = 3; + slave_hid_event.ux_device_class_hid_event_buffer[5] = 3; + slave_hid_event.ux_device_class_hid_event_buffer[6] = 0; + slave_hid_event.ux_device_class_hid_event_buffer[7] = 0; + _run_idle_rate_test(__LINE__, 100/4, &slave_hid_event); + + _run_idle_rate_test(__LINE__, 0, 0); + + _ux_utility_delay_ms(500); + + stepinfo(">>>>>>>>>> Test done\n"); + + /* 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_device_class_hid_initialize_test.c b/test/regression/usbx_ux_device_class_hid_initialize_test.c new file mode 100644 index 00000000..379dba69 --- /dev/null +++ b/test/regression/usbx_ux_device_class_hid_initialize_test.c @@ -0,0 +1,499 @@ +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_hid_initialize_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_hid_initialize 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, error code 0x%x\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code 0x%x\n", __LINE__, status); + 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, error code 0x%x\n", __LINE__, status); + 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 0x%x\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, error code 0x%x\n", __LINE__, status); + 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, error code 0x%x\n", __LINE__, status); + 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, error code 0x%x\n", __LINE__, status); + 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, error code 0x%x\n", __LINE__, status); + 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, error code 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_SLAVE_CLASS_COMMAND command; +UX_SLAVE_CLASS class; +UX_SLAVE_CLASS_HID_PARAMETER hid_parameter; +// UX_MEMORY_BLOCK *dummy_memory_block_first = (UX_MEMORY_BLOCK *)dummy_usbx_memory; +// UX_MEMORY_BLOCK *original_regular_memory_block = (UX_MEMORY_BLOCK *)_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start; +// UX_MEMORY_BLOCK *original_cache_safe_memory_block = (UX_MEMORY_BLOCK *)_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_start; +UCHAR class_thread_stack[UX_THREAD_STACK_SIZE]; +UX_SLAVE_CLASS_HID *hid_instance; +TX_EVENT_FLAGS_GROUP hid_instance_event_flags_copy; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + command.ux_slave_class_command_parameter = &hid_parameter; + command.ux_slave_class_command_class_ptr = &class; + + /* Allocate a hid instance like hid_initialize(). */ + hid_instance = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_SLAVE_CLASS_HID)); + if (hid_instance == UX_NULL) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /**************************************************/ + /** Test case: status = _ux_utility_event_flags_create(&hid -> ux_device_class_hid_event_flags_group, "ux_device_class_hid_event_flag"); fails **/ + /**************************************************/ + + /* Create the event_flags like hid_initialize(). */ + status = ux_utility_event_flags_create(&hid_instance -> ux_device_class_hid_event_flags_group, "ux_host_class_hid_keyboard_event_flags"); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Make a copy of the event_flags. */ + hid_instance_event_flags_copy = hid_instance -> ux_device_class_hid_event_flags_group; + + /* Free the memory so hid_initialize() uses the same memory as us, which will cause threadx to detect a event_flags duplicate. */ + ux_utility_memory_free(hid_instance); + + status = _ux_device_class_hid_initialize(&command); + if (status != UX_EVENT_ERROR) + { + + printf("Error on line %d, error code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* ux_utility_memory_allocate() zero'd out our hid instance event_flags! Good thing we made a copy! */ + hid_instance -> ux_device_class_hid_event_flags_group = hid_instance_event_flags_copy; + + /** Restore state for next test. **/ + + status = ux_utility_event_flags_delete(&hid_instance -> ux_device_class_hid_event_flags_group); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: status = _ux_utility_thread_create(&class -> ux_slave_class_thread, "ux_slave_class_thread", + _ux_device_class_hid_interrupt_thread, + (ULONG) class, (VOID *) class -> ux_slave_class_thread_stack, + UX_THREAD_STACK_SIZE, UX_THREAD_PRIORITY_CLASS, + UX_THREAD_PRIORITY_CLASS, UX_NO_TIME_SLICE, TX_DONT_START); fails **/ + /**************************************************/ + + /* Create the thread like hid_initialize(). */ + status = _ux_utility_thread_create(&class.ux_slave_class_thread, "ux_slave_class_thread", + _ux_device_class_hid_interrupt_thread, + (ULONG) (ALIGN_TYPE) &class, class_thread_stack, + UX_THREAD_STACK_SIZE, UX_THREAD_PRIORITY_CLASS, + UX_THREAD_PRIORITY_CLASS, UX_NO_TIME_SLICE, TX_DONT_START); + UX_THREAD_EXTENSION_PTR_SET(&class.ux_slave_class_thread, &class) + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + status = _ux_device_class_hid_initialize(&command); + if (status != UX_THREAD_ERROR) + { + + printf("Error on line %d, error code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + status = ux_utility_thread_delete(&class.ux_slave_class_thread); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code 0x%x\n", __LINE__, status); + test_control_return(1); + } +#if 0 /* Tested by basic memory tests */ + /**************************************************/ + /** Test case: hid = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_SLAVE_CLASS_HID)); fails **/ + /**************************************************/ + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + dummy_memory_block_first -> ux_memory_block_size = 0; + _ux_system -> ux_system_regular_memory_pool_start = dummy_memory_block_first; + _ux_system -> ux_system_cache_safe_memory_pool_start = dummy_memory_block_first; + + status = _ux_device_class_hid_initialize(&command); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: class -> ux_slave_class_thread_stack = + _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, UX_THREAD_STACK_SIZE); fails **/ + /**************************************************/ + + command.ux_slave_class_command_class_ptr = &class; + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + dummy_memory_block_first -> ux_memory_block_size = calculate_final_memory_request_size(1, sizeof(UX_SLAVE_CLASS_HID)); + _ux_system -> ux_system_regular_memory_pool_start = dummy_memory_block_first; + _ux_system -> ux_system_cache_safe_memory_pool_start = dummy_memory_block_first; + + status = _ux_device_class_hid_initialize(&command); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code 0x%x\n", __LINE__, status); + test_control_return(1); + } +#endif +#if 0 /* @BUG_FIX_PENDING: returns UX_EVENT_ERROR when it should return UX_MEMORY_INSUFFICIENT */ + /**************************************************/ + /** Test case: class -> ux_slave_class_thread_stack = + _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, UX_THREAD_STACK_SIZE); fails **/ + /**************************************************/ + + command.ux_slave_class_command_parameter = &hid_parameter; + command.ux_slave_class_command_class_ptr = &class; + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + dummy_memory_block_first -> ux_memory_block_size = calculate_final_memory_request_size(2, sizeof(UX_SLAVE_CLASS_HID), UX_THREAD_STACK_SIZE); + _ux_system -> ux_system_regular_memory_pool_start = dummy_memory_block_first; + _ux_system -> ux_system_cache_safe_memory_pool_start = dummy_memory_block_first; + + status = _ux_device_class_hid_initialize(&command); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + _ux_system -> ux_system_regular_memory_pool_start = original_regular_memory_block; + _ux_system -> ux_system_cache_safe_memory_pool_start = original_cache_safe_memory_block; + + status = ux_utility_thread_delete(&class.ux_slave_class_thread); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code 0x%x\n", __LINE__, status); + test_control_return(1); + } +#endif + + /* 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_device_class_hid_interrupt_thread_test.c b/test/regression/usbx_ux_device_class_hid_interrupt_thread_test.c new file mode 100644 index 00000000..80c65b63 --- /dev/null +++ b/test/regression/usbx_ux_device_class_hid_interrupt_thread_test.c @@ -0,0 +1,393 @@ +/* This file tests _ux_device_class_hid_interrupt_thread(), which only runs when there +is a new event available in the queue. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + +UINT callback_error_code; + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + callback_error_code = error_code; +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_hid_interrupt_thread_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_hid_interrupt_thread 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +UINT _ux_dcd_sim_slave_function(UX_SLAVE_DCD *dcd , UINT function, VOID *parameter); +static UINT my_ux_dcd_sim_slave_function(UX_SLAVE_DCD *dcd , UINT function, VOID *parameter) +{ + +UINT status; +UX_SLAVE_TRANSFER *transfer_request; + + + transfer_request = (UX_SLAVE_TRANSFER *)parameter; + + /* Is this from the interrupt thread? */ + if ((function == UX_DCD_TRANSFER_REQUEST) && + (*(ULONG *)transfer_request -> ux_slave_transfer_request_data_pointer == 0xdeadbeef)) + + status = UX_ERROR; + + else + + status = _ux_dcd_sim_slave_function(dcd, function, parameter); + + return status; +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_SLAVE_DEVICE *device; +UX_SLAVE_INTERFACE *interface; +UX_SLAVE_CLASS_HID *device_hid; +UX_HOST_CLASS_HID_KEYBOARD *keyboard; +UX_SLAVE_CLASS_HID_EVENT hid_event; + + + /* 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); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the keyboard instance */ + keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)hid_client -> ux_host_class_hid_client_local_instance; + + /* Derive device hid class. */ + device = &_ux_system_slave -> ux_system_slave_device; + interface = device -> ux_slave_device_first_interface; + device_hid = interface -> ux_slave_interface_class_instance; + + /**************************************************/ + /** Test case: _ux_device_stack_transfer_request fails. **/ + /**************************************************/ + + /* Override device's entry function to intercept specific transfer request. */ + _ux_system_slave -> ux_system_slave_dcd.ux_slave_dcd_function = my_ux_dcd_sim_slave_function; + + /* Add an event to let the interrupt thread run. */ + *(ULONG *)hid_event.ux_device_class_hid_event_buffer = 0xdeadbeef; + hid_event.ux_device_class_hid_event_length = 4; + hid_event.ux_device_class_hid_event_report_id = 0; + ux_device_class_hid_event_set(device_hid, &hid_event); + + /* Wait for error in callback. */ + while (callback_error_code != UX_ERROR) + ux_utility_thread_sleep(10); + + /* Restore state for next test. */ + _ux_system_slave -> ux_system_slave_dcd.ux_slave_dcd_function = _ux_dcd_sim_slave_function; + + /**************************************************/ + /** Test case: _ux_utility_thread_suspend() is called (meaning the device gets unconfigured). **/ + /**************************************************/ + + /* Now disconnect the device. This is to get it out of the configured state. */ + _ux_device_stack_disconnect(); + + /* Add an event to let the interrupt thread run. */ + *(ULONG *)hid_event.ux_device_class_hid_event_buffer = 0xdeadbeef; + hid_event.ux_device_class_hid_event_length = 4; + hid_event.ux_device_class_hid_event_report_id = 0; + ux_device_class_hid_event_set(device_hid, &hid_event); + + /* We have no way of checking if this succeeds... */ + ux_utility_thread_sleep(10); + + /* 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_device_class_hid_interrupt_thread_test2.c b/test/regression/usbx_ux_device_class_hid_interrupt_thread_test2.c new file mode 100644 index 00000000..4f1adba4 --- /dev/null +++ b/test/regression/usbx_ux_device_class_hid_interrupt_thread_test2.c @@ -0,0 +1,395 @@ +/* This file tests _ux_device_class_hid_interrupt_thread(), which only runs when there +is a new event available in the queue. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + +UINT callback_error_code; + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + callback_error_code = error_code; +} + +static UCHAR count = 0; +UINT _ux_dcd_sim_slave_function(UX_SLAVE_DCD *dcd , UINT function, VOID *parameter); + +static UINT my_ux_dcd_sim_slave_function(UX_SLAVE_DCD *dcd , UINT function, VOID *parameter) +{ + if (count == 0) + { + count++; + return UX_ERROR; + } + else if (count == 1) + { + count++; + return UX_TRANSFER_BUS_RESET; + } + else if (count == 2) + { + count++; + return UX_TRANSFER_ERROR; + } + else + { + count++; + return UX_SUCCESS; + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_hid_interrupt_thread_test2_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_hid_interrupt_thread Test 2................. "); + + /* 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_SLAVE_DEVICE *device; +UX_SLAVE_INTERFACE *interface; +UX_SLAVE_CLASS_HID *device_hid; +UX_HOST_CLASS_HID_KEYBOARD *keyboard; + +UX_SLAVE_CLASS_HID_EVENT hid_event; +ULONG tmp_timeout; + + + /* 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); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the keyboard instance */ + keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)hid_client -> ux_host_class_hid_client_local_instance; + + /* Derive device hid class. */ + device = &_ux_system_slave -> ux_system_slave_device; + interface = device -> ux_slave_device_first_interface; + device_hid = interface -> ux_slave_interface_class_instance; + + /**************************************************/ + /** Test case: _ux_device_stack_transfer_request return with different value in case of no event. **/ + /**************************************************/ + /* Add an event to let the interrupt thread run. */ + *(ULONG *)hid_event.ux_device_class_hid_event_buffer = 0xdeadbeef; + hid_event.ux_device_class_hid_event_length = 4; + hid_event.ux_device_class_hid_event_report_id = 0; + tmp_timeout = device_hid->ux_device_class_hid_event_wait_timeout; + /* Set the timeout to 2s and sleep 10s later to generate >=3 times of no event cases */ + device_hid->ux_device_class_hid_event_wait_timeout = 2; + _ux_system_slave -> ux_system_slave_dcd.ux_slave_dcd_function = my_ux_dcd_sim_slave_function; + ux_device_class_hid_event_set(device_hid, &hid_event); + ux_utility_thread_sleep(10); + + /* restore ux_device_class_hid_event_wait_timeout */ + device_hid->ux_device_class_hid_event_wait_timeout = tmp_timeout; + /* Restore state for next test. */ + _ux_system_slave -> ux_system_slave_dcd.ux_slave_dcd_function = _ux_dcd_sim_slave_function; + + /**************************************************/ + /** Test case: status = _ux_utility_event_flags_get(&hid -> ux_device_class_hid_event_flags_group, UX_DEVICE_CLASS_HID_NEW_EVENT, + TX_OR_CLEAR, &actual_flags, TX_WAIT_FOREVER); fails. **/ + /**************************************************/ + status = ux_utility_event_flags_delete(&device_hid -> ux_device_class_hid_event_flags_group); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + tx_thread_sleep(10); + + /* 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_device_class_hid_read_test.c b/test/regression/usbx_ux_device_class_hid_read_test.c new file mode 100644 index 00000000..dd26a498 --- /dev/null +++ b/test/regression/usbx_ux_device_class_hid_read_test.c @@ -0,0 +1,494 @@ +/* This file tests the + * _ux_device_class_hid_control_request + * _ux_device_class_hid_interrupt_thread + */ + +#include "usbx_test_common_hid.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#include "ux_host_class_hid_mouse.h" +#include "ux_host_class_hid_keyboard.h" + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) + +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UX_SLAVE_CLASS_HID *slave_hid = UX_NULL; +static UX_SLAVE_CLASS_HID_EVENT slave_hid_event; + +#define DEMO_PACKET_SIZE 8 +#define DEVICE_BUFFER_LENGTH 32 /* 4*8 */ + 1 + +static TX_SEMAPHORE device_semaphore; +static UCHAR device_buffer[DEVICE_BUFFER_LENGTH]; +static UINT device_read_status; +static ULONG device_read_request_length; +static ULONG device_read_actual_length; +static ULONG device_read_count; + +#define HOST_BUFFER_LENGTH 32 /* 4*8 */ + +static UCHAR host_buffer[HOST_BUFFER_LENGTH]; +static ULONG host_buffer_length; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#define HID_REPORT_LENGTH sizeof(hid_report_descriptor)/sizeof(hid_report_descriptor[0]) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* HID Mouse interface descriptors 9+9+7=25 bytes */ +#define HID_MOUSE_IFC_DESC_ALL(ifc, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 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, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_MOUSE_IFC_DESC_ALL_LEN 25 + +/* HID Test interface descriptors 9+9+7+7=32 bytes */ +#define HID_TEST_IFC_DESC_ALL(ifc, epa0, epa0_type, epa1, epa1_type) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x02, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_REPORT_LENGTH),\ + MSB(HID_REPORT_LENGTH),\ + /* Endpoint descriptor */\ + 0x07, 0x05, (epa0), (epa0_type), 0x08, 0x00, 0x08,\ + /* Endpoint descriptor */\ + 0x07, 0x05, (epa1), (epa1_type), 0x08, 0x00, 0x08, +#define HID_TEST_IFC_DESC_ALL_LEN 32 + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC(CFG_DESC_LEN+HID_TEST_IFC_DESC_ALL_LEN, 1, 1) + /* Interrupt IN @ 1st */ + HID_TEST_IFC_DESC_ALL(0, 0x81, 3, 0x02, 3) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC(CFG_DESC_LEN+HID_MOUSE_IFC_DESC_ALL_LEN, 1, 1) + /* Interrupt IN @ 1st */ + HID_TEST_IFC_DESC_ALL(0, 0x81, 3, 0x02, 3) +}; +#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 + 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 +}; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID instance_activate_callback(VOID *parameter) +{ + + slave_hid = (UX_SLAVE_CLASS_HID *)parameter; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + // printf("Error on line %d: 0x%x, 0x%x, 0x%x\n", __LINE__, system_level, system_context, error_code); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_hid_read_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_hid_ read/interrupt OUT tests .............. "); + stepinfo("\n"); + + /* 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, error code: 0x%x\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\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, error code: 0x%x\n", __LINE__, status); + 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; + hid_parameter.ux_slave_class_hid_instance_activate = instance_activate_callback; + + /* Initialize 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,0, (VOID *)&hid_parameter); + if(status!=UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Create the main device simulation thread. */ + stack_pointer += UX_DEMO_STACK_SIZE; + status = tx_thread_create(&tx_demo_thread_device_simulation, "tx demo device simulation", tx_demo_thread_device_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR $%d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_DEVICE *device; +UX_ENDPOINT *endpoint; + + stepinfo(">>>>>>>>>> Thread start\n"); + + _ux_utility_delay_ms(500); + + /* Get device instance. */ + status = ux_host_stack_device_get(0, &device); + + if (status != UX_SUCCESS) + { + printf("ERROR #%d: get_device fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>> Get HID class instance\n"); + + /* 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); + } + if (slave_hid == UX_NULL) + { + printf("Error on line %d, HID slave instance error\n", __LINE__); + test_control_return(1); + } + +#if defined(UX_DEVICE_CLASS_HID_INTERRUPT_OUT_SUPPORT) + endpoint = hid -> ux_host_class_hid_interface -> ux_interface_first_endpoint; + if (endpoint -> ux_endpoint_descriptor.bEndpointAddress & 0x80) + endpoint = endpoint -> ux_endpoint_next_endpoint; + if (endpoint == UX_NULL) + { + printf("ERROR #%d: endpoint OUT not found\n", __LINE__); + test_control_return(1); + } + endpoint->ux_endpoint_transfer_request.ux_transfer_request_timeout_value = 100; + /* Device read 8, host send 0. */ + device_read_request_length = 8; + device_read_count = 0; + tx_semaphore_put(&device_semaphore); + status = ux_test_host_endpoint_write(endpoint, host_buffer, 0, UX_NULL); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(device_read_count == 1); + UX_TEST_ASSERT(device_read_status == UX_SUCCESS); + UX_TEST_ASSERT(device_read_actual_length == 0); + /* Device read 8, host send 1. */ + tx_semaphore_put(&device_semaphore); + ux_utility_memory_set(host_buffer, 0x5A, sizeof(host_buffer)); + ux_utility_memory_set(device_buffer, 0x37, sizeof(device_buffer)); + status = ux_test_host_endpoint_write(endpoint, host_buffer, 1, UX_NULL); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(device_read_count == 2); + UX_TEST_ASSERT(device_read_status == UX_SUCCESS); + UX_TEST_ASSERT(device_read_actual_length == 1); + UX_TEST_ASSERT(device_buffer[0] == host_buffer[0]); + UX_TEST_ASSERT(device_buffer[1] == 0X37); + /* Device read 8, host send 8. */ + tx_semaphore_put(&device_semaphore); + ux_utility_memory_set(host_buffer, 0x5A, sizeof(host_buffer)); + ux_utility_memory_set(device_buffer, 0x37, sizeof(device_buffer)); + status = ux_test_host_endpoint_write(endpoint, host_buffer, 8, UX_NULL); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(device_read_count == 3); + UX_TEST_ASSERT(device_read_status == UX_SUCCESS); + UX_TEST_ASSERT(device_read_actual_length == 8); + UX_TEST_ASSERT(device_buffer[0] == host_buffer[0]); + UX_TEST_ASSERT(device_buffer[7] == host_buffer[7]); + UX_TEST_ASSERT(device_buffer[8] == 0X37); + /* Device read 32, host send 8, then 3. */ + device_read_request_length = 32; + tx_semaphore_put(&device_semaphore); + ux_utility_memory_set(host_buffer, 0x5A, sizeof(host_buffer)); + ux_utility_memory_set(device_buffer, 0x37, sizeof(device_buffer)); + status = ux_test_host_endpoint_write(endpoint, host_buffer, 8, UX_NULL); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(device_read_count == 3); + status = ux_test_host_endpoint_write(endpoint, host_buffer, 3, UX_NULL); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(device_read_count == 4); + UX_TEST_ASSERT(device_read_status == UX_SUCCESS); + UX_TEST_ASSERT(device_read_actual_length == 11); + UX_TEST_ASSERT(device_buffer[0] == host_buffer[0]); + UX_TEST_ASSERT(device_buffer[10] == host_buffer[10]); + UX_TEST_ASSERT(device_buffer[11] == 0X37); +#endif + + _ux_utility_delay_ms(500); + + stepinfo(">>>>>>>>>> Test done\n"); + + /* 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 void tx_demo_thread_device_simulation_entry(ULONG arg) +{ + +UINT status; + + status = tx_semaphore_create(&device_semaphore, "device semaphore", 0); + if (status != TX_SUCCESS) + { + printf("ERROR #%d device semaphore creation error 0x%x\n", __LINE__, status); + test_control_return(1); + return; + } + + while(1) + { + if (slave_hid == UX_NULL) + { + tx_thread_sleep(10); + continue; + } + /* Wait semaphore to start read. */ + status = tx_semaphore_get(&device_semaphore, TX_WAIT_FOREVER); + if (status != TX_SUCCESS) + { + printf("ERROR #%d device semaphore get error 0x%x\n", __LINE__, status); + test_control_return(1); + return; + } + /* Read and save status. */ +#if defined(UX_DEVICE_STANDALONE) + do + { + ux_system_tasks_run(); + status = ux_device_class_hid_read_run(slave_hid, device_buffer, device_read_request_length, &device_read_actual_length); + } while(status == UX_STATE_WAIT); + status = (status == UX_STATE_NEXT) ? UX_SUCCESS : UX_ERROR; +#else + status = ux_device_class_hid_read(slave_hid, device_buffer, device_read_request_length, &device_read_actual_length); +#endif + device_read_status = status; + device_read_count ++; + } +} + + +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_device_class_hid_receiver_memory_test.c b/test/regression/usbx_ux_device_class_hid_receiver_memory_test.c new file mode 100644 index 00000000..89a52c94 --- /dev/null +++ b/test/regression/usbx_ux_device_class_hid_receiver_memory_test.c @@ -0,0 +1,849 @@ +/* This file tests the ux_device_class_hid API. */ + +#include "usbx_test_common_hid.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#include "ux_host_class_hid_mouse.h" +#include "ux_host_class_hid_keyboard.h" +#include "ux_host_class_hid_remote_control.h" + + +static UCHAR hid_keyboard_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0, // END_COLLECTION + + 0xa1, 0x01, // COLLECTION (Application) + 0x19, 0x01, // USAGE_MINIMUM (1) + 0x29, 0x04, // USAGE_MAXIMUM (4) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x04, // REPORT_COUNT (4) + 0xb1, 0x02, // FEATURE (Data,Var,Abs) + 0x85, 0x02, // REPORT_ID (2) + 0x19, 0x05, // USAGE_MINIMUM (5) + 0x29, 0x07, // USAGE_MAXIMUM (7) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x03, // REPORT_COUNT (3) + 0xb1, 0x02, // FEATURE (Data,Var,Abs) + 0x85, 0x04, // REPORT_ID (4) + 0x09, 0x08, // USAGE (8) + 0x75, 0x10, // REPORT_SIZE (16) + 0x95, 0x01, // REPORT_COUNT (1) + 0xb1, 0x02, // FEATURE (Data,Var,Abs) + 0xc0, // END_COLLECTION +}; +#define HID_KEYBOARD_REPORT_LENGTH sizeof(hid_keyboard_report)/sizeof(hid_keyboard_report[0]) + + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +static UCHAR hid_remote_control_report[] = { + + 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) + 0x09, 0x01, // USAGE (Consumer Control) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x02, // USAGE (Numeric Key Pad) + 0xa1, 0x02, // COLLECTION (Logical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x0a, // USAGE_MAXIMUM (Button 10) + 0x15, 0x01, // LOGICAL_MINIMUM (1) + 0x25, 0x0a, // LOGICAL_MAXIMUM (10) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0, // END_COLLECTION + 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) + 0x09, 0x86, // USAGE (Channel) + 0x09, 0xe0, // USAGE (Volume) + 0x15, 0xff, // LOGICAL_MINIMUM (-1) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x02, // REPORT_SIZE (2) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x46, // INPUT (Data,Var,Rel,Null) + 0xc0 // END_COLLECTION +}; +#define HID_REMOTE_CONTROL_REPORT_LENGTH (sizeof(hid_remote_control_report)/sizeof(hid_remote_control_report[0])) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN (9) + + +/* HID Mouse/Keyboard interface descriptors 9+9+7=25 bytes */ +#define HID_IFC_DESC_ALL(ifc, report_len, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(report_len),\ + MSB(report_len),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_IFC_DESC_ALL_LEN (9+9+7) + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC(CFG_DESC_LEN+3*HID_IFC_DESC_ALL_LEN, 2, 1) + /* Keyboard */ + HID_IFC_DESC_ALL(0, HID_KEYBOARD_REPORT_LENGTH, 0x82) + /* Mouse */ + HID_IFC_DESC_ALL(1, HID_MOUSE_REPORT_LENGTH, 0x81) + /* Remote control */ + HID_IFC_DESC_ALL(2, HID_REMOTE_CONTROL_REPORT_LENGTH, 0x83) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC(CFG_DESC_LEN+3*HID_IFC_DESC_ALL_LEN, 2, 1) + /* Keyboard */ + HID_IFC_DESC_ALL(0, HID_KEYBOARD_REPORT_LENGTH, 0x82) + /* Mouse */ + HID_IFC_DESC_ALL(1, HID_MOUSE_REPORT_LENGTH, 0x81) + /* Remote control */ + HID_IFC_DESC_ALL(2, HID_REMOTE_CONTROL_REPORT_LENGTH, 0x83) +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +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 +}; +#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. */ +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +static UX_HOST_CLASS_HID *hid = UX_NULL; +static UX_HOST_CLASS_HID_MOUSE *hid_mouse = UX_NULL; +static UX_HOST_CLASS_HID_KEYBOARD *hid_keyboard = UX_NULL; +static UX_HOST_CLASS_HID_REMOTE_CONTROL *hid_remote_control = UX_NULL; + +static UX_SLAVE_CLASS_HID *hid_mouse_slave = UX_NULL; +static UX_SLAVE_CLASS_HID *hid_keyboard_slave = UX_NULL; +static UX_SLAVE_CLASS_HID *hid_remote_control_slave = UX_NULL; + +static UX_SLAVE_CLASS_HID_PARAMETER hid_mouse_parameter; +static UX_SLAVE_CLASS_HID_PARAMETER hid_keyboard_parameter; +static UX_SLAVE_CLASS_HID_PARAMETER hid_remote_control_parameter; + +static ULONG rsc_mem_alloc_cnt_on_set_cfg; +static ULONG rsc_enum_mem_alloc_count; +static ULONG rsc_hid_mem_alloc_count; + +static ULONG error_callback_counter; +static UCHAR error_callback_ignore; + +static ULONG error_counter = 0; + +static UINT ux_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_HID_CLIENT *client = (UX_HOST_CLASS_HID_CLIENT *)inst; +UINT is_mouse = (UX_SUCCESS == _ux_utility_memory_compare(client->ux_host_class_hid_client_name, + _ux_system_host_class_hid_client_mouse_name, + _ux_utility_string_length_get(_ux_system_host_class_hid_client_mouse_name))); +UINT is_keyboard = (UX_SUCCESS == _ux_utility_memory_compare(client->ux_host_class_hid_client_name, + _ux_system_host_class_hid_client_keyboard_name, + _ux_utility_string_length_get(_ux_system_host_class_hid_client_keyboard_name))); + + // if(event >= UX_HID_CLIENT_INSERTION) printf("hChg: ev %lx, cls %p, inst %p, %s\n", event, cls, inst, is_mouse ? "Mouse" : "Keyboard"); + switch(event) + { + + case UX_HID_CLIENT_INSERTION: + if (is_mouse) + hid_mouse = (UX_HOST_CLASS_HID_MOUSE *)client->ux_host_class_hid_client_local_instance; + else + { + if (is_keyboard) + hid_keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)client->ux_host_class_hid_client_local_instance; + else + hid_remote_control = (UX_HOST_CLASS_HID_REMOTE_CONTROL *)client->ux_host_class_hid_client_local_instance; + } + break; + + case UX_HID_CLIENT_REMOVAL: + if (is_mouse) + hid_mouse = UX_NULL; + else + { + if (is_keyboard) + hid_keyboard = UX_NULL; + else + hid_remote_control = UX_NULL; + } + break; + + default: + break; + } + return 0; +} + +static VOID mouse_instance_activate_callback(VOID *parameter) +{ + // printf("dMouse: %p\n", parameter); + hid_mouse_slave = (UX_SLAVE_CLASS_HID *)parameter; +} + +static VOID keyboard_instance_activate_callback(VOID *parameter) +{ + // printf("dKeyboard: %p\n", parameter); + hid_keyboard_slave = (UX_SLAVE_CLASS_HID *)parameter; +} + +static VOID remote_control_instance_activate_callback(VOID *parameter) +{ + // printf("dKeyboard: %p\n", parameter); + hid_remote_control_slave = (UX_SLAVE_CLASS_HID *)parameter; +} + +static VOID instance_deactivate_callback(VOID *parameter) +{ + // printf("dRm: %p\n", parameter); + if ((VOID *)hid_mouse_slave == parameter) + hid_mouse_slave = UX_NULL; + + if ((VOID *)hid_keyboard_slave == parameter) + hid_keyboard_slave = UX_NULL; + + if ((VOID *)hid_remote_control_slave == parameter) + hid_remote_control_slave = UX_NULL; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (error_code == UX_MEMORY_INSUFFICIENT) + error_callback_counter ++; + // printf("ERROR #%d: 0x%x, 0x%x, 0x%x\n", __LINE__, system_level, system_context, error_code); +} + +static UINT break_on_all_activated(VOID) +{ + + if (hid_mouse_slave == UX_NULL) + return 0; + if (hid_keyboard_slave == UX_NULL) + return 0; + if (hid_remote_control_slave == UX_NULL) + return 0; + if (hid_mouse == UX_NULL) + return 0; + if (hid_keyboard == UX_NULL) + return 0; + if (hid_remote_control == UX_NULL) + return 0; + + return 1; +} + + +static UINT break_on_all_removed(VOID) +{ + if (hid_mouse_slave || hid_keyboard_slave || hid_remote_control_slave) + return 0; + if (hid_mouse || hid_keyboard || hid_remote_control) + return 0; + + return 1; +} + + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *_params) +{ + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); +} + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_hid_receiver_memory_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +ULONG mem_free; +ULONG alloc_count; +ULONG test_n; + + /* Inform user. */ + printf("Running ux_device_class_hid Receiver Memory test ................... "); + stepinfo("\n"); + + /* Initialize memory logger. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + + /* 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 #%d, code 0x%x\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + 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 #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Register the HID client(s). */ + status |= ux_host_class_hid_client_register(_ux_system_host_class_hid_client_mouse_name, ux_host_class_hid_mouse_entry); + status |= ux_host_class_hid_client_register(_ux_system_host_class_hid_client_keyboard_name, ux_host_class_hid_keyboard_entry); + status |= ux_host_class_hid_client_register(_ux_system_host_class_hid_client_remote_control_name, ux_host_class_hid_remote_control_entry); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if (status != UX_SUCCESS) + { + + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } +#endif + + /* 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, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Initialize the hid class parameters for mouse and keyboard. */ + hid_mouse_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_mouse_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_REPORT_LENGTH; + hid_mouse_parameter.ux_device_class_hid_parameter_callback = demo_thread_hid_callback; + hid_mouse_parameter.ux_slave_class_hid_instance_activate = mouse_instance_activate_callback; + hid_mouse_parameter.ux_slave_class_hid_instance_deactivate = instance_deactivate_callback; + + hid_keyboard_parameter.ux_device_class_hid_parameter_report_address = hid_keyboard_report; + hid_keyboard_parameter.ux_device_class_hid_parameter_report_length = HID_KEYBOARD_REPORT_LENGTH; + hid_keyboard_parameter.ux_device_class_hid_parameter_callback = demo_thread_hid_callback; + hid_keyboard_parameter.ux_slave_class_hid_instance_activate = keyboard_instance_activate_callback; + hid_keyboard_parameter.ux_slave_class_hid_instance_deactivate = instance_deactivate_callback; + + hid_remote_control_parameter.ux_device_class_hid_parameter_report_address = hid_remote_control_report; + hid_remote_control_parameter.ux_device_class_hid_parameter_report_length = HID_REMOTE_CONTROL_REPORT_LENGTH; + hid_remote_control_parameter.ux_device_class_hid_parameter_callback = demo_thread_hid_callback; + hid_remote_control_parameter.ux_slave_class_hid_instance_activate = remote_control_instance_activate_callback; + hid_remote_control_parameter.ux_slave_class_hid_instance_deactivate = instance_deactivate_callback; + +#if defined(UX_DEVICE_CLASS_HID_INTERRUPT_OUT_SUPPORT) + hid_mouse_parameter.ux_device_class_hid_parameter_receiver_initialize = ux_device_class_hid_receiver_initialize; + hid_mouse_parameter.ux_device_class_hid_parameter_receiver_event_max_number = 8; + hid_mouse_parameter.ux_device_class_hid_parameter_receiver_event_max_length = 32; + + hid_keyboard_parameter.ux_device_class_hid_parameter_receiver_initialize = ux_device_class_hid_receiver_initialize; + hid_keyboard_parameter.ux_device_class_hid_parameter_receiver_event_max_number = 8; + hid_keyboard_parameter.ux_device_class_hid_parameter_receiver_event_max_length = 32; + + hid_remote_control_parameter.ux_device_class_hid_parameter_receiver_initialize = ux_device_class_hid_receiver_initialize; + hid_remote_control_parameter.ux_device_class_hid_parameter_receiver_event_max_number = 8; + hid_remote_control_parameter.ux_device_class_hid_parameter_receiver_event_max_length = 32; +#endif + + stepinfo(">>>>>>>>>> Test HID Class Initialize/deinitialize memory\n"); + + stepinfo(">>>>>>>>>> - Reset counts\n"); + ux_test_utility_sim_mem_alloc_count_reset(); + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + stepinfo(">>>>>>>>>> - _class_register\n"); + + /* Initilize the device hid class. */ + status = ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,1, (VOID *)&hid_mouse_parameter); + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,0, (VOID *)&hid_keyboard_parameter); + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,2, (VOID *)&hid_remote_control_parameter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } +#endif +#if 1 + /* Log create counts when instances active for further tests. */ + alloc_count = ux_test_utility_sim_mem_alloc_count(); + + /* Lock log base for tests. */ + ux_test_utility_sim_mem_alloc_log_lock(); + + stepinfo("init & uninit alloc : %ld\n", alloc_count); + stepinfo("mem free : %ld, %ld\n", _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); + + if (alloc_count) stepinfo(">>>>>>>>>> - Init/deinit memory errors test\n"); + mem_free = (~0); + for (test_n = 0; test_n < alloc_count; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, alloc_count - 1); + + /* Unregister. */ + ux_device_stack_class_unregister(_ux_system_slave_class_hid_name, ux_device_class_hid_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_hid_name, ux_device_class_hid_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_hid_name, ux_device_class_hid_entry); + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + error_counter ++; + test_control_return(1); + } + + /* Set memory error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n); + + /* Register. */ + status = ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,1, (VOID *)&hid_mouse_parameter); + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,0, (VOID *)&hid_keyboard_parameter); + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,2, (VOID *)&hid_remote_control_parameter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + /* Check error */ + if (status == UX_SUCCESS) + { + + printf("ERROR #%d.%ld: registered when there is memory error\n", __LINE__, test_n); + error_counter ++; + } +#endif + + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + } + ux_test_utility_sim_mem_alloc_error_generation_stop(); + if (alloc_count) stepinfo("\n"); + + /* Unregister. */ + ux_device_stack_class_unregister(_ux_system_slave_class_hid_name, ux_device_class_hid_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_hid_name, ux_device_class_hid_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_hid_name, ux_device_class_hid_entry); + + /* Register. */ + status = ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,1, (VOID *)&hid_mouse_parameter); + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,0, (VOID *)&hid_keyboard_parameter); + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,2, (VOID *)&hid_remote_control_parameter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } +#endif +#endif + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + 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 #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Create the main device simulation thread. */ + stack_pointer += UX_DEMO_STACK_SIZE; + status = tx_thread_create(&tx_demo_thread_device_simulation, "tx demo device simulation", tx_demo_thread_device_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR $%d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_DEVICE *device; +ULONG mem_free; +ULONG alloc_count; +ULONG test_n; +UX_HCD *hcd; + + + stepinfo(">>>>>>>>>> Thread start\n"); + + hcd = &_ux_system_host->ux_system_host_hcd_array[0]; + + ux_test_breakable_sleep(500, break_on_all_activated); + + /* Get device instance. */ + status = ux_host_stack_device_get(0, &device); + + if (status != UX_SUCCESS) + { + printf("ERROR #%d: get_device fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>> Disconnect\n"); + + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + if (hid_keyboard || hid_mouse) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>> Reset counts\n"); + + ux_test_utility_sim_mem_alloc_count_reset(); + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + rsc_mem_alloc_cnt_on_set_cfg = 0; + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + + stepinfo(">>>>>>>>>> Connect\n"); + + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + ux_test_breakable_sleep(500, break_on_all_activated); + + /* Log create counts for further tests. */ + rsc_enum_mem_alloc_count = rsc_mem_alloc_cnt_on_set_cfg; + + /* Log create counts when instances active for further tests. */ + alloc_count = ux_test_utility_sim_mem_alloc_count(); + + /* Lock log base for tests. */ + ux_test_utility_sim_mem_alloc_log_lock(); + + rsc_hid_mem_alloc_count = alloc_count - rsc_enum_mem_alloc_count; + + stepinfo("enum mem: %ld\n", rsc_enum_mem_alloc_count); + stepinfo("hid mem : %ld\n", rsc_hid_mem_alloc_count); + stepinfo("mem free: %ld, %ld\n", _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); + + if (hid_mouse == UX_NULL +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + || hid_keyboard == UX_NULL +#endif + ) + { + printf("ERROR #%d: %p %p\n", __LINE__, hid_keyboard, hid_mouse); + test_control_return(1); + } + + /* Simulate detach and attach for FS enumeration, + and test possible memory allocation error handlings. + */ + if (rsc_hid_mem_alloc_count) stepinfo(">>>>>>>>>> Memory errors enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_hid_mem_alloc_count; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_hid_mem_alloc_count - 1); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check number of devices. */ + if (hcd->ux_hcd_nb_devices != 0) + { + printf("ERROR #%d.%ld: number of devices (%d) must be 0\n", __LINE__, test_n, hcd->ux_hcd_nb_devices); + error_counter ++; + } + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + error_counter ++; + test_control_return(1); + } + + /* Set memory error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n + rsc_enum_mem_alloc_count); + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); +#if 1 /* @nick */ + ux_test_hcd_sim_host_connect_no_wait(UX_FULL_SPEED_DEVICE); + + /* Wait for enum thread to complete. */ + ux_test_wait_for_enum_thread_completion(); +#else + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on errors. */ + ux_test_breakable_sleep(400, sleep_break_on_error); +#endif + + /* Check error */ + if (hid_mouse && hid_keyboard && hid_mouse_slave && hid_keyboard_slave && hid_remote_control && hid_remote_control_slave) + { + + printf("ERROR #%d.%ld: device detected when there is memory error\n", __LINE__, test_n); + error_counter ++; + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + ux_test_utility_sim_mem_alloc_error_generation_stop(); + } + if (alloc_count) stepinfo("\n"); + + stepinfo(">>>>>>>>>> Test done\n"); + + /* 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(); + + if (error_counter) + { + printf("FAIL %ld errors!\n", error_counter); + test_control_return(1); + } + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + +static void tx_demo_thread_device_simulation_entry(ULONG arg) +{ + + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); +#else + /* Nothing to do. */ + tx_thread_sleep(1000); +#endif + } +} + +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_device_class_hid_receiver_test.c b/test/regression/usbx_ux_device_class_hid_receiver_test.c new file mode 100644 index 00000000..2643b972 --- /dev/null +++ b/test/regression/usbx_ux_device_class_hid_receiver_test.c @@ -0,0 +1,504 @@ +/* This file tests the + * _ux_device_class_hid_control_request + * _ux_device_class_hid_interrupt_thread + */ + +#include "usbx_test_common_hid.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#include "ux_host_class_hid_mouse.h" +#include "ux_host_class_hid_keyboard.h" + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) + +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UX_SLAVE_CLASS_HID *slave_hid = UX_NULL; +static UX_SLAVE_CLASS_HID_EVENT slave_hid_event; + +#define DEMO_PACKET_SIZE 8 +#define DEVICE_BUFFER_LENGTH 32 /* 4*8 */ + 1 + +static UCHAR device_buffer[DEVICE_BUFFER_LENGTH]; + +#define HOST_BUFFER_LENGTH 32 /* 4*8 */ + +static UCHAR host_buffer[HOST_BUFFER_LENGTH]; +static ULONG host_buffer_length; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#define HID_REPORT_LENGTH sizeof(hid_report_descriptor)/sizeof(hid_report_descriptor[0]) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* HID Mouse interface descriptors 9+9+7=25 bytes */ +#define HID_MOUSE_IFC_DESC_ALL(ifc, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 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, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_MOUSE_IFC_DESC_ALL_LEN 25 + +/* HID Test interface descriptors 9+9+7+7=32 bytes */ +#define HID_TEST_IFC_DESC_ALL(ifc, epa0, epa0_type, epa1, epa1_type) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x02, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_REPORT_LENGTH),\ + MSB(HID_REPORT_LENGTH),\ + /* Endpoint descriptor */\ + 0x07, 0x05, (epa0), (epa0_type), 0x08, 0x00, 0x08,\ + /* Endpoint descriptor */\ + 0x07, 0x05, (epa1), (epa1_type), 0x08, 0x00, 0x08, +#define HID_TEST_IFC_DESC_ALL_LEN 32 + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC(CFG_DESC_LEN+HID_TEST_IFC_DESC_ALL_LEN, 1, 1) + /* Interrupt IN @ 1st */ + HID_TEST_IFC_DESC_ALL(0, 0x81, 3, 0x02, 3) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC(CFG_DESC_LEN+HID_MOUSE_IFC_DESC_ALL_LEN, 1, 1) + /* Interrupt IN @ 1st */ + HID_TEST_IFC_DESC_ALL(0, 0x81, 3, 0x02, 3) +}; +#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 + 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 +}; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID instance_activate_callback(VOID *parameter) +{ + + slave_hid = (UX_SLAVE_CLASS_HID *)parameter; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + // printf("Error on line %d: 0x%x, 0x%x, 0x%x\n", __LINE__, system_level, system_context, error_code); +} + +#if defined(UX_DEVICE_CLASS_HID_INTERRUPT_OUT_SUPPORT) +static ULONG test_hid_receiver_event_callback_count = 0; +static VOID test_hid_receiver_event_callback(UX_SLAVE_CLASS_HID *hid) +{ + test_hid_receiver_event_callback_count ++; +} +#endif + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_hid_receiver_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_hid_ receiver/interrupt OUT tests .......... "); + stepinfo("\n"); + + /* 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, error code: 0x%x\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\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, error code: 0x%x\n", __LINE__, status); + 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; + hid_parameter.ux_slave_class_hid_instance_activate = instance_activate_callback; +#if defined(UX_DEVICE_CLASS_HID_INTERRUPT_OUT_SUPPORT) + hid_parameter.ux_device_class_hid_parameter_receiver_initialize = ux_device_class_hid_receiver_initialize; + hid_parameter.ux_device_class_hid_parameter_receiver_event_max_length = 32; + hid_parameter.ux_device_class_hid_parameter_receiver_event_max_number = 3; + hid_parameter.ux_device_class_hid_parameter_receiver_event_callback = test_hid_receiver_event_callback; +#endif + + /* Initialize 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,0, (VOID *)&hid_parameter); + if(status!=UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Create the main device simulation thread. */ + stack_pointer += UX_DEMO_STACK_SIZE; + status = tx_thread_create(&tx_demo_thread_device_simulation, "tx demo device simulation", tx_demo_thread_device_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR $%d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_DEVICE *device; +UX_ENDPOINT *endpoint; +UX_DEVICE_CLASS_HID_RECEIVED_EVENT received_event; + + stepinfo(">>>>>>>>>> Thread start\n"); + + _ux_utility_delay_ms(500); + + /* Get device instance. */ + status = ux_host_stack_device_get(0, &device); + + if (status != UX_SUCCESS) + { + printf("ERROR #%d: get_device fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>> Get HID class instance\n"); + + /* 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); + } + if (slave_hid == UX_NULL) + { + printf("Error on line %d, HID slave instance error\n", __LINE__); + test_control_return(1); + } + +#if defined(UX_DEVICE_CLASS_HID_INTERRUPT_OUT_SUPPORT) + endpoint = hid -> ux_host_class_hid_interface -> ux_interface_first_endpoint; + if (endpoint -> ux_endpoint_descriptor.bEndpointAddress & 0x80) + endpoint = endpoint -> ux_endpoint_next_endpoint; + if (endpoint == UX_NULL) + { + printf("ERROR #%d: endpoint OUT not found\n", __LINE__); + test_control_return(1); + } + endpoint->ux_endpoint_transfer_request.ux_transfer_request_timeout_value = 5; + /* Host send 0, no event. */ + test_hid_receiver_event_callback_count = 0; + status = ux_test_host_endpoint_write(endpoint, host_buffer, 0, UX_NULL); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(test_hid_receiver_event_callback_count == 0); + status = ux_device_class_hid_receiver_event_get(slave_hid, &received_event); + UX_TEST_ASSERT(status != UX_SUCCESS); + status = ux_device_class_hid_receiver_event_free(slave_hid); + UX_TEST_ASSERT(status != UX_SUCCESS); + /* Host Send 8, 17, 32. */ + test_hid_receiver_event_callback_count = 0; + ux_utility_memory_set(host_buffer, 8, 8); + status = ux_test_host_endpoint_write(endpoint, host_buffer, 8, UX_NULL); + UX_TEST_ASSERT(status == UX_SUCCESS); + status = ux_test_host_endpoint_write(endpoint, host_buffer, 0, UX_NULL); /* ZLP for multi-packet frame. */ + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(test_hid_receiver_event_callback_count == 1); + ux_utility_memory_set(host_buffer, 17, 17); + status = ux_test_host_endpoint_write(endpoint, host_buffer, 17, UX_NULL); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(test_hid_receiver_event_callback_count == 2); + ux_utility_memory_set(host_buffer, 32, 32); + status = ux_test_host_endpoint_write(endpoint, host_buffer, 32, UX_NULL); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(test_hid_receiver_event_callback_count == 3); + /* Host Send 1, timeout. */ + ux_utility_memory_set(host_buffer, 1, 1); + status = ux_test_host_endpoint_write(endpoint, host_buffer, 1, UX_NULL); + UX_TEST_ASSERT(status != UX_SUCCESS); + UX_TEST_ASSERT(test_hid_receiver_event_callback_count == 3); + /* Get event of 8. */ + status = ux_device_class_hid_receiver_event_get(slave_hid, &received_event); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(received_event.ux_device_class_hid_received_event_length == 8); + UX_TEST_ASSERT(received_event.ux_device_class_hid_received_event_data[0] == 8); + UX_TEST_ASSERT(received_event.ux_device_class_hid_received_event_data[7] == 8); + status = ux_device_class_hid_receiver_event_free(slave_hid); + UX_TEST_ASSERT(status == UX_SUCCESS); + /* Remove callback. */ + slave_hid->ux_device_class_hid_receiver->ux_device_class_hid_receiver_event_callback = UX_NULL; + /* Host Send 1, success. */ + ux_utility_memory_set(host_buffer, 1, 1); + status = ux_test_host_endpoint_write(endpoint, host_buffer, 1, UX_NULL); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(test_hid_receiver_event_callback_count == 3); + /* Get event of 17. */ + status = ux_device_class_hid_receiver_event_get(slave_hid, &received_event); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(received_event.ux_device_class_hid_received_event_length == 17); + UX_TEST_ASSERT(received_event.ux_device_class_hid_received_event_data[0] == 17); + UX_TEST_ASSERT(received_event.ux_device_class_hid_received_event_data[16] == 17); + status = ux_device_class_hid_receiver_event_free(slave_hid); + UX_TEST_ASSERT(status == UX_SUCCESS); + /* Get event of 32. */ + status = ux_device_class_hid_receiver_event_get(slave_hid, &received_event); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(received_event.ux_device_class_hid_received_event_length == 32); + UX_TEST_ASSERT(received_event.ux_device_class_hid_received_event_data[0] == 32); + UX_TEST_ASSERT(received_event.ux_device_class_hid_received_event_data[31] == 32); + status = ux_device_class_hid_receiver_event_free(slave_hid); + UX_TEST_ASSERT(status == UX_SUCCESS); + /* Get event of 1. */ + status = ux_device_class_hid_receiver_event_get(slave_hid, &received_event); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(received_event.ux_device_class_hid_received_event_length == 1); + UX_TEST_ASSERT(received_event.ux_device_class_hid_received_event_data[0] == 1); + status = ux_device_class_hid_receiver_event_free(slave_hid); + UX_TEST_ASSERT(status == UX_SUCCESS); + /* Nothing to get and free. */ + status = ux_device_class_hid_receiver_event_get(slave_hid, &received_event); + UX_TEST_ASSERT(status != UX_SUCCESS); + status = ux_device_class_hid_receiver_event_free(slave_hid); + UX_TEST_ASSERT(status != UX_SUCCESS); +#endif + + _ux_utility_delay_ms(500); + + stepinfo(">>>>>>>>>> Test done\n"); + + /* 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 void tx_demo_thread_device_simulation_entry(ULONG arg) +{ + + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); +#else + if (slave_hid == UX_NULL) + { + tx_thread_sleep(10); + continue; + } + /* Nothing to do. */ + tx_thread_sleep(1000); +#endif + } +} + + +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_device_class_hid_report_set_test.c b/test/regression/usbx_ux_device_class_hid_report_set_test.c new file mode 100644 index 00000000..3210f0c0 --- /dev/null +++ b/test/regression/usbx_ux_device_class_hid_report_set_test.c @@ -0,0 +1,358 @@ +/* This test concentrates on ux_device_class_hid_report_set(), specifically when the report +id is non-zero and the report to set is larger than the device's event buffer length. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + +UINT has_testing_started; +UCHAR buffer_device[64]; +TX_SEMAPHORE test_semaphore; + +UCHAR test_buffer[33] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x85, 0x01, // REPORT_ID (1) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x21, // REPORT_COUNT (33) + 0x75, 0x08, // REPORT_SIZE (8) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + 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_device_class_hid_report_set_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_hid_report_set.c 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; + hid_parameter.ux_device_class_hid_parameter_report_id = 0x01; + + /* 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 UINT demo_thread_hid_callback(UX_SLAVE_CLASS_HID *class, UX_SLAVE_CLASS_HID_EVENT *event) +{ + + if (event -> ux_device_class_hid_event_report_type == UX_DEVICE_CLASS_HID_REPORT_TYPE_OUTPUT) + { + + if (has_testing_started) + { + + /* Ensure report id is correct. */ + if (event -> ux_device_class_hid_event_buffer[0] != 0x01) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + if (ux_utility_memory_compare(test_buffer, event -> ux_device_class_hid_event_buffer + 1, 32) != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + ux_utility_semaphore_put(&test_semaphore); + } + } + + return(UX_SUCCESS); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_CLIENT_REPORT client_report; + + + status = ux_utility_semaphore_create(&test_semaphore, "test_semaphore", 0); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + client_report.ux_host_class_hid_client_report = hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_output_report; + client_report.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_RAW; + client_report.ux_host_class_hid_client_report_length = 33; + client_report.ux_host_class_hid_client_report_buffer = (ULONG *)test_buffer; + + status = ux_host_class_hid_report_set(hid, &client_report); + if (status != UX_SUCCESS) + { + + printf("Error on line %d; status code: %d\n", __LINE__, status); + 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); +} diff --git a/test/regression/usbx_ux_device_class_hid_report_set_test2.c b/test/regression/usbx_ux_device_class_hid_report_set_test2.c new file mode 100644 index 00000000..01c70273 --- /dev/null +++ b/test/regression/usbx_ux_device_class_hid_report_set_test2.c @@ -0,0 +1,326 @@ +/**************************************************/ +/** Test case: if (hid -> ux_device_class_hid_callback != UX_NULL) fails. **/ +/** How: Do hid_parameter.ux_device_class_hid_parameter_callback = UX_NULL; before passing hid_parameter to device class register function. **/ +/**************************************************/ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_hid_report_set_test2_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_hid_report_set Test 2....................... "); + + /* 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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 = UX_NULL; + + /* 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_KEYBOARD *keyboard; + + /* 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); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the keyboard instance */ + keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)hid_client -> ux_host_class_hid_client_local_instance; + + /* 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_device_class_hid_report_test.c b/test/regression/usbx_ux_device_class_hid_report_test.c new file mode 100644 index 00000000..92a6a772 --- /dev/null +++ b/test/regression/usbx_ux_device_class_hid_report_test.c @@ -0,0 +1,745 @@ +/* This file tests the ux_device_class_hid API. */ + +#include "usbx_test_common_hid.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#include "ux_host_class_hid_mouse.h" +#include "ux_host_class_hid_keyboard.h" + + +static UCHAR hid_keyboard_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#define HID_KEYBOARD_REPORT_LENGTH sizeof(hid_keyboard_report)/sizeof(hid_keyboard_report[0]) + + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x85, 0x01, // REPORT_ID (1) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN (9) + + +/* HID Mouse/Keyboard interface descriptors 9+9+7=25 bytes */ +#define HID_IFC_DESC_ALL(ifc, report_len, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(report_len),\ + MSB(report_len),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_IFC_DESC_ALL_LEN (9+9+7) + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC(CFG_DESC_LEN+2*HID_IFC_DESC_ALL_LEN, 2, 1) + /* Mouse */ + HID_IFC_DESC_ALL(0, HID_MOUSE_REPORT_LENGTH, 0x81) + /* Keyboard */ + HID_IFC_DESC_ALL(1, HID_KEYBOARD_REPORT_LENGTH, 0x82) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC(CFG_DESC_LEN+2*HID_IFC_DESC_ALL_LEN, 2, 1) + /* Mouse */ + HID_IFC_DESC_ALL(0, HID_MOUSE_REPORT_LENGTH, 0x81) + /* Keyboard */ + HID_IFC_DESC_ALL(1, HID_KEYBOARD_REPORT_LENGTH, 0x82) +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +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 +}; +#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. */ +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +static UCHAR buffer[4*UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH]; + +static UX_HOST_CLASS_HID *hid = UX_NULL; +static UX_HOST_CLASS_HID_MOUSE *hid_mouse = UX_NULL; +static UX_HOST_CLASS_HID_KEYBOARD *hid_keyboard = UX_NULL; + +static UX_SLAVE_CLASS_HID *hid_mouse_slave = UX_NULL; +static UX_SLAVE_CLASS_HID *hid_keyboard_slave = UX_NULL; + +static UX_SLAVE_CLASS_HID_PARAMETER hid_mouse_parameter; +static UX_SLAVE_CLASS_HID_PARAMETER hid_keyboard_parameter; + +static ULONG rsc_mem_alloc_cnt_on_set_cfg; +static ULONG rsc_enum_mem_alloc_count; +static ULONG rsc_hid_mem_alloc_count; + +static ULONG error_callback_counter; +static UCHAR error_callback_ignore; + +static ULONG error_counter = 0; + +static UCHAR event_callback_length_error = 0; + +static UINT ux_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_HID_CLIENT *client = (UX_HOST_CLASS_HID_CLIENT *)inst; +UINT is_mouse = (UX_SUCCESS == _ux_utility_memory_compare(client->ux_host_class_hid_client_name, + _ux_system_host_class_hid_client_mouse_name, + _ux_utility_string_length_get(_ux_system_host_class_hid_client_mouse_name))); + + // printf("hChg: %lx, %p, %p\n", event, cls, inst); + switch(event) + { + + case UX_HID_CLIENT_INSERTION: + if (is_mouse) + hid_mouse = (UX_HOST_CLASS_HID_MOUSE *)client->ux_host_class_hid_client_local_instance; + else + hid_keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)client->ux_host_class_hid_client_local_instance; + break; + + case UX_HID_CLIENT_REMOVAL: + if (is_mouse) + hid_mouse = UX_NULL; + else + hid_keyboard = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID mouse_instance_activate_callback(VOID *parameter) +{ + // printf("dMouse: %p\n", parameter); + hid_mouse_slave = (UX_SLAVE_CLASS_HID *)parameter; +} + +static VOID keyboard_instance_activate_callback(VOID *parameter) +{ + // printf("dKeyboard: %p\n", parameter); + hid_keyboard_slave = (UX_SLAVE_CLASS_HID *)parameter; +} + +static VOID instance_deactivate_callback(VOID *parameter) +{ + // printf("dRm: %p\n", parameter); + if ((VOID *)hid_mouse_slave == parameter) + hid_mouse_slave = UX_NULL; + + if ((VOID *)hid_keyboard_slave == parameter) + hid_keyboard_slave = UX_NULL; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (error_code == UX_MEMORY_INSUFFICIENT) + error_callback_counter ++; + // printf("ERROR #%d: 0x%x, 0x%x, 0x%x\n", __LINE__, system_level, system_context, error_code); +} + +static UINT break_on_all_activated(VOID) +{ + + if (hid_mouse_slave == UX_NULL) + return 0; + if (hid_keyboard_slave == UX_NULL) + return 0; + if (hid_mouse == UX_NULL) + return 0; + if (hid_keyboard == UX_NULL) + return 0; + + return 1; +} + + +static UINT break_on_all_removed(VOID) +{ + if (hid_mouse_slave || hid_keyboard_slave) + return 0; + if (hid_mouse || hid_keyboard) + return 0; + + return 1; +} + + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_hid_report_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_hid_report_... test ......,,................ "); + stepinfo("\n"); + + /* 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 #%d, code 0x%x\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + 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 #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Register the HID client(s). */ + status = ux_host_class_hid_client_register(_ux_system_host_class_hid_client_mouse_name, ux_host_class_hid_mouse_entry); + 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 #%d, code 0x%x\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 #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Initialize the hid class parameters for mouse and keyboard. */ + hid_mouse_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_mouse_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_REPORT_LENGTH; + hid_mouse_parameter.ux_device_class_hid_parameter_callback = demo_thread_hid_callback; + hid_mouse_parameter.ux_device_class_hid_parameter_get_callback = demo_thread_hid_get_callback; + hid_mouse_parameter.ux_slave_class_hid_instance_activate = mouse_instance_activate_callback; + hid_mouse_parameter.ux_slave_class_hid_instance_deactivate = instance_deactivate_callback; + hid_mouse_parameter.ux_device_class_hid_parameter_report_id = UX_TRUE; + + hid_keyboard_parameter.ux_device_class_hid_parameter_report_address = hid_keyboard_report; + hid_keyboard_parameter.ux_device_class_hid_parameter_report_length = HID_KEYBOARD_REPORT_LENGTH; + hid_keyboard_parameter.ux_device_class_hid_parameter_callback = UX_NULL; + hid_keyboard_parameter.ux_device_class_hid_parameter_get_callback = UX_NULL; + hid_keyboard_parameter.ux_slave_class_hid_instance_activate = keyboard_instance_activate_callback; + + /* Initilize the device hid class. */ + status = ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,0, (VOID *)&hid_mouse_parameter); + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1,1, (VOID *)&hid_keyboard_parameter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } +#endif + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + 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 #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_DEVICE *device; +UX_ENDPOINT *endpoint; +UX_TRANSFER *transfer_request; + + stepinfo(">>>>>>>>>> Thread start\n"); + + ux_test_breakable_sleep(200, break_on_all_activated); + + /* Get device instance. */ + status = ux_host_stack_device_get(0, &device); + + if (status != UX_SUCCESS) + { + printf("ERROR #%d: get_device fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Get control endpoint and control transfer request. */ + endpoint = &device->ux_device_control_endpoint; + transfer_request = &endpoint->ux_endpoint_transfer_request; + + /* Create a transfer request for the SET_REPORT request. */ + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_HID_SET_REPORT; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + + if (hid_keyboard) + { + + stepinfo(">>>>>>>>>> SetReport(noID, %d)\n", UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH + 1); + + transfer_request -> ux_transfer_request_requested_length = UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH + 1; + transfer_request -> ux_transfer_request_value = (UINT)((USHORT) 0 | (USHORT) UX_HOST_CLASS_HID_REPORT_TYPE_OUTPUT << 8); + transfer_request -> ux_transfer_request_index = hid_keyboard->ux_host_class_hid_keyboard_hid->ux_host_class_hid_interface->ux_interface_descriptor.bInterfaceNumber; + + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + error_counter ++; + } + } + + stepinfo(">>>>>>>>>> SetReport(1, %d)\n", UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH + 1); + + /* Create a transfer request for the SET_REPORT request. */ + transfer_request -> ux_transfer_request_requested_length = UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH; + transfer_request -> ux_transfer_request_value = (UINT)((USHORT) 1 | (USHORT) UX_HOST_CLASS_HID_REPORT_TYPE_OUTPUT << 8); + transfer_request -> ux_transfer_request_index = hid_mouse->ux_host_class_hid_mouse_hid->ux_host_class_hid_interface->ux_interface_descriptor.bInterfaceNumber; + + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + error_counter ++; + } + + if (hid_keyboard) + { + + /* Create a transfer request for the GET_REPORT request. */ + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_HID_GET_REPORT; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + + stepinfo(">>>>>>>>>> GetReport(noID, %d)\n", UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH + 1); + + transfer_request -> ux_transfer_request_requested_length = UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH + 1; + transfer_request -> ux_transfer_request_value = (UINT)((USHORT) 0 | (USHORT) UX_HOST_CLASS_HID_REPORT_TYPE_INPUT << 8); + transfer_request -> ux_transfer_request_index = hid_keyboard->ux_host_class_hid_keyboard_hid->ux_host_class_hid_interface->ux_interface_descriptor.bInterfaceNumber; + + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + error_counter ++; + } + } + + /* Create a transfer request for the GET_REPORT request. */ + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_HID_GET_REPORT; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + + if (hid_keyboard) + { + + /* Request a size that is smaller than the event buffer. */ + stepinfo(">>>>>>>>>> GetReport(noID, %d)\n", UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH - 1); + + /* Suspend the background keyboard interrupt thread so that it doesn't get our report. */ + tx_thread_suspend(&hid_keyboard_slave->ux_slave_class_hid_interface->ux_slave_interface_class->ux_slave_class_thread); + + /* Add an event so the device will try to send one back to the host. */ + UX_SLAVE_CLASS_HID_EVENT hid_event = { 0 }; + hid_event.ux_device_class_hid_event_length = UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH; + hid_event.ux_device_class_hid_event_report_id = 0; + hid_event.ux_device_class_hid_event_report_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = _ux_device_class_hid_event_set(hid_keyboard_slave, &hid_event); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + error_counter ++; + } + + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_requested_length = UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH - 1; + transfer_request -> ux_transfer_request_value = (UINT)((USHORT) 0 | (USHORT) UX_HOST_CLASS_HID_REPORT_TYPE_INPUT << 8); + transfer_request -> ux_transfer_request_index = hid_keyboard->ux_host_class_hid_keyboard_hid->ux_host_class_hid_interface->ux_interface_descriptor.bInterfaceNumber; + + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + error_counter ++; + } + + /* Resume the keyboard interrupt thread. */ + tx_thread_suspend(&hid_keyboard_slave->ux_slave_class_hid_interface->ux_slave_interface_class->ux_slave_class_thread); + + /* Request a size that is larger than the max control transfer, and when there are no events. */ + stepinfo(">>>>>>>>>> SetReport(noID, %d)\n", UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH + 1); + + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_requested_length = UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH + 1; + transfer_request -> ux_transfer_request_value = (UINT)((USHORT) 0 | (USHORT) UX_HOST_CLASS_HID_REPORT_TYPE_INPUT << 8); + transfer_request -> ux_transfer_request_index = hid_keyboard->ux_host_class_hid_keyboard_hid->ux_host_class_hid_interface->ux_interface_descriptor.bInterfaceNumber; + + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + error_counter ++; + } + } + + stepinfo(">>>>>>>>>> SetReport(1, %d)\n", UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH + 1); + + /* Create a transfer request for the SET_REPORT request. */ + transfer_request -> ux_transfer_request_requested_length = UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH + 1; + transfer_request -> ux_transfer_request_value = (UINT)((USHORT) 1 | (USHORT) UX_HOST_CLASS_HID_REPORT_TYPE_INPUT << 8); + transfer_request -> ux_transfer_request_index = hid_mouse->ux_host_class_hid_mouse_hid->ux_host_class_hid_interface->ux_interface_descriptor.bInterfaceNumber; + + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + error_counter ++; + } + + stepinfo(">>>>>>>>>> SetReport(FEATURE, 1, %d)\n", 2); + + /* Create a transfer request for the SET_REPORT request. */ + transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_HID_SET_REPORT; + transfer_request -> ux_transfer_request_type = UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_requested_length = 2; + transfer_request -> ux_transfer_request_value = (UINT)((USHORT) 1 | (USHORT) UX_HOST_CLASS_HID_REPORT_TYPE_FEATURE << 8); + transfer_request -> ux_transfer_request_index = hid_mouse->ux_host_class_hid_mouse_hid->ux_host_class_hid_interface->ux_interface_descriptor.bInterfaceNumber; + buffer[0] = 1; + buffer[1] = 0x5A; + + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + error_counter ++; + } + + stepinfo(">>>>>>>>>> GetReport(FEATURE, 1, %d)\n", 2); + + /* Create a transfer request for the GET_REPORT request. */ + transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_HID_GET_REPORT; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_requested_length = 2; + transfer_request -> ux_transfer_request_value = (UINT)((USHORT) 1 | (USHORT) UX_HOST_CLASS_HID_REPORT_TYPE_FEATURE << 8); + transfer_request -> ux_transfer_request_index = hid_mouse->ux_host_class_hid_mouse_hid->ux_host_class_hid_interface->ux_interface_descriptor.bInterfaceNumber; + buffer[0] = 0; + buffer[1] = 0; + + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + error_counter ++; + } + if (buffer[0] != 1) + { + printf("ERROR #%d: buffer[0] %x\n", __LINE__, buffer[0]); + error_counter ++; + } + if (buffer[1] != 0x5A) + { + printf("ERROR #%d: buffer[1] %x\n", __LINE__, buffer[1]); + error_counter ++; + } + + stepinfo(">>>>>>>>>> GetReport(FEATURE, 1, %d)\n", UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH + 2); + + /* Create a transfer request for the SET_REPORT request. */ + transfer_request -> ux_transfer_request_requested_length = UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH + 2; + transfer_request -> ux_transfer_request_value = (UINT)((USHORT) 1 | (USHORT) UX_HOST_CLASS_HID_REPORT_TYPE_FEATURE << 8); + transfer_request -> ux_transfer_request_index = hid_mouse->ux_host_class_hid_mouse_hid->ux_host_class_hid_interface->ux_interface_descriptor.bInterfaceNumber; + event_callback_length_error = UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH + 3; + + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + error_counter ++; + } + + if (hid_keyboard) + { + + stepinfo(">>>>>>>>>> GetReport(keyboard, FEATURE, 1, %d)\n", 1); + + /* Create a transfer request for the SET_REPORT request. */ + transfer_request -> ux_transfer_request_requested_length = 1; + transfer_request -> ux_transfer_request_value = (UINT)((USHORT) 1 | (USHORT) UX_HOST_CLASS_HID_REPORT_TYPE_FEATURE << 8); + transfer_request -> ux_transfer_request_index = hid_keyboard->ux_host_class_hid_keyboard_hid->ux_host_class_hid_interface->ux_interface_descriptor.bInterfaceNumber; + + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + error_counter ++; + } + } + + stepinfo(">>>>>>>>>> Test done\n"); + + /* 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(); + + if (error_counter) + { + printf("FAIL %ld errors!\n", error_counter); + test_control_return(1); + } + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + +static UX_SLAVE_CLASS_HID_EVENT hid_mouse_slave_event; +static UX_SLAVE_CLASS_HID_EVENT hid_keyboard_slave_event; +static UINT demo_thread_hid_callback(UX_SLAVE_CLASS_HID *class, UX_SLAVE_CLASS_HID_EVENT *event) +{ + /* Event buffer contains no report ID. */ + if (class == hid_mouse_slave) + _ux_utility_memory_copy(&hid_mouse_slave_event, event, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + if (class == hid_keyboard_slave) + _ux_utility_memory_copy(&hid_keyboard_slave_event, event, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + return(UX_SUCCESS); +} + +static UINT demo_thread_hid_get_callback(UX_SLAVE_CLASS_HID *class, UX_SLAVE_CLASS_HID_EVENT *event) +{ +UX_SLAVE_CLASS_HID_EVENT *class_event; + if (class == hid_mouse_slave) + class_event = &hid_mouse_slave_event; + else if (class == hid_keyboard_slave) + class_event = &hid_keyboard_slave_event; + else + return(UX_ERROR); + if (class -> ux_device_class_hid_report_id) + { + /* First byte in buffer should be report ID, if report ID is required. + * See HID spec. for more details. + */ + event->ux_device_class_hid_event_report_id = class_event->ux_device_class_hid_event_report_id; + event->ux_device_class_hid_event_report_type = class_event->ux_device_class_hid_event_report_type; + if (class_event->ux_device_class_hid_event_length < UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH - 1) + class_event->ux_device_class_hid_event_length += 1; + event->ux_device_class_hid_event_length = class_event->ux_device_class_hid_event_length; + *(event->ux_device_class_hid_event_buffer) = (UCHAR)event->ux_device_class_hid_event_report_id; + _ux_utility_memory_copy(event->ux_device_class_hid_event_buffer + 1, + class_event->ux_device_class_hid_event_buffer, + event->ux_device_class_hid_event_length - 1); + } + else + _ux_utility_memory_copy(event, class_event, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + if (event_callback_length_error) + { + event->ux_device_class_hid_event_length = event_callback_length_error; + event_callback_length_error = 0; + } + return(UX_SUCCESS); +} \ No newline at end of file diff --git a/test/regression/usbx_ux_device_class_hid_uninitialize_test.c b/test/regression/usbx_ux_device_class_hid_uninitialize_test.c new file mode 100644 index 00000000..1dfe9ecc --- /dev/null +++ b/test/regression/usbx_ux_device_class_hid_uninitialize_test.c @@ -0,0 +1,335 @@ +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_hid_uninitialize_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_hid_uninitialize 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_SLAVE_CLASS class; +UX_SLAVE_CLASS_COMMAND command; + + /* 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); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /**************************************************/ + /** Test case: if (hid != UX_NULL) fails **/ + /** Why direct: This function is only called if the HID class was registered. When it's registered, hid_initialize() is called, which sets 'class -> ux_slave_class_instance'. **/ + /**************************************************/ + + /* Set up. */ + class.ux_slave_class_instance = UX_NULL; + command.ux_slave_class_command_class_ptr = &class; + + if (_ux_device_class_hid_uninitialize(&command) != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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_device_class_hid_wMaxPacketSize_test.c b/test/regression/usbx_ux_device_class_hid_wMaxPacketSize_test.c new file mode 100644 index 00000000..2dd87e7d --- /dev/null +++ b/test/regression/usbx_ux_device_class_hid_wMaxPacketSize_test.c @@ -0,0 +1,427 @@ +/* This file tests the + * _ux_device_class_hid_control_request + * _ux_device_class_hid_interrupt_thread + */ + +#include "usbx_test_common_hid.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#include "ux_host_class_hid_mouse.h" +#include "ux_host_class_hid_keyboard.h" + +#include "ux_host_stack.h" + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) + +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UX_SLAVE_CLASS_HID *slave_hid = UX_NULL; +static UX_SLAVE_CLASS_HID_EVENT slave_hid_event; + +#define HOST_BUFFER_LENGTH 32 + +static UCHAR host_buffer[HOST_BUFFER_LENGTH]; +static ULONG host_buffer_length; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#define HID_REPORT_LENGTH sizeof(hid_report_descriptor)/sizeof(hid_report_descriptor[0]) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* HID Mouse interface descriptors 9+9+7=25 bytes */ +#define HID_MOUSE_IFC_DESC_ALL(ifc, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 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, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_MOUSE_IFC_DESC_ALL_LEN 25 + +/* HID Mouse interface descriptors 9+9+7+7=32 bytes */ +#define HID_TEST_IFC_DESC_ALL(ifc, epa0, epa0_type, epa1, epa1_type) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x02, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_REPORT_LENGTH),\ + MSB(HID_REPORT_LENGTH),\ + /* Endpoint descriptor */\ + 0x07, 0x05, (epa0), (epa0_type), 0x08, 0x00, 0x08,\ + /* Endpoint descriptor */\ + 0x07, 0x05, (epa1), (epa1_type), 0x08, 0x00, 0x08, +#define HID_TEST_IFC_DESC_ALL_LEN 32 + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor @ 0 */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor @ 18 */ + CFG_DESC(CFG_DESC_LEN+2*HID_TEST_IFC_DESC_ALL_LEN, 2, 1) + /* Interrupt IN @ 1st */ + HID_TEST_IFC_DESC_ALL(0, 0x81, 3, 0x02, 3) + /* HID interface but no interrupt IN */ + HID_TEST_IFC_DESC_ALL(1, 0x84, 2, 0x03, 3) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +#define DEVICE_FRAMEWORK_OFFSET_FS_EP_MPS (DEVICE_FRAMEWORK_LENGTH_FULL_SPEED-HID_TEST_IFC_DESC_ALL_LEN-7-7+4) + + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC(CFG_DESC_LEN+HID_MOUSE_IFC_DESC_ALL_LEN+HID_TEST_IFC_DESC_ALL_LEN, 2, 1) + /* Good HID interface. */ + HID_MOUSE_IFC_DESC_ALL(0, 0x81) + /* Interrupt IN @ 2nd. */ + HID_TEST_IFC_DESC_ALL(1, 0x03, 3, 0x84, 3) +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) +#define DEVICE_FRAMEWORK_OFFSET_HS_EP_MPS (DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED-HID_TEST_IFC_DESC_ALL_LEN-7+4) + + + /* 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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID instance_activate_callback(VOID *parameter) +{ + + slave_hid = (UX_SLAVE_CLASS_HID *)parameter; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + // printf("Error on line %d: 0x%x, 0x%x, 0x%x\n", __LINE__, system_level, system_context, error_code); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_hid_wMaxPacketSize_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_hid_ wMaxPacketSize tests .................. "); + stepinfo("\n"); + + /* 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, error code: 0x%x\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } +#if 0 + /* 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); + } +#endif + /* 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, error code: 0x%x\n", __LINE__, status); + 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; + hid_parameter.ux_slave_class_hid_instance_activate = instance_activate_callback; + + /* Initialize 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, 0, (VOID *)&hid_parameter); + if(status!=UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static VOID _hid_report_callback(UX_HOST_CLASS_HID_REPORT_CALLBACK *callback) +{ + ULONG length; + length = callback->ux_host_class_hid_report_callback_actual_length; + if (length > HOST_BUFFER_LENGTH) + length = HOST_BUFFER_LENGTH; + _ux_utility_memory_copy(host_buffer, + callback->ux_host_class_hid_report_callback_buffer, + length); + host_buffer_length = length; +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_DEVICE *device; +UINT i; +struct _test { + ULONG speed; + ULONG wMaxPacketSize; +} tests[] = { + {UX_FULL_SPEED_DEVICE, 0}, + {UX_FULL_SPEED_DEVICE, 128}, + {UX_FULL_SPEED_DEVICE, 8+(2<<11)}, + {UX_FULL_SPEED_DEVICE, 0xFFFF}, + {UX_FULL_SPEED_DEVICE, 16}, + {UX_HIGH_SPEED_DEVICE, 16}, + {UX_HIGH_SPEED_DEVICE, 16+(1<<11)}, + {UX_HIGH_SPEED_DEVICE, 0xFFFF}, + {UX_HIGH_SPEED_DEVICE, 32}, +}; +#define N_TESTS (sizeof(tests)/sizeof(struct _test)) + + stepinfo(">>>>>>>>>> Get HID class instance\n"); + + /* 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); + } + if (slave_hid == UX_NULL) + { + printf("Error on line %d, HID slave instance error\n", __LINE__); + test_control_return(1); + } + + /* Get device instance. */ + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: get_device fail, 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* No exit on assert hit. */ + ux_test_assert_hit_exit(0); + + for (i = 0; i < N_TESTS; i ++) + { + + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + status = demo_class_hid_get(); + + if (tests[i].speed == UX_HIGH_SPEED_DEVICE) + _ux_utility_short_put(device_framework_high_speed+DEVICE_FRAMEWORK_OFFSET_HS_EP_MPS, tests[i].wMaxPacketSize); + else + _ux_utility_short_put(device_framework_full_speed+DEVICE_FRAMEWORK_OFFSET_FS_EP_MPS, tests[i].wMaxPacketSize); + + ux_test_dcd_sim_slave_connect(tests[i].speed); + ux_test_hcd_sim_host_connect(tests[i].speed); + + /* Find the HID class */ + status = demo_class_hid_get(); + + /* Set configuration. */ + _ux_host_stack_configuration_set(device -> ux_device_first_configuration); + } + + stepinfo(">>>>>>>>>> Test done\n"); + + /* 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_device_class_storage_control_request_test.c b/test/regression/usbx_ux_device_class_storage_control_request_test.c new file mode 100644 index 00000000..5e7e0753 --- /dev/null +++ b/test/regression/usbx_ux_device_class_storage_control_request_test.c @@ -0,0 +1,797 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00 + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00 + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_storage_control_request_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_storage_control_request Test................ "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_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(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + +static void _test_init_cbw_test_unit_ready(void) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, 0, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_TEST_READY_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_TEST_READY; +} + +static UINT _test_send_cbw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; +UCHAR *cbw; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + transfer_request -> ux_transfer_request_data_pointer = cbw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CBW_LENGTH; + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(status); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_wait_csw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + /* Get the pointer to the transfer request, on the bulk in endpoint. */ + transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + /* Fill in the transfer_request parameters. */ + transfer_request -> ux_transfer_request_data_pointer = (UCHAR *) &storage -> ux_host_class_storage_csw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CSW_LENGTH; + + /* Get the CSW on the bulk in endpoint. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + return(status); + + /* Wait for the completion of the transfer request. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* If OK, we are done. */ + if (status == UX_SUCCESS) + return(status); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_EXT *class_ext; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; +UX_SLAVE_DEVICE *slave_device; +UX_SLAVE_CLASS *slave_class; +UX_SLAVE_CLASS_STORAGE *slave_storage; +UX_SLAVE_INTERFACE *slave_interface; +UX_SLAVE_ENDPOINT *slave_endpoint; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + class_ext = class -> ux_host_class_ext; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done. */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&class_ext->ux_host_class_thread); + + /* Check if test functions works. */ + _test_init_cbw_test_unit_ready(); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_send_cbw(); + if (status == UX_SUCCESS) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Send transfer request - request not supported. */ + transfer_request -> ux_transfer_request_data_pointer = UX_NULL; + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = 0x1; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceNumber; + status = ux_host_stack_transfer_request(transfer_request); + if (status == UX_SUCCESS) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Send transfer request - UX_SLAVE_CLASS_STORAGE_RESET. */ + transfer_request -> ux_transfer_request_data_pointer = UX_NULL; + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_SLAVE_CLASS_STORAGE_RESET; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceNumber; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Swap slave endpoint instance for coverage. */ + slave_device = &_ux_system_slave->ux_system_slave_device; + slave_class = _ux_system_slave->ux_system_slave_interface_class_array[0]; + slave_storage = (UX_SLAVE_CLASS_STORAGE *)slave_class->ux_slave_class_instance; + slave_interface = slave_storage->ux_slave_class_storage_interface; + + slave_endpoint = slave_interface->ux_slave_interface_first_endpoint; + slave_interface->ux_slave_interface_first_endpoint = slave_endpoint->ux_slave_endpoint_next_endpoint; + slave_interface->ux_slave_interface_first_endpoint->ux_slave_endpoint_next_endpoint = slave_endpoint; + slave_endpoint->ux_slave_endpoint_next_endpoint = UX_NULL; + + /* Send transfer request - UX_SLAVE_CLASS_STORAGE_RESET. */ + transfer_request -> ux_transfer_request_data_pointer = UX_NULL; + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_SLAVE_CLASS_STORAGE_RESET; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceNumber; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Send transfer request - GetMaxLun. */ + transfer_request -> ux_transfer_request_data_pointer = UX_NULL; + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_SLAVE_CLASS_STORAGE_GET_MAX_LUN; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceNumber; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS && status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Invalid wValue. */ + transfer_request -> ux_transfer_request_value = 1; + transfer_request -> ux_transfer_request_index = storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceNumber; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Invalid wIndex. */ + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceNumber + 1; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Send transfer request - UX_SLAVE_CLASS_STORAGE_RESET. */ + transfer_request -> ux_transfer_request_function = UX_SLAVE_CLASS_STORAGE_RESET; + + /* Invalid wValue. */ + transfer_request -> ux_transfer_request_value = 1; + transfer_request -> ux_transfer_request_index = storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceNumber; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Invalid wIndex. */ + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceNumber + 1; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Invalid wLength. */ + transfer_request -> ux_transfer_request_data_pointer = (UCHAR*)&status; + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceNumber; + transfer_request -> ux_transfer_request_requested_length = 1; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} diff --git a/test/regression/usbx_ux_device_class_storage_entry_test.c b/test/regression/usbx_ux_device_class_storage_entry_test.c new file mode 100644 index 00000000..d4297cb0 --- /dev/null +++ b/test/regression/usbx_ux_device_class_storage_entry_test.c @@ -0,0 +1,646 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00 + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00 + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_storage_entry_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_storage_entry Test.......................... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_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(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + +static void _test_init_cbw_test_unit_ready(void) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, 0, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_TEST_READY_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_TEST_READY; +} + +static UINT _test_send_cbw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; +UCHAR *cbw; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + transfer_request -> ux_transfer_request_data_pointer = cbw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CBW_LENGTH; + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(status); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_wait_csw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + /* Get the pointer to the transfer request, on the bulk in endpoint. */ + transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + /* Fill in the transfer_request parameters. */ + transfer_request -> ux_transfer_request_data_pointer = (UCHAR *) &storage -> ux_host_class_storage_csw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CSW_LENGTH; + + /* Get the CSW on the bulk in endpoint. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + return(status); + + /* Wait for the completion of the transfer request. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* If OK, we are done. */ + if (status == UX_SUCCESS) + return(status); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; +UX_SLAVE_CLASS_COMMAND slave_command; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done. */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + /* UX_NO_CLASS_MATCH. */ + slave_command.ux_slave_class_command_request = UX_SLAVE_CLASS_COMMAND_QUERY; + slave_command.ux_slave_class_command_class = UX_SLAVE_CLASS_STORAGE_CLASS + 1; + status = ux_device_class_storage_entry(&slave_command); + if (status != UX_NO_CLASS_MATCH) + { + printf("ERROR #%d: 0x%2x\n", __LINE__, status); + test_control_return(1); + } + + /* UX_FUNCTION_NOT_SUPPORTED. */ + slave_command.ux_slave_class_command_request = 0xFF; + status = ux_device_class_storage_entry(&slave_command); + if (status != UX_FUNCTION_NOT_SUPPORTED) + { + printf("ERROR #%d: 0x%2x\n", __LINE__, status); + test_control_return(1); + } + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} diff --git a/test/regression/usbx_ux_device_class_storage_format_test.c b/test/regression/usbx_ux_device_class_storage_format_test.c new file mode 100644 index 00000000..06f3160d --- /dev/null +++ b/test/regression/usbx_ux_device_class_storage_format_test.c @@ -0,0 +1,746 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00 + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00 + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_storage_format_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_storage_format Test......................... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_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(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + +static void _test_init_cbw_FORMAT_UNIT(void) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, 0, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_FORMAT; +} + +static UINT _test_send_cbw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; +UCHAR *cbw; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + transfer_request -> ux_transfer_request_data_pointer = cbw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CBW_LENGTH; + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_transfer_data(UCHAR *data, ULONG size, UCHAR do_read) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + transfer_request = do_read ? + &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request : + &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + transfer_request -> ux_transfer_request_data_pointer = data; + transfer_request -> ux_transfer_request_requested_length = size; + + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_wait_csw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + /* Get the pointer to the transfer request, on the bulk in endpoint. */ + transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + /* Fill in the transfer_request parameters. */ + transfer_request -> ux_transfer_request_data_pointer = (UCHAR *) &storage -> ux_host_class_storage_csw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CSW_LENGTH; + + /* Get the CSW on the bulk in endpoint. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + return(status); + + /* Wait for the completion of the transfer request. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* If OK, we are done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static VOID _test_clear_stall(UCHAR clear_read_stall) +{ + +UX_ENDPOINT *endpoint; + + + endpoint = clear_read_stall ? + storage -> ux_host_class_storage_bulk_in_endpoint : + storage -> ux_host_class_storage_bulk_out_endpoint; + _ux_host_stack_endpoint_reset(endpoint); +} + +static UINT _test_request_sense(void) +{ + +UINT status; +UX_TRANSFER *transfer_request; +UCHAR *cbw; +UCHAR *request_sense_response; +ULONG sense_code; +UINT command_length = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_COMMAND_LENGTH_SBC; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + _ux_utility_memory_copy(storage -> ux_host_class_storage_saved_cbw, storage -> ux_host_class_storage_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + _ux_host_class_storage_cbw_initialize(storage, UX_HOST_CLASS_STORAGE_DATA_IN, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_REQUEST_SENSE; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_ALLOCATION_LENGTH) = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH; + request_sense_response = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH); + if (request_sense_response == UX_NULL) + return(UX_MEMORY_INSUFFICIENT); + status = _test_send_cbw(); + if (status == UX_SUCCESS) + { + status = _test_transfer_data(request_sense_response, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, UX_TRUE); + if (status == UX_SUCCESS) + { + status = _test_wait_csw(); + if (status == UX_SUCCESS) + { + + sense_code = (((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_SENSE_KEY)) & 0x0f) << 16; + sense_code |= ((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE)) << 8; + sense_code |= (ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE_QUALIFIER); + + storage -> ux_host_class_storage_sense_code = sense_code; + } + } + } + _ux_utility_memory_free(request_sense_response); + _ux_utility_memory_copy(storage -> ux_host_class_storage_cbw, storage -> ux_host_class_storage_saved_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + return(status); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done. */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + _test_init_cbw_FORMAT_UNIT(); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data("test dead beef", 15, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_request_sense(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} diff --git a/test/regression/usbx_ux_device_class_storage_initialize_test.c b/test/regression/usbx_ux_device_class_storage_initialize_test.c new file mode 100644 index 00000000..9e096f2b --- /dev/null +++ b/test/regression/usbx_ux_device_class_storage_initialize_test.c @@ -0,0 +1,831 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_storage_initialize_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_storage_initialize Test..................... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_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(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + +static UINT test_host_class_storage_inquiry(UX_HOST_CLASS_STORAGE *storage, UCHAR page_code, UCHAR *response, ULONG response_length) +{ +UINT status; +UCHAR *cbw; +UINT command_length; + + /* Use a pointer for the cbw, easier to manipulate. */ + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + /* Get the Write Command Length. */ + command_length = UX_HOST_CLASS_STORAGE_INQUIRY_COMMAND_LENGTH_SBC; + + /* Initialize the CBW for this command. */ + _ux_host_class_storage_cbw_initialize(storage, UX_HOST_CLASS_STORAGE_DATA_IN, UX_HOST_CLASS_STORAGE_INQUIRY_RESPONSE_LENGTH, command_length); + + /* Prepare the INQUIRY command block. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_INQUIRY; + + /* Store the page code. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_PAGE_CODE) = page_code; + + /* Store the length of the Inquiry Response. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_ALLOCATION_LENGTH) = (UCHAR)response_length; + + /* Send the command to transport layer. */ + status = _ux_host_class_storage_transport(storage, response); + + /* Return completion status. */ + return(status); +} + +static void _test_init_cbw_MODE_SENSE(UCHAR op6, UCHAR page_code, ULONG buffer_length) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, 0, command_length); + if (op6) + { + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE_SHORT; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PARAMETER_LIST_LENGTH_6) = (UCHAR)buffer_length; + } + else + { + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE; + _ux_utility_short_put_big_endian(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PARAMETER_LIST_LENGTH_10, (USHORT)buffer_length); + } + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PC_PAGE_CODE) = page_code; +} + +static UINT _test_send_cbw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; +UCHAR *cbw; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + transfer_request -> ux_transfer_request_data_pointer = cbw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CBW_LENGTH; + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_transfer_data(UCHAR *data, ULONG size, UCHAR do_read) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + transfer_request = do_read ? + &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request : + &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + transfer_request -> ux_transfer_request_data_pointer = data; + transfer_request -> ux_transfer_request_requested_length = size; + + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_wait_csw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + /* Get the pointer to the transfer request, on the bulk in endpoint. */ + transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + /* Fill in the transfer_request parameters. */ + transfer_request -> ux_transfer_request_data_pointer = (UCHAR *) &storage -> ux_host_class_storage_csw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CSW_LENGTH; + + /* Get the CSW on the bulk in endpoint. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + return(status); + + /* Wait for the completion of the transfer request. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* If OK, we are done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_clear_stall(UCHAR clear_read_stall) +{ + +UX_ENDPOINT *endpoint; + + + endpoint = clear_read_stall ? + storage -> ux_host_class_storage_bulk_in_endpoint : + storage -> ux_host_class_storage_bulk_out_endpoint; + _ux_host_stack_endpoint_reset(endpoint); +} + +static UINT _test_request_sense(void) +{ + +UINT status; +UX_TRANSFER *transfer_request; +UCHAR *cbw; +UCHAR *request_sense_response; +ULONG sense_code; +UINT command_length = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_COMMAND_LENGTH_SBC; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + _ux_utility_memory_copy(storage -> ux_host_class_storage_saved_cbw, storage -> ux_host_class_storage_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + _ux_host_class_storage_cbw_initialize(storage, UX_HOST_CLASS_STORAGE_DATA_IN, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_REQUEST_SENSE; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_ALLOCATION_LENGTH) = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH; + request_sense_response = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH); + if (request_sense_response == UX_NULL) + return(UX_MEMORY_INSUFFICIENT); + status = _test_send_cbw(); + if (status == UX_SUCCESS) + { + status = _test_transfer_data(request_sense_response, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, UX_TRUE); + if (status == UX_SUCCESS) + { + status = _test_wait_csw(); + if (status == UX_SUCCESS) + { + + sense_code = (((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_SENSE_KEY)) & 0x0f) << 16; + sense_code |= ((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE)) << 8; + sense_code |= (ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE_QUALIFIER); + + storage -> ux_host_class_storage_sense_code = sense_code; + } + } + } + _ux_utility_memory_free(request_sense_response); + _ux_utility_memory_copy(storage -> ux_host_class_storage_cbw, storage -> ux_host_class_storage_saved_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + return(status); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; +UX_SLAVE_DEVICE *slave_device; +UX_SLAVE_CLASS *slave_class; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done. */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + stepinfo(">>>>>>>>>>>>>>> ux_device_class_storage_initialize - lun exceed UX_MAX_SLAVE_LUN\n"); + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = UX_MAX_SLAVE_LUN + 1; + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 1, (VOID *)&global_storage_parameter); + if (status == UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + stepinfo(">>>>>>>>>>>>>>> ux_device_class_storage_initialize - storage memory error\n"); + ux_test_utility_sim_mem_allocate_until(0); + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 1, (VOID *)&global_storage_parameter); + ux_test_utility_sim_mem_free_all(); + if (status == UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_device_class_storage_initialize - thread stack memory error\n"); + ux_test_utility_sim_mem_allocate_until(sizeof(UX_SLAVE_CLASS_STORAGE) + UX_THREAD_STACK_SIZE / 2); + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 1, (VOID *)&global_storage_parameter); + ux_test_utility_sim_mem_free_all(); + if (status == UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_device_class_storage_initialize - thread create error\n"); + slave_device = &_ux_system_slave->ux_system_slave_device; + slave_class = &_ux_system_slave->ux_system_slave_class_array[1]; + status = _ux_utility_thread_create(&slave_class -> ux_slave_class_thread, "ux_slave_storage_thread", + _ux_device_class_storage_thread, + (ULONG) (ALIGN_TYPE) slave_class, (VOID *) buffer, + UX_THREAD_STACK_SIZE, UX_THREAD_PRIORITY_CLASS, + UX_THREAD_PRIORITY_CLASS, UX_NO_TIME_SLICE, TX_DONT_START); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + UX_THREAD_EXTENSION_PTR_SET(&slave_class -> ux_slave_class_thread, slave_class) + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 1, (VOID *)&global_storage_parameter); + if (status == UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_utility_thread_delete(&slave_class -> ux_slave_class_thread); + + stepinfo(">>>>>>>>>>>>>>> ux_device_class_storage_initialize - lun block length error\n"); + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE * 2; + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 1, (VOID *)&global_storage_parameter); + if (status == UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} diff --git a/test/regression/usbx_ux_device_class_storage_inquiry_test.c b/test/regression/usbx_ux_device_class_storage_inquiry_test.c new file mode 100644 index 00000000..2e9d668b --- /dev/null +++ b/test/regression/usbx_ux_device_class_storage_inquiry_test.c @@ -0,0 +1,868 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00 + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00 + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UX_SLAVE_CLASS_STORAGE slave_storage; +static UCHAR cbwcb_data[64]; +static UX_SLAVE_ENDPOINT endpoint_in; +static UCHAR data_pointer[256]; +static UCHAR product_serial[40]; +static void line190_coverage(void) +{ + UX_SLAVE_TRANSFER *transfer_request; + + cbwcb_data[UX_SLAVE_CLASS_STORAGE_INQUIRY_PAGE_CODE] = UX_SLAVE_CLASS_STORAGE_INQUIRY_PAGE_CODE_SERIAL; + + slave_storage.ux_slave_class_storage_host_length = 23; + slave_storage.ux_slave_class_storage_cbw_flags = 0x80; + endpoint_in.ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer = data_pointer; + slave_storage.ux_slave_class_storage_product_serial = product_serial; + _ux_device_class_storage_inquiry(&slave_storage, 0, &endpoint_in, NX_NULL, cbwcb_data); + + +} + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_storage_inquiry_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_storage_inquiry Test........................ "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_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(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + +static UINT _test_host_class_storage_inquiry(UX_HOST_CLASS_STORAGE *storage, + UCHAR flags, ULONG data_length, ULONG cb_length, + UCHAR page_code, UCHAR *response, ULONG response_length) +{ +UINT status; +UCHAR *cbw; +UINT command_length; + + /* Use a pointer for the cbw, easier to manipulate. */ + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + /* Initialize the CBW for this command. */ + _ux_host_class_storage_cbw_initialize(storage, flags, data_length, cb_length); + + /* Prepare the INQUIRY command block. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_INQUIRY; + + /* Store the page code. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_PAGE_CODE) = page_code; + + /* Store the length of the Inquiry Response. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_ALLOCATION_LENGTH) = (UCHAR)response_length; + + /* Send the command to transport layer. */ + status = _ux_host_class_storage_transport(storage, response); + + /* Return completion status. */ + return(status); +} + +static UINT test_host_class_storage_inquiry(UX_HOST_CLASS_STORAGE *storage, UCHAR page_code, UCHAR *response, ULONG response_length) +{ + _test_host_class_storage_inquiry(storage, + UX_HOST_CLASS_STORAGE_DATA_IN, + UX_HOST_CLASS_STORAGE_INQUIRY_RESPONSE_LENGTH, + UX_HOST_CLASS_STORAGE_INQUIRY_COMMAND_LENGTH_SBC, + page_code, response, response_length); +} + +static void _test_init_cbw_MODE_SENSE(UCHAR op6, UCHAR page_code, ULONG buffer_length) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, 0, command_length); + if (op6) + { + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE_SHORT; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PARAMETER_LIST_LENGTH_6) = (UCHAR)buffer_length; + } + else + { + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE; + _ux_utility_short_put_big_endian(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PARAMETER_LIST_LENGTH_10, (USHORT)buffer_length); + } + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PC_PAGE_CODE) = page_code; +} + +static UINT _test_send_cbw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; +UCHAR *cbw; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + transfer_request -> ux_transfer_request_data_pointer = cbw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CBW_LENGTH; + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_transfer_data(UCHAR *data, ULONG size, UCHAR do_read) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + transfer_request = do_read ? + &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request : + &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + transfer_request -> ux_transfer_request_data_pointer = data; + transfer_request -> ux_transfer_request_requested_length = size; + + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_wait_csw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + /* Get the pointer to the transfer request, on the bulk in endpoint. */ + transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + /* Fill in the transfer_request parameters. */ + transfer_request -> ux_transfer_request_data_pointer = (UCHAR *) &storage -> ux_host_class_storage_csw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CSW_LENGTH; + + /* Get the CSW on the bulk in endpoint. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + return(status); + + /* Wait for the completion of the transfer request. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* If OK, we are done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_clear_stall(UCHAR clear_read_stall) +{ + +UX_ENDPOINT *endpoint; + + + endpoint = clear_read_stall ? + storage -> ux_host_class_storage_bulk_in_endpoint : + storage -> ux_host_class_storage_bulk_out_endpoint; + _ux_host_stack_endpoint_reset(endpoint); +} + +static UINT _test_request_sense(void) +{ + +UINT status; +UX_TRANSFER *transfer_request; +UCHAR *cbw; +UCHAR *request_sense_response; +ULONG sense_code; +UINT command_length = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_COMMAND_LENGTH_SBC; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + _ux_utility_memory_copy(storage -> ux_host_class_storage_saved_cbw, storage -> ux_host_class_storage_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + _ux_host_class_storage_cbw_initialize(storage, UX_HOST_CLASS_STORAGE_DATA_IN, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_REQUEST_SENSE; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_ALLOCATION_LENGTH) = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH; + request_sense_response = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH); + if (request_sense_response == UX_NULL) + return(UX_MEMORY_INSUFFICIENT); + status = _test_send_cbw(); + if (status == UX_SUCCESS) + { + status = _test_transfer_data(request_sense_response, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, UX_TRUE); + if (status == UX_SUCCESS) + { + status = _test_wait_csw(); + if (status == UX_SUCCESS) + { + + sense_code = (((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_SENSE_KEY)) & 0x0f) << 16; + sense_code |= ((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE)) << 8; + sense_code |= (ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE_QUALIFIER); + + storage -> ux_host_class_storage_sense_code = sense_code; + } + } + } + _ux_utility_memory_free(request_sense_response); + _ux_utility_memory_copy(storage -> ux_host_class_storage_cbw, storage -> ux_host_class_storage_saved_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + return(status); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; +UX_SLAVE_DEVICE *slave_device; +UX_SLAVE_CLASS *slave_class; +UX_SLAVE_CLASS_STORAGE *slave_storage; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done. */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(standard)\n"); + + status = test_host_class_storage_inquiry(storage, 0x00, buffer, 64); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(standard, UX_SLAVE_CLASS_STORAGE_MEDIA_CDROM)\n"); + + slave_device = &_ux_system_slave->ux_system_slave_device; + slave_class = _ux_system_slave->ux_system_slave_interface_class_array[0]; + slave_storage = (UX_SLAVE_CLASS_STORAGE *)slave_class->ux_slave_class_instance; + slave_storage -> ux_slave_class_storage_lun[0].ux_slave_class_storage_media_type = UX_SLAVE_CLASS_STORAGE_MEDIA_CDROM; + status = test_host_class_storage_inquiry(storage, 0x00, buffer, 64); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(unknown page code)\n"); + + status = test_host_class_storage_inquiry(storage, 0xEF, buffer, 64); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(big buffer)\n"); + + status = _test_host_class_storage_inquiry(storage, 0x80, + 64, + UX_HOST_CLASS_STORAGE_INQUIRY_COMMAND_LENGTH_SBC, + 0x00, buffer, 64); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + UX_TEST_ASSERT(storage -> ux_host_class_storage_data_phase_length < 64); + UX_TEST_ASSERT(_ux_utility_long_get(storage -> ux_host_class_storage_csw + UX_SLAVE_CLASS_STORAGE_CSW_DATA_RESIDUE) == 64 - storage -> ux_host_class_storage_data_phase_length); + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(Hi <> Do)\n"); + + status = _test_host_class_storage_inquiry(storage, 0x00, + UX_HOST_CLASS_STORAGE_INQUIRY_RESPONSE_LENGTH, + UX_HOST_CLASS_STORAGE_INQUIRY_COMMAND_LENGTH_SBC, + 0x00, buffer, UX_HOST_CLASS_STORAGE_INQUIRY_RESPONSE_LENGTH); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(Hi <> Do)\n"); + + status = _test_host_class_storage_inquiry(storage, 0x00, + 0, + UX_HOST_CLASS_STORAGE_INQUIRY_COMMAND_LENGTH_SBC, + 0x00, buffer, UX_HOST_CLASS_STORAGE_INQUIRY_RESPONSE_LENGTH); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_entry); + + /* Deinitialize the device side of usbx. */ + _ux_device_stack_uninitialize(); + + /* And finally the usbx system resources. */ + _ux_system_uninitialize(); + + line190_coverage(); + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + + +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} diff --git a/test/regression/usbx_ux_device_class_storage_invalid_lun_test.c b/test/regression/usbx_ux_device_class_storage_invalid_lun_test.c new file mode 100644 index 00000000..98b9a8e2 --- /dev/null +++ b/test/regression/usbx_ux_device_class_storage_invalid_lun_test.c @@ -0,0 +1,817 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00 + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00 + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_storage_inquiry_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_storage_ Invalid LUN Test................... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_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(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + +static UINT _test_host_class_storage_inquiry(UX_HOST_CLASS_STORAGE *storage, + UCHAR flags, ULONG data_length, ULONG cb_length, + UCHAR page_code, UCHAR *response, ULONG response_length) +{ +UINT status; +UCHAR *cbw; +UINT command_length; + + /* Use a pointer for the cbw, easier to manipulate. */ + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + /* Initialize the CBW for this command. */ + _ux_host_class_storage_cbw_initialize(storage, flags, data_length, cb_length); + + /* Prepare the INQUIRY command block. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_INQUIRY; + + /* Store the page code. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_PAGE_CODE) = page_code; + + /* Store the length of the Inquiry Response. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_ALLOCATION_LENGTH) = (UCHAR)response_length; + + /* Send the command to transport layer. */ + status = _ux_host_class_storage_transport(storage, response); + + /* Return completion status. */ + return(status); +} + +static UINT test_host_class_storage_inquiry(UX_HOST_CLASS_STORAGE *storage, UCHAR page_code, UCHAR *response, ULONG response_length) +{ + _test_host_class_storage_inquiry(storage, + UX_HOST_CLASS_STORAGE_DATA_IN, + UX_HOST_CLASS_STORAGE_INQUIRY_RESPONSE_LENGTH, + UX_HOST_CLASS_STORAGE_INQUIRY_COMMAND_LENGTH_SBC, + page_code, response, response_length); +} + +static void _test_init_cbw_MODE_SENSE(UCHAR op6, UCHAR page_code, ULONG buffer_length) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, 0, command_length); + if (op6) + { + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE_SHORT; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PARAMETER_LIST_LENGTH_6) = (UCHAR)buffer_length; + } + else + { + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE; + _ux_utility_short_put_big_endian(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PARAMETER_LIST_LENGTH_10, (USHORT)buffer_length); + } + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PC_PAGE_CODE) = page_code; +} + +static UINT _test_send_cbw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; +UCHAR *cbw; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + transfer_request -> ux_transfer_request_data_pointer = cbw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CBW_LENGTH; + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_transfer_data(UCHAR *data, ULONG size, UCHAR do_read) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + transfer_request = do_read ? + &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request : + &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + transfer_request -> ux_transfer_request_data_pointer = data; + transfer_request -> ux_transfer_request_requested_length = size; + + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_wait_csw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + /* Get the pointer to the transfer request, on the bulk in endpoint. */ + transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + /* Fill in the transfer_request parameters. */ + transfer_request -> ux_transfer_request_data_pointer = (UCHAR *) &storage -> ux_host_class_storage_csw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CSW_LENGTH; + + /* Get the CSW on the bulk in endpoint. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + return(status); + + /* Wait for the completion of the transfer request. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* If OK, we are done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_clear_stall(UCHAR clear_read_stall) +{ + +UX_ENDPOINT *endpoint; + + + endpoint = clear_read_stall ? + storage -> ux_host_class_storage_bulk_in_endpoint : + storage -> ux_host_class_storage_bulk_out_endpoint; + _ux_host_stack_endpoint_reset(endpoint); +} + +static UINT _test_request_sense(void) +{ + +UINT status; +UX_TRANSFER *transfer_request; +UCHAR *cbw; +UCHAR *request_sense_response; +ULONG sense_code; +UINT command_length = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_COMMAND_LENGTH_SBC; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + _ux_utility_memory_copy(storage -> ux_host_class_storage_saved_cbw, storage -> ux_host_class_storage_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + _ux_host_class_storage_cbw_initialize(storage, UX_HOST_CLASS_STORAGE_DATA_IN, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_REQUEST_SENSE; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_ALLOCATION_LENGTH) = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH; + request_sense_response = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH); + if (request_sense_response == UX_NULL) + return(UX_MEMORY_INSUFFICIENT); + status = _test_send_cbw(); + if (status == UX_SUCCESS) + { + status = _test_transfer_data(request_sense_response, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, UX_TRUE); + if (status == UX_SUCCESS) + { + status = _test_wait_csw(); + if (status == UX_SUCCESS) + { + + sense_code = (((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_SENSE_KEY)) & 0x0f) << 16; + sense_code |= ((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE)) << 8; + sense_code |= (ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE_QUALIFIER); + + storage -> ux_host_class_storage_sense_code = sense_code; + } + } + } + _ux_utility_memory_free(request_sense_response); + _ux_utility_memory_copy(storage -> ux_host_class_storage_cbw, storage -> ux_host_class_storage_saved_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + return(status); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; +UX_SLAVE_DEVICE *slave_device; +UX_SLAVE_CLASS *slave_class; +UX_SLAVE_CLASS_STORAGE *slave_storage; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done. */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(standard)\n"); + + status = test_host_class_storage_inquiry(storage, 0x00, buffer, 64); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test LUNs ~255\n"); + for (; storage -> ux_host_class_storage_lun < 255; storage -> ux_host_class_storage_lun ++) + { + status = test_host_class_storage_inquiry(storage, 0x00, buffer, 64); + if (storage -> ux_host_class_storage_lun < global_storage_parameter.ux_slave_class_storage_parameter_number_lun) + { + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + } + else + { + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: expect error!\n", __LINE__); + test_control_return(1); + } + } + } + + stepinfo(">>>>>>>>>>>>>>>> Test LUN 0\n"); + storage -> ux_host_class_storage_lun = 0; + status = test_host_class_storage_inquiry(storage, 0x00, buffer, 64); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} diff --git a/test/regression/usbx_ux_device_class_storage_mode_select_test.c b/test/regression/usbx_ux_device_class_storage_mode_select_test.c new file mode 100644 index 00000000..05548c60 --- /dev/null +++ b/test/regression/usbx_ux_device_class_storage_mode_select_test.c @@ -0,0 +1,783 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00 + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00 + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_storage_mode_select_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_storage_mode_select Test.................... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_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(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + +static void _test_init_cbw_MODE_SELECT(ULONG data_length) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, data_length, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SELECT; +} + +static UINT _test_send_cbw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; +UCHAR *cbw; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + transfer_request -> ux_transfer_request_data_pointer = cbw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CBW_LENGTH; + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_transfer_data(UCHAR *data, ULONG size, UCHAR do_read) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + transfer_request = do_read ? + &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request : + &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + transfer_request -> ux_transfer_request_data_pointer = data; + transfer_request -> ux_transfer_request_requested_length = size; + + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_wait_csw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + /* Get the pointer to the transfer request, on the bulk in endpoint. */ + transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + /* Fill in the transfer_request parameters. */ + transfer_request -> ux_transfer_request_data_pointer = (UCHAR *) &storage -> ux_host_class_storage_csw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CSW_LENGTH; + + /* Get the CSW on the bulk in endpoint. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + return(status); + + /* Wait for the completion of the transfer request. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* If OK, we are done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static VOID _test_clear_stall(UCHAR clear_read_stall) +{ + +UX_ENDPOINT *endpoint; + + + endpoint = clear_read_stall ? + storage -> ux_host_class_storage_bulk_in_endpoint : + storage -> ux_host_class_storage_bulk_out_endpoint; + _ux_host_stack_endpoint_reset(endpoint); +} + +static UINT _test_request_sense(void) +{ + +UINT status; +UX_TRANSFER *transfer_request; +UCHAR *cbw; +UCHAR *request_sense_response; +ULONG sense_code; +UINT command_length = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_COMMAND_LENGTH_SBC; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + _ux_utility_memory_copy(storage -> ux_host_class_storage_saved_cbw, storage -> ux_host_class_storage_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + _ux_host_class_storage_cbw_initialize(storage, UX_HOST_CLASS_STORAGE_DATA_IN, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_REQUEST_SENSE; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_ALLOCATION_LENGTH) = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH; + request_sense_response = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH); + if (request_sense_response == UX_NULL) + return(UX_MEMORY_INSUFFICIENT); + status = _test_send_cbw(); + if (status == UX_SUCCESS) + { + status = _test_transfer_data(request_sense_response, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, UX_TRUE); + if (status == UX_SUCCESS) + { + status = _test_wait_csw(); + if (status == UX_SUCCESS) + { + + sense_code = (((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_SENSE_KEY)) & 0x0f) << 16; + sense_code |= ((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE)) << 8; + sense_code |= (ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE_QUALIFIER); + + storage -> ux_host_class_storage_sense_code = sense_code; + } + } + } + _ux_utility_memory_free(request_sense_response); + _ux_utility_memory_copy(storage -> ux_host_class_storage_cbw, storage -> ux_host_class_storage_saved_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + return(status); +} + +static void _msc_mode_select_cases_test(const char* __file__, int __line__) +{ +UINT status; + + stepinfo("\n%s:%d:MSC MODE_SELECT tests\n", __file__, __line__); + + _test_init_cbw_MODE_SELECT(15); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data("test dead beef", 15, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_request_sense(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void _msc_mode_select_cases_test2(const char* __file__, int __line__) +{ +UINT status; + + stepinfo("\n%s:%d:MSC MODE_SELECT tests\n", __file__, __line__); + + _test_init_cbw_MODE_SELECT(0); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_request_sense(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done. */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + _msc_mode_select_cases_test(__FILE__, __LINE__); + _msc_mode_select_cases_test2(__FILE__, __LINE__); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} diff --git a/test/regression/usbx_ux_device_class_storage_mode_sense_test.c b/test/regression/usbx_ux_device_class_storage_mode_sense_test.c new file mode 100644 index 00000000..d7e5f6fb --- /dev/null +++ b/test/regression/usbx_ux_device_class_storage_mode_sense_test.c @@ -0,0 +1,941 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00 + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00 + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_storage_mode_sense_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_storage_mode_sense Test..................... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_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(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + +static void _test_init_cbw_MODE_SENSE(UCHAR op6, UCHAR page_code, ULONG buffer_length) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, 0, command_length); + if (op6) + { + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE_SHORT; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PARAMETER_LIST_LENGTH_6) = (UCHAR)buffer_length; + } + else + { + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE; + _ux_utility_short_put_big_endian(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PARAMETER_LIST_LENGTH_10, (USHORT)buffer_length); + } + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_MODE_SENSE_PC_PAGE_CODE) = page_code; +} + +static UINT _test_send_cbw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; +UCHAR *cbw; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + transfer_request -> ux_transfer_request_data_pointer = cbw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CBW_LENGTH; + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_transfer_data(UCHAR *data, ULONG size, UCHAR do_read) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + transfer_request = do_read ? + &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request : + &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + transfer_request -> ux_transfer_request_data_pointer = data; + transfer_request -> ux_transfer_request_requested_length = size; + + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_wait_csw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + /* Get the pointer to the transfer request, on the bulk in endpoint. */ + transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + /* Fill in the transfer_request parameters. */ + transfer_request -> ux_transfer_request_data_pointer = (UCHAR *) &storage -> ux_host_class_storage_csw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CSW_LENGTH; + + /* Get the CSW on the bulk in endpoint. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + return(status); + + /* Wait for the completion of the transfer request. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* If OK, we are done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_clear_stall(UCHAR clear_read_stall) +{ + +UX_ENDPOINT *endpoint; + + + endpoint = clear_read_stall ? + storage -> ux_host_class_storage_bulk_in_endpoint : + storage -> ux_host_class_storage_bulk_out_endpoint; + _ux_host_stack_endpoint_reset(endpoint); +} + +static UINT _test_request_sense(void) +{ + +UINT status; +UX_TRANSFER *transfer_request; +UCHAR *cbw; +UCHAR *request_sense_response; +ULONG sense_code; +UINT command_length = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_COMMAND_LENGTH_SBC; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + _ux_utility_memory_copy(storage -> ux_host_class_storage_saved_cbw, storage -> ux_host_class_storage_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + _ux_host_class_storage_cbw_initialize(storage, UX_HOST_CLASS_STORAGE_DATA_IN, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_REQUEST_SENSE; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_ALLOCATION_LENGTH) = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH; + request_sense_response = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH); + if (request_sense_response == UX_NULL) + return(UX_MEMORY_INSUFFICIENT); + status = _test_send_cbw(); + if (status == UX_SUCCESS) + { + status = _test_transfer_data(request_sense_response, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, UX_TRUE); + if (status == UX_SUCCESS) + { + status = _test_wait_csw(); + if (status == UX_SUCCESS) + { + + sense_code = (((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_SENSE_KEY)) & 0x0f) << 16; + sense_code |= ((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE)) << 8; + sense_code |= (ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE_QUALIFIER); + + storage -> ux_host_class_storage_sense_code = sense_code; + } + } + } + _ux_utility_memory_free(request_sense_response); + _ux_utility_memory_copy(storage -> ux_host_class_storage_cbw, storage -> ux_host_class_storage_saved_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + return(status); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; +UX_SLAVE_DEVICE *slave_device; +UX_SLAVE_CLASS *slave_class; +UX_SLAVE_CLASS_STORAGE *slave_storage; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done. */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + /************ UX_SLAVE_CLASS_STORAGE_MMC2_PAGE_CODE_CDROM ****************/ + + _test_init_cbw_MODE_SENSE(UX_FALSE, UX_SLAVE_CLASS_STORAGE_MMC2_PAGE_CODE_CDROM, 128); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(buffer, 128, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + _test_init_cbw_MODE_SENSE(UX_TRUE, UX_SLAVE_CLASS_STORAGE_MMC2_PAGE_CODE_CDROM, 74); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(buffer, 74, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Change read_only_flag */ + slave_device = &_ux_system_slave->ux_system_slave_device; + slave_class = _ux_system_slave->ux_system_slave_interface_class_array[0]; + slave_storage = (UX_SLAVE_CLASS_STORAGE *)slave_class->ux_slave_class_instance; + slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_read_only_flag = UX_TRUE; + + /************ UX_SLAVE_CLASS_STORAGE_PAGE_CODE_CACHE ****************/ + + _test_init_cbw_MODE_SENSE(UX_FALSE, UX_SLAVE_CLASS_STORAGE_PAGE_CODE_CACHE, 128); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(buffer, 128, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + _test_init_cbw_MODE_SENSE(UX_TRUE, UX_SLAVE_CLASS_STORAGE_PAGE_CODE_CACHE, 24); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(buffer, 24, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_flush = demo_media_flush; + _test_init_cbw_MODE_SENSE(UX_TRUE, UX_SLAVE_CLASS_STORAGE_PAGE_CODE_CACHE, 24); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(buffer, 24, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /************ UX_SLAVE_CLASS_STORAGE_PAGE_CODE_IEC ****************/ + + _test_init_cbw_MODE_SENSE(UX_FALSE, UX_SLAVE_CLASS_STORAGE_PAGE_CODE_IEC, 128); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(buffer, 128, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + _test_init_cbw_MODE_SENSE(UX_TRUE, UX_SLAVE_CLASS_STORAGE_PAGE_CODE_IEC, 16); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(buffer, 16, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /************ 0x3F ****************/ + + _test_init_cbw_MODE_SENSE(UX_FALSE, 0x3F, 128); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(buffer, 128, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /************ 0x3F ****************/ + + _test_init_cbw_MODE_SENSE(UX_FALSE, 0x3F, UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE + 8); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(buffer, 128, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)lun; + (void)number_blocks; + (void)lba; + (void)media_status; + return 0; +} \ No newline at end of file diff --git a/test/regression/usbx_ux_device_class_storage_prevent_allow_media_removal_test.c b/test/regression/usbx_ux_device_class_storage_prevent_allow_media_removal_test.c new file mode 100644 index 00000000..66429d49 --- /dev/null +++ b/test/regression/usbx_ux_device_class_storage_prevent_allow_media_removal_test.c @@ -0,0 +1,734 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00 + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00 + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_storage_prevent_allow_media_removal_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_storage_prevent_allow_media_removal Test.... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_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(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + +static void _test_init_cbw_PREVENT_ALLOW_MEDIA_REMOVAL(void) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, 0, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_PREVENT_ALLOW_MEDIA_REMOVAL; +} + +static UINT _test_send_cbw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; +UCHAR *cbw; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + transfer_request -> ux_transfer_request_data_pointer = cbw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CBW_LENGTH; + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_transfer_data(UCHAR *data, ULONG size, UCHAR do_read) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + transfer_request = do_read ? + &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request : + &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + transfer_request -> ux_transfer_request_data_pointer = data; + transfer_request -> ux_transfer_request_requested_length = size; + + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_wait_csw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + /* Get the pointer to the transfer request, on the bulk in endpoint. */ + transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + /* Fill in the transfer_request parameters. */ + transfer_request -> ux_transfer_request_data_pointer = (UCHAR *) &storage -> ux_host_class_storage_csw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CSW_LENGTH; + + /* Get the CSW on the bulk in endpoint. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + return(status); + + /* Wait for the completion of the transfer request. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* If OK, we are done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_clear_stall(UCHAR clear_read_stall) +{ + +UX_ENDPOINT *endpoint; + + + endpoint = clear_read_stall ? + storage -> ux_host_class_storage_bulk_in_endpoint : + storage -> ux_host_class_storage_bulk_out_endpoint; + _ux_host_stack_endpoint_reset(endpoint); +} + +static UINT _test_request_sense(void) +{ + +UINT status; +UX_TRANSFER *transfer_request; +UCHAR *cbw; +UCHAR *request_sense_response; +ULONG sense_code; +UINT command_length = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_COMMAND_LENGTH_SBC; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + _ux_utility_memory_copy(storage -> ux_host_class_storage_saved_cbw, storage -> ux_host_class_storage_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + _ux_host_class_storage_cbw_initialize(storage, UX_HOST_CLASS_STORAGE_DATA_IN, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_REQUEST_SENSE; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_ALLOCATION_LENGTH) = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH; + request_sense_response = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH); + if (request_sense_response == UX_NULL) + return(UX_MEMORY_INSUFFICIENT); + status = _test_send_cbw(); + if (status == UX_SUCCESS) + { + status = _test_transfer_data(request_sense_response, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, UX_TRUE); + if (status == UX_SUCCESS) + { + status = _test_wait_csw(); + if (status == UX_SUCCESS) + { + + sense_code = (((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_SENSE_KEY)) & 0x0f) << 16; + sense_code |= ((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE)) << 8; + sense_code |= (ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE_QUALIFIER); + + storage -> ux_host_class_storage_sense_code = sense_code; + } + } + } + _ux_utility_memory_free(request_sense_response); + _ux_utility_memory_copy(storage -> ux_host_class_storage_cbw, storage -> ux_host_class_storage_saved_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + return(status); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done. */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + _test_init_cbw_PREVENT_ALLOW_MEDIA_REMOVAL(); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} diff --git a/test/regression/usbx_ux_device_class_storage_read_test.c b/test/regression/usbx_ux_device_class_storage_read_test.c new file mode 100644 index 00000000..8e61630e --- /dev/null +++ b/test/regression/usbx_ux_device_class_storage_read_test.c @@ -0,0 +1,995 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static CHAR ram_disk_flush = 0; +static UINT ram_disk_flush_status = UX_SUCCESS; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + + +static UX_TEST_HCD_SIM_ACTION fail_on_bulkin[] = { +/* 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_DCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x81, UX_NULL, 0, UX_ERROR, + UX_ERROR, UX_NULL, + UX_FALSE}, /* Invoke callback & no continue */ +{ 0 } +}; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_storage_read_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_storage_read Test........................... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_parameter); + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + 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 #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + +static UINT test_host_class_storage_inquiry(UX_HOST_CLASS_STORAGE *storage, UCHAR page_code, UCHAR *response, ULONG response_length) +{ +UINT status; +UCHAR *cbw; +UINT command_length; + + /* Use a pointer for the cbw, easier to manipulate. */ + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + /* Get the Write Command Length. */ + command_length = UX_HOST_CLASS_STORAGE_INQUIRY_COMMAND_LENGTH_SBC; + + /* Initialize the CBW for this command. */ + _ux_host_class_storage_cbw_initialize(storage, UX_HOST_CLASS_STORAGE_DATA_IN, UX_HOST_CLASS_STORAGE_INQUIRY_RESPONSE_LENGTH, command_length); + + /* Prepare the INQUIRY command block. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_INQUIRY; + + /* Store the page code. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_PAGE_CODE) = page_code; + + /* Store the length of the Inquiry Response. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_ALLOCATION_LENGTH) = (UCHAR)response_length; + + /* Send the command to transport layer. */ + status = _ux_host_class_storage_transport(storage, response); + + /* Return completion status. */ + return(status); +} + +typedef struct cbw_read_struct { + UCHAR flags_pos; + UCHAR lba_pos; + UCHAR lba_size; + UCHAR len_pos; + UCHAR len_size; +} cbw_read_struct_t; +static cbw_read_struct_t cbw_READ_info[] = +{ + { 1, 2, 2, 4, 1}, + { 1, 2, 4, 7, 2}, + { 1, 2, 4, 6, 4}, + { 1, 2, 8, 10, 4}, + {10, 12, 8, 28, 4} +}; +static UCHAR _read_op(UCHAR op_code) +{ + switch(op_code) + { + case 0x28: return 1; + case 0xA8: return 2; + case 0x88: return 3; + case 0x7F: return 4; + case 0x08: return 0; + default: return 0xFF; + } +} + +static void _test_init_cbw_READ_EX( + UCHAR flags, ULONG data_length, + UCHAR op6_10_12_16_32, ULONG lba, ULONG len) +{ +UCHAR *cbw; +UINT command_length; +UCHAR op = _read_op(op6_10_12_16_32); +UINT i; + + + if (op >= 5) + return; + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, flags, data_length, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = op6_10_12_16_32; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + cbw_READ_info[op].flags_pos) = 0; + for (i = cbw_READ_info[op].lba_pos + cbw_READ_info[op].lba_size - 1; i >= cbw_READ_info[op].lba_pos; i --) + { + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + i) = (UCHAR)lba; + lba >>= 8; + } + for (i = cbw_READ_info[op].len_pos + cbw_READ_info[op].len_size - 1; i >= cbw_READ_info[op].len_size; i --) + { + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + i) = (UCHAR)len; + len >>= 8; + } +} + +static void _test_init_cbw_READ(UCHAR op6_10_12_16_32, ULONG lba, ULONG len) +{ + _test_init_cbw_READ_EX(0x80, len * 512, op6_10_12_16_32, lba, len); +} + +static UINT _test_send_cbw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; +UCHAR *cbw; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + transfer_request -> ux_transfer_request_data_pointer = cbw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CBW_LENGTH; + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_transfer_data(UCHAR *data, ULONG size, UCHAR do_read) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + transfer_request = do_read ? + &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request : + &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + transfer_request -> ux_transfer_request_data_pointer = data; + transfer_request -> ux_transfer_request_requested_length = size; + + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_wait_csw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + /* Get the pointer to the transfer request, on the bulk in endpoint. */ + transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + /* Fill in the transfer_request parameters. */ + transfer_request -> ux_transfer_request_data_pointer = (UCHAR *) &storage -> ux_host_class_storage_csw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CSW_LENGTH; + + /* Get the CSW on the bulk in endpoint. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + return(status); + + /* Wait for the completion of the transfer request. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* If OK, we are done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static VOID _test_clear_stall(UCHAR clear_read_stall) +{ + +UX_ENDPOINT *endpoint; + + + endpoint = clear_read_stall ? + storage -> ux_host_class_storage_bulk_in_endpoint : + storage -> ux_host_class_storage_bulk_out_endpoint; + _ux_host_stack_endpoint_reset(endpoint); +} + +static UINT _test_request_sense(void) +{ + +UINT status; +UX_TRANSFER *transfer_request; +UCHAR *cbw; +UCHAR *request_sense_response; +ULONG sense_code; +UINT command_length = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_COMMAND_LENGTH_SBC; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + _ux_utility_memory_copy(storage -> ux_host_class_storage_saved_cbw, storage -> ux_host_class_storage_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + _ux_host_class_storage_cbw_initialize(storage, UX_HOST_CLASS_STORAGE_DATA_IN, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_REQUEST_SENSE; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_ALLOCATION_LENGTH) = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH; + request_sense_response = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH); + if (request_sense_response == UX_NULL) + return(UX_MEMORY_INSUFFICIENT); + status = _test_send_cbw(); + if (status == UX_SUCCESS) + { + status = _test_transfer_data(request_sense_response, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, UX_TRUE); + if (status == UX_SUCCESS) + { + status = _test_wait_csw(); + if (status == UX_SUCCESS) + { + + sense_code = (((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_SENSE_KEY)) & 0x0f) << 16; + sense_code |= ((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE)) << 8; + sense_code |= (ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE_QUALIFIER); + + storage -> ux_host_class_storage_sense_code = sense_code; + } + } + } + _ux_utility_memory_free(request_sense_response); + _ux_utility_memory_copy(storage -> ux_host_class_storage_cbw, storage -> ux_host_class_storage_saved_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + return(status); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done. */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_READ16 - success\n"); + _test_init_cbw_READ(UX_SLAVE_CLASS_STORAGE_SCSI_READ16, 0, 1); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(buffer, 512, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_READ32 - success\n"); + _test_init_cbw_READ(UX_SLAVE_CLASS_STORAGE_SCSI_READ32, 0, 1); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(buffer, 512, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_READ16 - status fail\n"); + ram_disk_status = UX_ERROR; + _test_init_cbw_READ(UX_SLAVE_CLASS_STORAGE_SCSI_READ16, 0, 1); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(buffer, 512, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + ram_disk_status = UX_SUCCESS; + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_READ16 - transfer fail\n"); + _test_init_cbw_READ(UX_SLAVE_CLASS_STORAGE_SCSI_READ16, 0, 1); + ux_test_dcd_sim_slave_set_actions(fail_on_bulkin); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(buffer, 512, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_READ16 - Case(7) Hi < Di\n"); + _test_init_cbw_READ_EX(0x80, 0, UX_SLAVE_CLASS_STORAGE_SCSI_READ16, 0, 1); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(buffer, 512, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_READ16 - Case(8) Hi <> Do\n"); + _test_init_cbw_READ_EX(0x00, 512, UX_SLAVE_CLASS_STORAGE_SCSI_READ16, 0, 1); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(buffer, 512, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_READ16 - Case(5) Hi > Di\n"); + _test_init_cbw_READ_EX(0x80, 1024, UX_SLAVE_CLASS_STORAGE_SCSI_READ16, 0, 1); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(buffer, 1024, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)number_blocks; + (void)lba; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ram_disk_flush = UX_TRUE; + return ram_disk_flush_status; +} \ No newline at end of file diff --git a/test/regression/usbx_ux_device_class_storage_request_sense_coverage_test.c b/test/regression/usbx_ux_device_class_storage_request_sense_coverage_test.c new file mode 100644 index 00000000..ce3d1398 --- /dev/null +++ b/test/regression/usbx_ux_device_class_storage_request_sense_coverage_test.c @@ -0,0 +1,44 @@ +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" +#include "ux_test.h" +#include "ux_device_class_storage.h" +#include "ux_test_utility_sim.h" + + +static UX_SYSTEM_SLAVE system_slave; +static UX_SLAVE_CLASS_STORAGE slave_storage; +static UCHAR cbwcb_data[64]; +static UX_SLAVE_ENDPOINT endpoint_in; +static UCHAR data_pointer[256]; + + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_device_class_storage_request_sense_coverage_test_application_define(void *first_unused_memory) +#endif +{ + + + /* Inform user. */ + printf("Running USB Device Class Storage Request Sense Coverage Test ....... "); + + + _ux_system_slave = &system_slave; + cbwcb_data[UX_SLAVE_CLASS_STORAGE_INQUIRY_PAGE_CODE] = UX_SLAVE_CLASS_STORAGE_INQUIRY_PAGE_CODE_SERIAL; + + slave_storage.ux_slave_class_storage_host_length = 0; + + endpoint_in.ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer = data_pointer; + _ux_device_class_storage_request_sense(&slave_storage, 0, &endpoint_in, NX_NULL, cbwcb_data); + + + printf("SUCCESS!\n"); + + test_control_return(0); + return; +} diff --git a/test/regression/usbx_ux_device_class_storage_request_sense_test.c b/test/regression/usbx_ux_device_class_storage_request_sense_test.c new file mode 100644 index 00000000..5cedef8b --- /dev/null +++ b/test/regression/usbx_ux_device_class_storage_request_sense_test.c @@ -0,0 +1,742 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; +static UCHAR demo_buffer[UX_DEMO_BUFFER_SIZE]; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00 + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00 + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_storage_request_sense_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_storage_request_sense Test.................. "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_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(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + +static void _test_init_cbw_REQUEST_SENSE(ULONG data_length) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0x80, data_length, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_REQUEST_SENSE; +} + +static UINT _test_send_cbw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; +UCHAR *cbw; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + transfer_request -> ux_transfer_request_data_pointer = cbw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CBW_LENGTH; + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_transfer_data(UCHAR *data, ULONG size, UCHAR do_read) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + transfer_request = do_read ? + &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request : + &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + transfer_request -> ux_transfer_request_data_pointer = data; + transfer_request -> ux_transfer_request_requested_length = size; + + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_wait_csw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + /* Get the pointer to the transfer request, on the bulk in endpoint. */ + transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + /* Fill in the transfer_request parameters. */ + transfer_request -> ux_transfer_request_data_pointer = (UCHAR *) &storage -> ux_host_class_storage_csw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CSW_LENGTH; + + /* Get the CSW on the bulk in endpoint. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + return(status); + + /* Wait for the completion of the transfer request. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* If OK, we are done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static VOID _test_clear_stall(UCHAR clear_read_stall) +{ + +UX_ENDPOINT *endpoint; + + + endpoint = clear_read_stall ? + storage -> ux_host_class_storage_bulk_in_endpoint : + storage -> ux_host_class_storage_bulk_out_endpoint; + _ux_host_stack_endpoint_reset(endpoint); +} + +static UINT _test_request_sense(void) +{ + +UINT status; +UX_TRANSFER *transfer_request; +UCHAR *cbw; +UCHAR *request_sense_response; +ULONG sense_code; +UINT command_length = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_COMMAND_LENGTH_SBC; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + _ux_utility_memory_copy(storage -> ux_host_class_storage_saved_cbw, storage -> ux_host_class_storage_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + _ux_host_class_storage_cbw_initialize(storage, UX_HOST_CLASS_STORAGE_DATA_IN, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_REQUEST_SENSE; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_ALLOCATION_LENGTH) = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH; + request_sense_response = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH); + if (request_sense_response == UX_NULL) + return(UX_MEMORY_INSUFFICIENT); + status = _test_send_cbw(); + if (status == UX_SUCCESS) + { + status = _test_transfer_data(request_sense_response, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, UX_TRUE); + if (status == UX_SUCCESS) + { + status = _test_wait_csw(); + if (status == UX_SUCCESS) + { + + sense_code = (((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_SENSE_KEY)) & 0x0f) << 16; + sense_code |= ((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE)) << 8; + sense_code |= (ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE_QUALIFIER); + + storage -> ux_host_class_storage_sense_code = sense_code; + } + } + } + _ux_utility_memory_free(request_sense_response); + _ux_utility_memory_copy(storage -> ux_host_class_storage_cbw, storage -> ux_host_class_storage_saved_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + return(status); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done. */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + _test_init_cbw_REQUEST_SENSE(64); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(demo_buffer, 64, UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} diff --git a/test/regression/usbx_ux_device_class_storage_start_stop_test.c b/test/regression/usbx_ux_device_class_storage_start_stop_test.c new file mode 100644 index 00000000..bf432b61 --- /dev/null +++ b/test/regression/usbx_ux_device_class_storage_start_stop_test.c @@ -0,0 +1,736 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00 + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00 + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_storage_start_stop_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_storage_start_stop Test..................... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_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(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + +static void _test_init_cbw_START_STOP(void) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, 0, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_START_STOP; +} + +static UINT _test_send_cbw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; +UCHAR *cbw; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + transfer_request -> ux_transfer_request_data_pointer = cbw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CBW_LENGTH; + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_transfer_data(UCHAR *data, ULONG size, UCHAR do_read) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + transfer_request = do_read ? + &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request : + &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + transfer_request -> ux_transfer_request_data_pointer = data; + transfer_request -> ux_transfer_request_requested_length = size; + + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_wait_csw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + /* Get the pointer to the transfer request, on the bulk in endpoint. */ + transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + /* Fill in the transfer_request parameters. */ + transfer_request -> ux_transfer_request_data_pointer = (UCHAR *) &storage -> ux_host_class_storage_csw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CSW_LENGTH; + + /* Get the CSW on the bulk in endpoint. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + return(status); + + /* Wait for the completion of the transfer request. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* If OK, we are done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_clear_stall(UCHAR clear_read_stall) +{ + +UX_ENDPOINT *endpoint; + + + endpoint = clear_read_stall ? + storage -> ux_host_class_storage_bulk_in_endpoint : + storage -> ux_host_class_storage_bulk_out_endpoint; + _ux_host_stack_endpoint_reset(endpoint); +} + +static UINT _test_request_sense(void) +{ + +UINT status; +UX_TRANSFER *transfer_request; +UCHAR *cbw; +UCHAR *request_sense_response; +ULONG sense_code; +UINT command_length = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_COMMAND_LENGTH_SBC; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + _ux_utility_memory_copy(storage -> ux_host_class_storage_saved_cbw, storage -> ux_host_class_storage_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + _ux_host_class_storage_cbw_initialize(storage, UX_HOST_CLASS_STORAGE_DATA_IN, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_REQUEST_SENSE; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_ALLOCATION_LENGTH) = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH; + request_sense_response = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH); + if (request_sense_response == UX_NULL) + return(UX_MEMORY_INSUFFICIENT); + status = _test_send_cbw(); + if (status == UX_SUCCESS) + { + status = _test_transfer_data(request_sense_response, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, UX_TRUE); + if (status == UX_SUCCESS) + { + status = _test_wait_csw(); + if (status == UX_SUCCESS) + { + + sense_code = (((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_SENSE_KEY)) & 0x0f) << 16; + sense_code |= ((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE)) << 8; + sense_code |= (ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE_QUALIFIER); + + storage -> ux_host_class_storage_sense_code = sense_code; + } + } + } + _ux_utility_memory_free(request_sense_response); + _ux_utility_memory_copy(storage -> ux_host_class_storage_cbw, storage -> ux_host_class_storage_saved_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + return(status); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done. */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + /************ UX_SLAVE_CLASS_STORAGE_MMC2_PAGE_CODE_CDROM ****************/ + + _test_init_cbw_START_STOP(); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} diff --git a/test/regression/usbx_ux_device_class_storage_synchronize_cache_test.c b/test/regression/usbx_ux_device_class_storage_synchronize_cache_test.c new file mode 100644 index 00000000..4f376728 --- /dev/null +++ b/test/regression/usbx_ux_device_class_storage_synchronize_cache_test.c @@ -0,0 +1,845 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static CHAR ram_disk_flush = 0; +static UINT ram_disk_flush_status = UX_SUCCESS; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_storage_synchronize_cache_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_storage_synchronize_cache Test.............. "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_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(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + +static UINT test_host_class_storage_inquiry(UX_HOST_CLASS_STORAGE *storage, UCHAR page_code, UCHAR *response, ULONG response_length) +{ +UINT status; +UCHAR *cbw; +UINT command_length; + + /* Use a pointer for the cbw, easier to manipulate. */ + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + /* Get the Write Command Length. */ + command_length = UX_HOST_CLASS_STORAGE_INQUIRY_COMMAND_LENGTH_SBC; + + /* Initialize the CBW for this command. */ + _ux_host_class_storage_cbw_initialize(storage, UX_HOST_CLASS_STORAGE_DATA_IN, UX_HOST_CLASS_STORAGE_INQUIRY_RESPONSE_LENGTH, command_length); + + /* Prepare the INQUIRY command block. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_INQUIRY; + + /* Store the page code. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_PAGE_CODE) = page_code; + + /* Store the length of the Inquiry Response. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_ALLOCATION_LENGTH) = (UCHAR)response_length; + + /* Send the command to transport layer. */ + status = _ux_host_class_storage_transport(storage, response); + + /* Return completion status. */ + return(status); +} + +static void _test_init_cbw_SYNCHRONIZE_CACHE(UCHAR op16, UCHAR immed, ULONG lba, ULONG nb_blocks) +{ + +UCHAR *cbw; +UINT command_length; + + + (void)op16; + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, 0, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_SYNCHRONIZE_CACHE_FLAGS) = immed ? UX_SLAVE_CLASS_STORAGE_SYNCHRONIZE_CACHE_FLAGS_IMMED : 0; + _ux_utility_long_put_big_endian(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_SYNCHRONIZE_CACHE_LBA, lba); + _ux_utility_short_put_big_endian(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_SLAVE_CLASS_STORAGE_SYNCHRONIZE_CACHE_NUMBER_OF_BLOCKS, (USHORT)nb_blocks); +} + +static UINT _test_send_cbw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; +UCHAR *cbw; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + transfer_request -> ux_transfer_request_data_pointer = cbw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CBW_LENGTH; + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_transfer_data(UCHAR *data, ULONG size, UCHAR do_read) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + transfer_request = do_read ? + &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request : + &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + transfer_request -> ux_transfer_request_data_pointer = data; + transfer_request -> ux_transfer_request_requested_length = size; + + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_wait_csw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + /* Get the pointer to the transfer request, on the bulk in endpoint. */ + transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + /* Fill in the transfer_request parameters. */ + transfer_request -> ux_transfer_request_data_pointer = (UCHAR *) &storage -> ux_host_class_storage_csw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CSW_LENGTH; + + /* Get the CSW on the bulk in endpoint. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + return(status); + + /* Wait for the completion of the transfer request. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* If OK, we are done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static VOID _test_clear_stall(UCHAR clear_read_stall) +{ + +UX_ENDPOINT *endpoint; + + + endpoint = clear_read_stall ? + storage -> ux_host_class_storage_bulk_in_endpoint : + storage -> ux_host_class_storage_bulk_out_endpoint; + _ux_host_stack_endpoint_reset(endpoint); +} + +static UINT _test_request_sense(void) +{ + +UINT status; +UX_TRANSFER *transfer_request; +UCHAR *cbw; +UCHAR *request_sense_response; +ULONG sense_code; +UINT command_length = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_COMMAND_LENGTH_SBC; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + _ux_utility_memory_copy(storage -> ux_host_class_storage_saved_cbw, storage -> ux_host_class_storage_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + _ux_host_class_storage_cbw_initialize(storage, UX_HOST_CLASS_STORAGE_DATA_IN, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_REQUEST_SENSE; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_ALLOCATION_LENGTH) = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH; + request_sense_response = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH); + if (request_sense_response == UX_NULL) + return(UX_MEMORY_INSUFFICIENT); + status = _test_send_cbw(); + if (status == UX_SUCCESS) + { + status = _test_transfer_data(request_sense_response, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, UX_TRUE); + if (status == UX_SUCCESS) + { + status = _test_wait_csw(); + if (status == UX_SUCCESS) + { + + sense_code = (((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_SENSE_KEY)) & 0x0f) << 16; + sense_code |= ((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE)) << 8; + sense_code |= (ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE_QUALIFIER); + + storage -> ux_host_class_storage_sense_code = sense_code; + } + } + } + _ux_utility_memory_free(request_sense_response); + _ux_utility_memory_copy(storage -> ux_host_class_storage_cbw, storage -> ux_host_class_storage_saved_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + return(status); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done. */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE - success\n"); + _test_init_cbw_SYNCHRONIZE_CACHE(UX_FALSE, UX_FALSE, 0, 1); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE - status fail\n"); + _test_init_cbw_SYNCHRONIZE_CACHE(UX_FALSE, UX_FALSE, 0, 1); + ram_disk_status = UX_ERROR; + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_request_sense(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + ram_disk_status = UX_SUCCESS; + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE - flush fail\n"); + _test_init_cbw_SYNCHRONIZE_CACHE(UX_FALSE, UX_FALSE, 0, 1); + ram_disk_flush_status = UX_ERROR; + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + ram_disk_flush_status = UX_SUCCESS; + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)number_blocks; + (void)lba; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ram_disk_flush = UX_TRUE; + return ram_disk_flush_status; +} \ No newline at end of file diff --git a/test/regression/usbx_ux_device_class_storage_test_ready_test.c b/test/regression/usbx_ux_device_class_storage_test_ready_test.c new file mode 100644 index 00000000..84e895cd --- /dev/null +++ b/test/regression/usbx_ux_device_class_storage_test_ready_test.c @@ -0,0 +1,750 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_class_storage.h" +#include "ux_host_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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; +static UCHAR demo_buffer[UX_DEMO_BUFFER_SIZE]; + +static UX_HOST_CLASS_STORAGE *storage; +UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00 + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00 + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_storage_test_ready_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_storage_test_ready Test..................... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_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(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + +static void _test_init_cbw_TEST_READY(ULONG data_length) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0x00, data_length, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_TEST_READY; +} + +static UINT _test_send_cbw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; +UCHAR *cbw; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + transfer_request -> ux_transfer_request_data_pointer = cbw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CBW_LENGTH; + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_transfer_data(UCHAR *data, ULONG size, UCHAR do_read) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + transfer_request = do_read ? + &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request : + &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + transfer_request -> ux_transfer_request_data_pointer = data; + transfer_request -> ux_transfer_request_requested_length = size; + + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_wait_csw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + /* Get the pointer to the transfer request, on the bulk in endpoint. */ + transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + /* Fill in the transfer_request parameters. */ + transfer_request -> ux_transfer_request_data_pointer = (UCHAR *) &storage -> ux_host_class_storage_csw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CSW_LENGTH; + + /* Get the CSW on the bulk in endpoint. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + return(status); + + /* Wait for the completion of the transfer request. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* If OK, we are done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static VOID _test_clear_stall(UCHAR clear_read_stall) +{ + +UX_ENDPOINT *endpoint; + + + endpoint = clear_read_stall ? + storage -> ux_host_class_storage_bulk_in_endpoint : + storage -> ux_host_class_storage_bulk_out_endpoint; + _ux_host_stack_endpoint_reset(endpoint); +} + +static UINT _test_request_sense(void) +{ + +UINT status; +UX_TRANSFER *transfer_request; +UCHAR *cbw; +UCHAR *request_sense_response; +ULONG sense_code; +UINT command_length = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_COMMAND_LENGTH_SBC; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + _ux_utility_memory_copy(storage -> ux_host_class_storage_saved_cbw, storage -> ux_host_class_storage_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + _ux_host_class_storage_cbw_initialize(storage, UX_HOST_CLASS_STORAGE_DATA_IN, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_REQUEST_SENSE; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_ALLOCATION_LENGTH) = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH; + request_sense_response = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH); + if (request_sense_response == UX_NULL) + return(UX_MEMORY_INSUFFICIENT); + status = _test_send_cbw(); + if (status == UX_SUCCESS) + { + status = _test_transfer_data(request_sense_response, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, UX_TRUE); + if (status == UX_SUCCESS) + { + status = _test_wait_csw(); + if (status == UX_SUCCESS) + { + + sense_code = (((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_SENSE_KEY)) & 0x0f) << 16; + sense_code |= ((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE)) << 8; + sense_code |= (ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE_QUALIFIER); + + storage -> ux_host_class_storage_sense_code = sense_code; + } + } + } + _ux_utility_memory_free(request_sense_response); + _ux_utility_memory_copy(storage -> ux_host_class_storage_cbw, storage -> ux_host_class_storage_saved_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + return(status); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Change RAM disk status and wait it sent. */ + ram_disk_status = UX_ERROR; + ram_disk_media_status = UX_SLAVE_CLASS_STORAGE_SENSE_KEY_NOT_READY; + ram_disk_status_sent = UX_FALSE; + while(!ram_disk_status_sent) + _ux_utility_delay_ms(100); + + /* Confirm media unmounted on host side. */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED, 1000); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Change RAM disk status and wait it sent. */ + ram_disk_status = UX_ERROR; + ram_disk_media_status = UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8); + ram_disk_status_sent = UX_FALSE; + while(!ram_disk_status_sent) + _ux_utility_delay_ms(100); + + /* Confirm media mounted on host side. */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 1000); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + _test_init_cbw_TEST_READY(64); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(demo_buffer, 64, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} diff --git a/test/regression/usbx_ux_device_class_storage_thread_test.c b/test/regression/usbx_ux_device_class_storage_thread_test.c new file mode 100644 index 00000000..723fcdfb --- /dev/null +++ b/test/regression/usbx_ux_device_class_storage_thread_test.c @@ -0,0 +1,1080 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static CHAR ram_disk_flush = 0; +static UINT ram_disk_flush_status = UX_SUCCESS; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + + +static UX_TEST_HCD_SIM_ACTION fail_on_bulkin[] = { +/* 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_DCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x81, UX_NULL, 0, UX_ERROR, + UX_ERROR, UX_NULL, + UX_FALSE}, /* Invoke callback & no continue */ +{ 0 } +}; + +static VOID action_disconnect_on_stall(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_SLAVE_DEVICE *slave_device; + + + slave_device = &_ux_system_slave->ux_system_slave_device; + slave_device->ux_slave_device_state = UX_DEVICE_ADDRESSED; +} + +static UX_TEST_HCD_SIM_ACTION disconnect_on_stall[] = { +/* 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_DCD_STALL_ENDPOINT, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x81, UX_NULL, 0, UX_SUCCESS, + UX_SUCCESS, action_disconnect_on_stall, + UX_FALSE}, /* Invoke callback & no continue */ +{ 0 } +}; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_storage_thread_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_storage_thread Test......................... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_parameter); + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + 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 #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + +static UINT test_host_class_storage_inquiry(UX_HOST_CLASS_STORAGE *storage, UCHAR page_code, UCHAR *response, ULONG response_length) +{ +UINT status; +UCHAR *cbw; +UINT command_length; + + /* Use a pointer for the cbw, easier to manipulate. */ + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + /* Get the Write Command Length. */ + command_length = UX_HOST_CLASS_STORAGE_INQUIRY_COMMAND_LENGTH_SBC; + + /* Initialize the CBW for this command. */ + _ux_host_class_storage_cbw_initialize(storage, UX_HOST_CLASS_STORAGE_DATA_IN, UX_HOST_CLASS_STORAGE_INQUIRY_RESPONSE_LENGTH, command_length); + + /* Prepare the INQUIRY command block. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_INQUIRY; + + /* Store the page code. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_PAGE_CODE) = page_code; + + /* Store the length of the Inquiry Response. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_ALLOCATION_LENGTH) = (UCHAR)response_length; + + /* Send the command to transport layer. */ + status = _ux_host_class_storage_transport(storage, response); + + /* Return completion status. */ + return(status); +} + +static void _test_init_cbw(UCHAR dCBWSignature_error, + ULONG dCBWDataTransferLength, UCHAR dir, UCHAR lun, UCHAR bCBWCBLength, + UCHAR cb_op) +{ + +UCHAR *cbw; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + _ux_host_class_storage_cbw_initialize(storage, dir ? 0x80 : 0, dCBWDataTransferLength, bCBWCBLength); + + if (dCBWSignature_error) + *(cbw + UX_HOST_CLASS_STORAGE_CBW_SIGNATURE) = 0x00; + + *(cbw + UX_HOST_CLASS_STORAGE_CBW_LUN) = lun; + + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = cb_op; +} + +static UINT _test_send_cbw(UCHAR length_error) +{ + +UX_TRANSFER *transfer_request; +UINT status; +UCHAR *cbw; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + transfer_request -> ux_transfer_request_data_pointer = cbw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CBW_LENGTH - length_error; + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_transfer_data(UCHAR *data, ULONG size, UCHAR do_read) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + transfer_request = do_read ? + &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request : + &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + transfer_request -> ux_transfer_request_data_pointer = data; + transfer_request -> ux_transfer_request_requested_length = size; + + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_wait_csw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + /* Get the pointer to the transfer request, on the bulk in endpoint. */ + transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + /* Fill in the transfer_request parameters. */ + transfer_request -> ux_transfer_request_data_pointer = (UCHAR *) &storage -> ux_host_class_storage_csw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CSW_LENGTH; + + /* Get the CSW on the bulk in endpoint. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + return(status); + + /* Wait for the completion of the transfer request. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* If OK, we are done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static VOID _test_clear_stall(UCHAR clear_read_stall) +{ + +UX_ENDPOINT *endpoint; + + + endpoint = clear_read_stall ? + storage -> ux_host_class_storage_bulk_in_endpoint : + storage -> ux_host_class_storage_bulk_out_endpoint; + _ux_host_stack_endpoint_reset(endpoint); +} + +static UINT _test_request_sense(void) +{ + +UINT status; +UX_TRANSFER *transfer_request; +UCHAR *cbw; +UCHAR *request_sense_response; +ULONG sense_code; +UINT command_length = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_COMMAND_LENGTH_SBC; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + _ux_utility_memory_copy(storage -> ux_host_class_storage_saved_cbw, storage -> ux_host_class_storage_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + _ux_host_class_storage_cbw_initialize(storage, UX_HOST_CLASS_STORAGE_DATA_IN, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_REQUEST_SENSE; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_ALLOCATION_LENGTH) = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH; + request_sense_response = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH); + if (request_sense_response == UX_NULL) + return(UX_MEMORY_INSUFFICIENT); + status = _test_send_cbw(UX_FALSE); + if (status == UX_SUCCESS) + { + status = _test_transfer_data(request_sense_response, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, UX_TRUE); + if (status == UX_SUCCESS) + { + status = _test_wait_csw(); + if (status == UX_SUCCESS) + { + + sense_code = (((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_SENSE_KEY)) & 0x0f) << 16; + sense_code |= ((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE)) << 8; + sense_code |= (ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE_QUALIFIER); + + storage -> ux_host_class_storage_sense_code = sense_code; + } + } + } + _ux_utility_memory_free(request_sense_response); + _ux_utility_memory_copy(storage -> ux_host_class_storage_cbw, storage -> ux_host_class_storage_saved_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + return(status); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; +UX_SLAVE_DEVICE *slave_device; +UX_SLAVE_CLASS *slave_class; +UX_SLAVE_CLASS_STORAGE *slave_storage; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done. */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + stepinfo(">>>>>>>>>>>>>>> ux_device_class_storage_thread - command unknown (write)\n"); + _test_init_cbw(UX_FALSE, 10, UX_FALSE, 0, 6, 0xFF); + status = _test_send_cbw(UX_FALSE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(buffer, 512, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_device_class_storage_thread - command unknown (read)\n"); + _test_init_cbw(UX_FALSE, 10, UX_TRUE, 0, 6, 0xFF); + status = _test_send_cbw(UX_FALSE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(buffer, 512, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_device_class_storage_thread - command unknown (no data)\n"); + _test_init_cbw(UX_FALSE, 0, UX_TRUE, 0, 6, 0xFF); + status = _test_send_cbw(UX_FALSE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Get slave information. */ + slave_device = &_ux_system_slave->ux_system_slave_device; + slave_class = _ux_system_slave->ux_system_slave_interface_class_array[0]; + slave_storage = (UX_SLAVE_CLASS_STORAGE *)slave_class->ux_slave_class_instance; + + stepinfo(">>>>>>>>>>>>>>> ux_device_class_storage_thread - bad LUN\n"); + _test_init_cbw(UX_FALSE, 0, UX_TRUE, (UCHAR)slave_storage->ux_slave_class_storage_number_lun, UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC, UX_HOST_CLASS_STORAGE_SCSI_TEST_READY); + status = _test_send_cbw(UX_FALSE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_send_cbw(UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Reset recovery. */ + _ux_host_class_storage_device_reset(storage); + _test_clear_stall(UX_TRUE); + _test_clear_stall(UX_FALSE); + + stepinfo(">>>>>>>>>>>>>>> ux_device_class_storage_thread - bad received length\n"); + _test_init_cbw(UX_FALSE, 0, UX_TRUE, 0, UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC, UX_HOST_CLASS_STORAGE_SCSI_TEST_READY); + status = _test_send_cbw(UX_TRUE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_send_cbw(UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Reset recovery. */ + _ux_host_class_storage_device_reset(storage); + _test_clear_stall(UX_TRUE); + _test_clear_stall(UX_FALSE); + + stepinfo(">>>>>>>>>>>>>>> ux_device_class_storage_thread - bad signature\n"); + _test_init_cbw(UX_TRUE, 0, UX_TRUE, 0, UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC, UX_HOST_CLASS_STORAGE_SCSI_TEST_READY); + status = _test_send_cbw(UX_FALSE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_send_cbw(UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Reset recovery. */ + _ux_host_class_storage_device_reset(storage); + _test_clear_stall(UX_TRUE); + _test_clear_stall(UX_FALSE); + + stepinfo(">>>>>>>>>>>>>>> ux_device_class_storage_thread - bad CBW length\n"); + _test_init_cbw(UX_FALSE, 0, UX_TRUE, 0, 0, UX_HOST_CLASS_STORAGE_SCSI_TEST_READY); + status = _test_send_cbw(UX_FALSE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_send_cbw(UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Reset recovery. */ + _ux_host_class_storage_device_reset(storage); + _test_clear_stall(UX_TRUE); + _test_clear_stall(UX_FALSE); + + stepinfo(">>>>>>>>>>>>>>> ux_device_class_storage_thread - CSW transfer error after stall\n"); + _test_init_cbw(UX_FALSE, 0, UX_TRUE, 0, 6, 0xFF); + ux_test_dcd_sim_slave_set_actions(fail_on_bulkin); + error_callback_counter = 0; + status = _test_send_cbw(UX_FALSE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + if (error_callback_counter == 0) + { + printf("ERROR #%d: error callback not detected\n", __LINE__); + test_control_return(1); + } + status = _test_wait_csw(); + if (status == UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_device_class_storage_thread - disconnect after stall\n"); + _test_init_cbw(UX_FALSE, 0, UX_TRUE, 0, 6, 0xFF); + ux_test_dcd_sim_slave_set_actions(disconnect_on_stall); + status = _test_send_cbw(UX_FALSE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status == UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status == UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Wait a while so the thread goes. */ + _ux_utility_delay_ms(10); + + /* Restore. */ + slave_device->ux_slave_device_state = UX_DEVICE_CONFIGURED; + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)number_blocks; + (void)lba; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ram_disk_flush = UX_TRUE; + return ram_disk_flush_status; +} \ No newline at end of file diff --git a/test/regression/usbx_ux_device_class_storage_uninitialize_test.c b/test/regression/usbx_ux_device_class_storage_uninitialize_test.c new file mode 100644 index 00000000..dc0b5264 --- /dev/null +++ b/test/regression/usbx_ux_device_class_storage_uninitialize_test.c @@ -0,0 +1,735 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00 + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00 + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_storage_uninitialize_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_storage_uninitialize Test................... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_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(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + +static void _test_init_cbw_VERIFY(void) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, 0, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_VERIFY; +} + +static UINT _test_send_cbw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; +UCHAR *cbw; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + transfer_request -> ux_transfer_request_data_pointer = cbw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CBW_LENGTH; + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_transfer_data(UCHAR *data, ULONG size, UCHAR do_read) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + transfer_request = do_read ? + &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request : + &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + transfer_request -> ux_transfer_request_data_pointer = data; + transfer_request -> ux_transfer_request_requested_length = size; + + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_wait_csw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + /* Get the pointer to the transfer request, on the bulk in endpoint. */ + transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + /* Fill in the transfer_request parameters. */ + transfer_request -> ux_transfer_request_data_pointer = (UCHAR *) &storage -> ux_host_class_storage_csw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CSW_LENGTH; + + /* Get the CSW on the bulk in endpoint. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + return(status); + + /* Wait for the completion of the transfer request. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* If OK, we are done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_clear_stall(UCHAR clear_read_stall) +{ + +UX_ENDPOINT *endpoint; + + + endpoint = clear_read_stall ? + storage -> ux_host_class_storage_bulk_in_endpoint : + storage -> ux_host_class_storage_bulk_out_endpoint; + _ux_host_stack_endpoint_reset(endpoint); +} + +static UINT _test_request_sense(void) +{ + +UINT status; +UX_TRANSFER *transfer_request; +UCHAR *cbw; +UCHAR *request_sense_response; +ULONG sense_code; +UINT command_length = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_COMMAND_LENGTH_SBC; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + _ux_utility_memory_copy(storage -> ux_host_class_storage_saved_cbw, storage -> ux_host_class_storage_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + _ux_host_class_storage_cbw_initialize(storage, UX_HOST_CLASS_STORAGE_DATA_IN, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_REQUEST_SENSE; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_ALLOCATION_LENGTH) = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH; + request_sense_response = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH); + if (request_sense_response == UX_NULL) + return(UX_MEMORY_INSUFFICIENT); + status = _test_send_cbw(); + if (status == UX_SUCCESS) + { + status = _test_transfer_data(request_sense_response, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, UX_TRUE); + if (status == UX_SUCCESS) + { + status = _test_wait_csw(); + if (status == UX_SUCCESS) + { + + sense_code = (((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_SENSE_KEY)) & 0x0f) << 16; + sense_code |= ((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE)) << 8; + sense_code |= (ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE_QUALIFIER); + + storage -> ux_host_class_storage_sense_code = sense_code; + } + } + } + _ux_utility_memory_free(request_sense_response); + _ux_utility_memory_copy(storage -> ux_host_class_storage_cbw, storage -> ux_host_class_storage_saved_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + return(status); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; +UX_SLAVE_CLASS *slave_class; +UX_SLAVE_CLASS_COMMAND slave_command; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done. */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + /* Select a class that not used and confirm its instance is NULL. */ + slave_class = &_ux_system_slave -> ux_system_slave_class_array[1]; + slave_class->ux_slave_class_instance = UX_NULL; + + slave_command.ux_slave_class_command_class_ptr = slave_class; + + status = _ux_device_class_storage_uninitialize(&slave_command); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} diff --git a/test/regression/usbx_ux_device_class_storage_vendor_strings_test.c b/test/regression/usbx_ux_device_class_storage_vendor_strings_test.c new file mode 100644 index 00000000..e36037c4 --- /dev/null +++ b/test/regression/usbx_ux_device_class_storage_vendor_strings_test.c @@ -0,0 +1,940 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" + +#include "ux_host_class_cdc_acm.h" +#include "ux_host_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#include "ux_host_stack.h" + +/* Define constants. */ +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (80*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_SIZE (256 * 1024) +#define UX_TEST_MAX_SECTOR_SIZE 512 + +/* Storage test strings. */ + +UCHAR test_ux_system_slave_class_storage_vendor_id[] = "Test VID"; +UCHAR test_ux_system_slave_class_storage_product_id[] = "UX Storage DEV "; +UCHAR test_ux_system_slave_class_storage_product_rev[] = "1010"; +UCHAR test_ux_system_slave_class_storage_product_serial[] = "01234567890123456789"; + +/* HID reports. */ + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH sizeof(hid_mouse_report) + +static UCHAR hid_keyboard_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + + 0xc0 // END_COLLECTION +}; +#define HID_KEYBOARD_REPORT_LENGTH sizeof(hid_keyboard_report) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +#define IAD_DESC(bIfc) \ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (bIfc), 0x02, 0x02, 0x02, 0x00, 0x00, +#define IAD_DESC_LEN 8 + +#define CDC_IFC_DESC_ALL(bIfc, bIntIn, bBulkIn, bBulkOut)\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (bIfc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06, (bIfc), (bIfc + 1),\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03, (bIfc + 1),\ + /* Endpoint interrupt in descriptor 7 bytes */\ + 0x07, 0x05, (bIntIn), 0x03, 0x40, 0x00, 0x10,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (bIfc + 1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint bulk in descriptor 7 bytes */\ + 0x07, 0x05, (bBulkIn), 0x02, 0x40, 0x00, 0x01,\ + /* Endpoint bulk out descriptor 7 bytes */\ + 0x07, 0x05, (bBulkOut), 0x02, 0x40, 0x00, 0x01, +#define CDC_IFC_DESC_ALL_LEN (9+5+4+5+5+7+ 9+7+7) + +#define STORAGE_IFC_DESC_ALL(bIfc, bBulkIn, bBulkOut)\ + /* Interface descriptor */\ + 0x09, 0x04, (bIfc), 0x00, 0x02, 0x08, 0x06, 0x50, 0x00,\ + /* Endpoint descriptor (Bulk In) */\ + 0x07, 0x05, (bBulkIn), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Bulk Out) */\ + 0x07, 0x05, (bBulkOut), 0x02, 0x40, 0x00, 0x00, +#define STORAGE_IFC_DESC_ALL_LEN (9+7+7) + +#define HID_MOUSE_IFC_DESC_ALL(bIfc, bInterruptIn)\ + /* Interface descriptor */\ + 0x09, 0x04, (bIfc), 0x00, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH), MSB(HID_MOUSE_REPORT_LENGTH),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (bInterruptIn), 0x03, 0x08, 0x00, 0x08 +#define HID_MOUSE_IFC_DESC_ALL_LEN (9+9+7) + +#define HID_KEYBOARD_IFC_DESC_ALL(bIfc, bInterruptIn)\ + /* Interface descriptor */\ + 0x09, 0x04, (bIfc), 0x00, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_KEYBOARD_REPORT_LENGTH), MSB(HID_KEYBOARD_REPORT_LENGTH),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (bInterruptIn), 0x03, 0x08, 0x00, 0x08 +#define HID_KEYBOARD_IFC_DESC_ALL_LEN (9+9+7) + +typedef struct TEST_DEVICE_CLASS_INFO_STRUCT +{ + UCHAR *class_name; + UINT (*class_entry)(UX_SLAVE_CLASS_COMMAND *command); + ULONG class_interface_nb; + VOID *class_parameter; +} TEST_DEVICE_CLASS_INFO; + +typedef struct TEST_DEVICE_FRAMEWORK_INFO_STRUCT +{ + UCHAR *framework; + ULONG length; +} TEST_DEVICE_FRAMEWORK_INFO; + +typedef struct TEST_DEVICE_INFO_STRUCT +{ + UINT (*slave_change_function)(ULONG); + TEST_DEVICE_FRAMEWORK_INFO *framework_high_speed; + TEST_DEVICE_FRAMEWORK_INFO *framework_full_speed; + TEST_DEVICE_FRAMEWORK_INFO *framework_string; + TEST_DEVICE_FRAMEWORK_INFO *framework_language; + TEST_DEVICE_CLASS_INFO *classes; + ULONG nb_classes; +} TEST_DEVICE_INFO; + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_simulation_entry(ULONG); + +static VOID test_slave_instance_activate(VOID *cdc_instance); +static VOID test_slave_instance_deactivate(VOID *cdc_instance); + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +static UINT default_device_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT default_device_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT default_device_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +static UX_SLAVE_CLASS_STORAGE_PARAMETER storage_parameter; + +static UCHAR inquiry_response[UX_HOST_CLASS_STORAGE_INQUIRY_RESPONSE_LENGTH]; + +static UX_SLAVE_CLASS_STORAGE *storage_slave; + +static FX_MEDIA ram_disk; +static UCHAR ram_disk_memory[UX_RAM_DISK_SIZE]; +static UCHAR ram_disk_working_buffer[UX_TEST_MAX_SECTOR_SIZE]; + +static ULONG error_counter; + +static ULONG error_callback_counter; +static UCHAR error_callback_ignore; + +static UCHAR dcd_initialized = UX_FALSE; + +/* Define device framework. */ + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Configuration 1 descriptor 9 bytes. */ + CFG_DESC(CFG_DESC_LEN + STORAGE_IFC_DESC_ALL_LEN, 2, 1) + /* MSC BO interfaces */ + STORAGE_IFC_DESC_ALL(0, 0x81, 0x02) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor 10 bytes */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor 9 bytes. */ + CFG_DESC(CFG_DESC_LEN + STORAGE_IFC_DESC_ALL_LEN, 2, 1) + /* MSC BO interfaces */ + STORAGE_IFC_DESC_ALL(0, 0x81, 0x02) +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT break_on_storage_all_ready(VOID) +{ +UINT status; +UX_HOST_CLASS *class; + + /* Find the main cdc_acm container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + /* Do not break. */ + return 0; + + /* Find class instances. */ + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status != UX_SUCCESS) + /* Do not break. */ + return 0; + + if (storage->ux_host_class_storage_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (storage_slave == UX_NULL) + /* Do not break. */ + return 0; + + /* All found, break. */ + return 1; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + storage = UX_NULL; + + return 1; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + storage = (UX_HOST_CLASS_STORAGE *)inst; + break; + + case UX_DEVICE_REMOVAL: + storage = (UX_HOST_CLASS_STORAGE *)inst; + break; + + default: + break; + } + return 0; +} + +static VOID test_slave_instance_activate(VOID *instance) +{ + storage_slave = (UX_SLAVE_CLASS_STORAGE *)instance; +} +static VOID test_slave_instance_deactivate(VOID *instance) +{ + storage_slave = UX_NULL; +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + error_callback_counter ++; + + if (!error_callback_ignore) + { + /* Exception: DCD Sim has no transfer abort. */ + if (system_context == UX_SYSTEM_CONTEXT_DCD && error_code == UX_FUNCTION_NOT_SUPPORTED) + return; + + /* 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 test_device_stack_storage_init(VOID) +{ + +UINT status; + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory, 0, UX_RAM_DISK_SIZE); + + /* Format the ram drive. */ + status = fx_media_format(&ram_disk, _fx_ram_driver, ram_disk_memory, ram_disk_working_buffer, 512, "RAM DISK", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* Check the media format status. */ + if (status != FX_SUCCESS) + { + + printf("ERROR #%d: code: %d\n", __LINE__, status); + return status; + } + + /* Open the ram_disk. */ + status = fx_media_open(&ram_disk, "RAM DISK", _fx_ram_driver, ram_disk_memory, ram_disk_working_buffer, 512); + + /* Check the media open status. */ + if (status != FX_SUCCESS) + { + + printf("ERROR #%d: code: %d\n", __LINE__, status); + return status; + } + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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: code: %d\n", __LINE__, status); + return status; + } + + /* Initilize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&storage_parameter); + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d: code: %d\n", __LINE__, status); + return status; + } + + return UX_SUCCESS; +} + +static VOID test_device_stack_storage_uninit(VOID) +{ + + /* Unregister all class drivers. */ + ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_entry); + + /* Uninitialize stack. */ + ux_device_stack_uninitialize(); + + /* Close RAM Disk. */ + fx_media_close(&ram_disk); +} + +static UINT test_host_class_storage_inquiry(UX_HOST_CLASS_STORAGE *storage, UCHAR page_code, UCHAR *response, ULONG response_length) +{ +UINT status; +UCHAR *cbw; +UINT command_length; + + /* Use a pointer for the cbw, easier to manipulate. */ + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + /* Get the Write Command Length. */ + command_length = UX_HOST_CLASS_STORAGE_INQUIRY_COMMAND_LENGTH_SBC; + + /* Initialize the CBW for this command. */ + _ux_host_class_storage_cbw_initialize(storage, UX_HOST_CLASS_STORAGE_DATA_IN, UX_HOST_CLASS_STORAGE_INQUIRY_RESPONSE_LENGTH, command_length); + + /* Prepare the INQUIRY command block. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_INQUIRY; + + /* Store the page code. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_PAGE_CODE) = page_code; + + /* Store the length of the Inquiry Response. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_ALLOCATION_LENGTH) = (UCHAR)response_length; + + /* Send the command to transport layer. */ + status = _ux_host_class_storage_transport(storage, response); + + /* Return completion status. */ + return(status); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_storage_vendor_strings_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + printf("Running ux_device_class_storage Vendor Strings Test................. "); + + /* Initialize the FX system. */ + fx_system_initialize(); + + /* 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 #%d: code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + stepinfo(">>>>>>>>>>>>>>>> Test test_device_stack_storage_init default\n"); + + /* Reset storage parameter. */ + _ux_utility_memory_set(&storage_parameter, 0, sizeof(storage_parameter)); + + /* Store the number of LUN in this device storage instance. */ + storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + /* Initialize the storage class parameters for reading/writing to the Flash Disk. */ + storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = (UX_RAM_DISK_SIZE / 512) - 1; + storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = default_device_media_read; + storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = default_device_media_write; + storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = default_device_media_status; + + /* Initialize callbacks. */ + storage_parameter.ux_slave_class_storage_instance_activate = test_slave_instance_activate; + storage_parameter.ux_slave_class_storage_instance_deactivate = test_slave_instance_deactivate; + + status = test_device_stack_storage_init(); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* 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 #%d: code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Register Storage class */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Register HCD for test */ + 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: code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx test simulation", tx_test_thread_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +void tx_test_thread_simulation_entry(ULONG arg) +{ + +UINT status; +UX_DEVICE *device; + + + stepinfo("\n"); + + + /* Test connect. */ + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + //ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + ux_test_breakable_sleep(1000, break_on_storage_all_ready); + + if (storage == UX_NULL || storage_slave == UX_NULL) + { + + printf("ERROR #%d: connect fail\n", __LINE__); + test_control_return(1); + } + + /* Get device instance. */ + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(standard)\n"); + + status = test_host_class_storage_inquiry(storage, 0x00, inquiry_response, 36); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: inquiry(standard) error %x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(standard) Response data\n"); + + if (_ux_utility_memory_compare(inquiry_response + 8, _ux_system_slave_class_storage_vendor_id, 8) != UX_SUCCESS) + { + + printf("ERROR #%d: vendor_id error %x\n", __LINE__, status); + error_counter ++; + } + + if (_ux_utility_memory_compare(inquiry_response + 16, _ux_system_slave_class_storage_product_id, 16) != UX_SUCCESS) + { + + printf("ERROR #%d: product_id error %x\n", __LINE__, status); + error_counter ++; + } + + if (_ux_utility_memory_compare(inquiry_response + 32, _ux_system_slave_class_storage_product_rev, 4) != UX_SUCCESS) + { + + printf("ERROR #%d: vendor id error %x\n", __LINE__, status); + error_counter ++; + } + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(serial)\n"); + + status = test_host_class_storage_inquiry(storage, 0x80, inquiry_response, 24); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: inquiry(serial) error %x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(serial) Response data\n"); + + if (_ux_utility_memory_compare(inquiry_response + 4, _ux_system_slave_class_storage_product_serial, 20) != UX_SUCCESS) + { + + printf("ERROR #%d: vendor_id error %x\n", __LINE__, status); + error_counter ++; + } + + stepinfo(">>>>>>>>>>>>>>>> Test disconnect and deinitialize stack\n"); + + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + test_device_stack_storage_uninit(); + + stepinfo(">>>>>>>>>>>>>>>> Test modify parameter - vendor strings\n"); + + storage_parameter.ux_slave_class_storage_parameter_vendor_id = test_ux_system_slave_class_storage_vendor_id; + storage_parameter.ux_slave_class_storage_parameter_product_id = test_ux_system_slave_class_storage_product_id; + storage_parameter.ux_slave_class_storage_parameter_product_rev = test_ux_system_slave_class_storage_product_rev; + storage_parameter.ux_slave_class_storage_parameter_product_serial = test_ux_system_slave_class_storage_product_serial; + + stepinfo(">>>>>>>>>>>>>>>> Test test_device_stack_storage_init with new string\n"); + + status = test_device_stack_storage_init(); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: code: %d\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + ux_test_breakable_sleep(100, break_on_storage_all_ready); + if (storage == UX_NULL || storage_slave == UX_NULL) + { + + printf("ERROR #%d: connect fail\n", __LINE__); + test_control_return(1); + } + + /* Get device instance. */ + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(standard)\n"); + + status = test_host_class_storage_inquiry(storage, 0x00, inquiry_response, 36); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: inquiry(standard) error %x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(standard) Response data\n"); + + if (_ux_utility_memory_compare(inquiry_response + 8, test_ux_system_slave_class_storage_vendor_id, 8) != UX_SUCCESS) + { + + printf("ERROR #%d: vendor_id error %x\n", __LINE__, status); + error_counter ++; + } + + if (_ux_utility_memory_compare(inquiry_response + 16, test_ux_system_slave_class_storage_product_id, 16) != UX_SUCCESS) + { + + printf("ERROR #%d: product_id error %x\n", __LINE__, status); + error_counter ++; + } + + if (_ux_utility_memory_compare(inquiry_response + 32, test_ux_system_slave_class_storage_product_rev, 4) != UX_SUCCESS) + { + + printf("ERROR #%d: vendor id error %x\n", __LINE__, status); + error_counter ++; + } + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(serial)\n"); + + status = test_host_class_storage_inquiry(storage, 0x80, inquiry_response, 24); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: inquiry(serial) error %x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test INQUIRY(serial) Response data\n"); + + if (_ux_utility_memory_compare(inquiry_response + 4, test_ux_system_slave_class_storage_product_serial, 20) != UX_SUCCESS) + { + + printf("ERROR #%d: vendor_id error %x\n", __LINE__, status); + error_counter ++; + } + + stepinfo(">>>>>>>>>>>>>>>> Dump results\n"); + + if (error_counter > 0) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + + +static UINT default_device_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + + /* The ATA drive never fails. This is just for demo only !!!! */ + return(UX_SUCCESS); +} + +static UINT default_device_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + +UINT status = UX_SUCCESS; + + + if(lba == 0) + { + ram_disk.fx_media_driver_logical_sector = 0; + ram_disk.fx_media_driver_sectors = 1; + ram_disk.fx_media_driver_request = FX_DRIVER_BOOT_READ; + ram_disk.fx_media_driver_buffer = data_pointer; + _fx_ram_driver(&ram_disk); + *(data_pointer) = 0xeb; + *(data_pointer+1) = 0x3c; + *(data_pointer+2) = 0x90; + *(data_pointer+21) = 0xF8; + + *(data_pointer+24) = 0x01; + *(data_pointer+26) = 0x10; + *(data_pointer+28) = 0x01; + + *(data_pointer+510) = 0x55; + *(data_pointer+511) = 0xaa; + ux_utility_memory_copy(data_pointer+0x36,"FAT12",5); + + + status = ram_disk.fx_media_driver_status; + } + else + { + while(number_blocks--) + { + status = fx_media_read(&ram_disk,lba,data_pointer); + data_pointer+=512; + lba++; + } + } + return(status); +} + +static UINT default_device_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + +UINT status = UX_SUCCESS; + + if(lba == 0) + { + ram_disk.fx_media_driver_logical_sector = 0; + ram_disk.fx_media_driver_sectors = 1; + ram_disk.fx_media_driver_request = FX_DRIVER_BOOT_WRITE; + ram_disk.fx_media_driver_buffer = data_pointer; + _fx_ram_driver(&ram_disk); + + status = ram_disk.fx_media_driver_status; + + } + else + { + + while(number_blocks--) + { + status = fx_media_write(&ram_disk,lba,data_pointer); + data_pointer+=512; + lba++; + } + return(status); + } + return(status); +} diff --git a/test/regression/usbx_ux_device_class_storage_verify_test.c b/test/regression/usbx_ux_device_class_storage_verify_test.c new file mode 100644 index 00000000..ec687876 --- /dev/null +++ b/test/regression/usbx_ux_device_class_storage_verify_test.c @@ -0,0 +1,734 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00 + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00 + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_storage_verify_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_storage_verify Test......................... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_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(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + +static void _test_init_cbw_VERIFY(void) +{ + +UCHAR *cbw; +UINT command_length; + + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, 0, 0, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = UX_SLAVE_CLASS_STORAGE_SCSI_VERIFY; +} + +static UINT _test_send_cbw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; +UCHAR *cbw; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + transfer_request -> ux_transfer_request_data_pointer = cbw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CBW_LENGTH; + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_transfer_data(UCHAR *data, ULONG size, UCHAR do_read) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + transfer_request = do_read ? + &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request : + &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + transfer_request -> ux_transfer_request_data_pointer = data; + transfer_request -> ux_transfer_request_requested_length = size; + + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_wait_csw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + /* Get the pointer to the transfer request, on the bulk in endpoint. */ + transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + /* Fill in the transfer_request parameters. */ + transfer_request -> ux_transfer_request_data_pointer = (UCHAR *) &storage -> ux_host_class_storage_csw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CSW_LENGTH; + + /* Get the CSW on the bulk in endpoint. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + return(status); + + /* Wait for the completion of the transfer request. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* If OK, we are done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_clear_stall(UCHAR clear_read_stall) +{ + +UX_ENDPOINT *endpoint; + + + endpoint = clear_read_stall ? + storage -> ux_host_class_storage_bulk_in_endpoint : + storage -> ux_host_class_storage_bulk_out_endpoint; + _ux_host_stack_endpoint_reset(endpoint); +} + +static UINT _test_request_sense(void) +{ + +UINT status; +UX_TRANSFER *transfer_request; +UCHAR *cbw; +UCHAR *request_sense_response; +ULONG sense_code; +UINT command_length = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_COMMAND_LENGTH_SBC; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + _ux_utility_memory_copy(storage -> ux_host_class_storage_saved_cbw, storage -> ux_host_class_storage_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + _ux_host_class_storage_cbw_initialize(storage, UX_HOST_CLASS_STORAGE_DATA_IN, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_REQUEST_SENSE; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_ALLOCATION_LENGTH) = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH; + request_sense_response = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH); + if (request_sense_response == UX_NULL) + return(UX_MEMORY_INSUFFICIENT); + status = _test_send_cbw(); + if (status == UX_SUCCESS) + { + status = _test_transfer_data(request_sense_response, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, UX_TRUE); + if (status == UX_SUCCESS) + { + status = _test_wait_csw(); + if (status == UX_SUCCESS) + { + + sense_code = (((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_SENSE_KEY)) & 0x0f) << 16; + sense_code |= ((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE)) << 8; + sense_code |= (ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE_QUALIFIER); + + storage -> ux_host_class_storage_sense_code = sense_code; + } + } + } + _ux_utility_memory_free(request_sense_response); + _ux_utility_memory_copy(storage -> ux_host_class_storage_cbw, storage -> ux_host_class_storage_saved_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + return(status); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done. */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + _test_init_cbw_VERIFY(); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} diff --git a/test/regression/usbx_ux_device_class_storage_write_test.c b/test/regression/usbx_ux_device_class_storage_write_test.c new file mode 100644 index 00000000..61ea67d2 --- /dev/null +++ b/test/regression/usbx_ux_device_class_storage_write_test.c @@ -0,0 +1,1025 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static CHAR ram_disk_flush = 0; +static UINT ram_disk_flush_status = UX_SUCCESS; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + + +static UX_TEST_HCD_SIM_ACTION fail_on_bulkin[] = { +/* 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_DCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_ERROR, + UX_ERROR, UX_NULL, + UX_FALSE}, /* Invoke callback & no continue */ +{ 0 } +}; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_class_storage_write_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_class_storage_write Test.......................... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_parameter); + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + 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 #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + +static UINT test_host_class_storage_inquiry(UX_HOST_CLASS_STORAGE *storage, UCHAR page_code, UCHAR *response, ULONG response_length) +{ +UINT status; +UCHAR *cbw; +UINT command_length; + + /* Use a pointer for the cbw, easier to manipulate. */ + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + /* Get the Write Command Length. */ + command_length = UX_HOST_CLASS_STORAGE_INQUIRY_COMMAND_LENGTH_SBC; + + /* Initialize the CBW for this command. */ + _ux_host_class_storage_cbw_initialize(storage, UX_HOST_CLASS_STORAGE_DATA_IN, UX_HOST_CLASS_STORAGE_INQUIRY_RESPONSE_LENGTH, command_length); + + /* Prepare the INQUIRY command block. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_INQUIRY; + + /* Store the page code. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_PAGE_CODE) = page_code; + + /* Store the length of the Inquiry Response. */ + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_INQUIRY_ALLOCATION_LENGTH) = (UCHAR)response_length; + + /* Send the command to transport layer. */ + status = _ux_host_class_storage_transport(storage, response); + + /* Return completion status. */ + return(status); +} + +typedef struct cbw_write_struct { + UCHAR flags_pos; + UCHAR lba_pos; + UCHAR lba_size; + UCHAR len_pos; + UCHAR len_size; +} cbw_write_struct_t; +static cbw_write_struct_t cbw_WRITE_info[] = +{ + { 1, 2, 2, 4, 1}, + { 1, 2, 4, 7, 2}, + { 1, 2, 4, 6, 4}, + { 1, 2, 8, 10, 4}, + {10, 12, 8, 28, 4} +}; +static UCHAR _write_op(UCHAR op_code) +{ + switch(op_code) + { + case 0x2A: return 1; + case 0xAA: return 2; + case 0x8A: return 3; + case 0x7F: return 4; + case 0x0A: return 0; + default: return 0xFF; + } +} + +static void _test_init_cbw_WRITE_EX(UCHAR flags, ULONG data_length, + UCHAR op6_10_12_16_32, ULONG lba, ULONG len) +{ + +UCHAR *cbw; +UINT command_length; +UCHAR op = _write_op(op6_10_12_16_32); +UINT i; + + + if (op >= 5) + return; + + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + command_length = UX_HOST_CLASS_STORAGE_TEST_READY_COMMAND_LENGTH_SBC; + _ux_host_class_storage_cbw_initialize(storage, flags, data_length, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + 0) = op6_10_12_16_32; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + cbw_WRITE_info[op].flags_pos) = 0; + for (i = cbw_WRITE_info[op].lba_pos + cbw_WRITE_info[op].lba_size - 1; i >= cbw_WRITE_info[op].lba_pos; i --) + { + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + i) = (UCHAR)lba; + lba >>= 8; + } + for (i = cbw_WRITE_info[op].len_pos + cbw_WRITE_info[op].len_size - 1; i >= cbw_WRITE_info[op].len_size; i --) + { + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + i) = (UCHAR)len; + len >>= 8; + } +} + +static void _test_init_cbw_WRITE(UCHAR op6_10_12_16_32, ULONG lba, ULONG len) +{ + _test_init_cbw_WRITE_EX(0x00, len * 512, op6_10_12_16_32, lba, len); +} + +static UINT _test_send_cbw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; +UCHAR *cbw; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + transfer_request -> ux_transfer_request_data_pointer = cbw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CBW_LENGTH; + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_transfer_data(UCHAR *data, ULONG size, UCHAR do_read) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + transfer_request = do_read ? + &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request : + &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + transfer_request -> ux_transfer_request_data_pointer = data; + transfer_request -> ux_transfer_request_requested_length = size; + + status = ux_host_stack_transfer_request(transfer_request); + + /* There is error, return the error code. */ + if (status != UX_SUCCESS) + return(status); + + /* Wait transfer done. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* No error, it's done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static UINT _test_wait_csw(void) +{ + +UX_TRANSFER *transfer_request; +UINT status; + + + /* Get the pointer to the transfer request, on the bulk in endpoint. */ + transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + /* Fill in the transfer_request parameters. */ + transfer_request -> ux_transfer_request_data_pointer = (UCHAR *) &storage -> ux_host_class_storage_csw; + transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CSW_LENGTH; + + /* Get the CSW on the bulk in endpoint. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + return(status); + + /* Wait for the completion of the transfer request. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, MS_TO_TICK(UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT)); + + /* If OK, we are done. */ + if (status == UX_SUCCESS) + return(transfer_request->ux_transfer_request_completion_code); + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* There was an error, return to the caller. */ + return(UX_TRANSFER_TIMEOUT); +} + +static VOID _test_clear_stall(UCHAR clear_read_stall) +{ + +UX_ENDPOINT *endpoint; + + + endpoint = clear_read_stall ? + storage -> ux_host_class_storage_bulk_in_endpoint : + storage -> ux_host_class_storage_bulk_out_endpoint; + _ux_host_stack_endpoint_reset(endpoint); +} + +static UINT _test_request_sense(void) +{ + +UINT status; +UX_TRANSFER *transfer_request; +UCHAR *cbw; +UCHAR *request_sense_response; +ULONG sense_code; +UINT command_length = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_COMMAND_LENGTH_SBC; + + + transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + cbw = (UCHAR *) storage -> ux_host_class_storage_cbw; + + _ux_utility_memory_copy(storage -> ux_host_class_storage_saved_cbw, storage -> ux_host_class_storage_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + _ux_host_class_storage_cbw_initialize(storage, UX_HOST_CLASS_STORAGE_DATA_IN, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, command_length); + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_OPERATION) = UX_HOST_CLASS_STORAGE_SCSI_REQUEST_SENSE; + *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_ALLOCATION_LENGTH) = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH; + request_sense_response = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH); + if (request_sense_response == UX_NULL) + return(UX_MEMORY_INSUFFICIENT); + status = _test_send_cbw(); + if (status == UX_SUCCESS) + { + status = _test_transfer_data(request_sense_response, UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH, UX_TRUE); + if (status == UX_SUCCESS) + { + status = _test_wait_csw(); + if (status == UX_SUCCESS) + { + + sense_code = (((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_SENSE_KEY)) & 0x0f) << 16; + sense_code |= ((ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE)) << 8; + sense_code |= (ULONG) *(request_sense_response + UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_CODE_QUALIFIER); + + storage -> ux_host_class_storage_sense_code = sense_code; + } + } + } + _ux_utility_memory_free(request_sense_response); + _ux_utility_memory_copy(storage -> ux_host_class_storage_cbw, storage -> ux_host_class_storage_saved_cbw, UX_HOST_CLASS_STORAGE_CBW_LENGTH); + return(status); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; +UX_SLAVE_DEVICE *slave_device; +UX_SLAVE_CLASS *slave_class; +UX_SLAVE_CLASS_STORAGE *slave_storage; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done. */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16 - success\n"); + _test_init_cbw_WRITE(UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16, 0, 1); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(buffer, 512, UX_FALSE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_WRITE32 - success\n"); + _test_init_cbw_WRITE(UX_SLAVE_CLASS_STORAGE_SCSI_WRITE32, 0, 1); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(buffer, 512, UX_FALSE); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16 - status fail\n"); + ram_disk_status = UX_ERROR; + _test_init_cbw_WRITE(UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16, 0, 1); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(buffer, 512, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + ram_disk_status = UX_SUCCESS; + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16 - transfer fail\n"); + _test_init_cbw_WRITE(UX_SLAVE_CLASS_STORAGE_SCSI_READ16, 0, 1); + ux_test_dcd_sim_slave_set_actions(fail_on_bulkin); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(buffer, 512, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16 - WP fail\n"); + slave_device = &_ux_system_slave->ux_system_slave_device; + slave_class = _ux_system_slave->ux_system_slave_interface_class_array[0]; + slave_storage = (UX_SLAVE_CLASS_STORAGE *)slave_class->ux_slave_class_instance; + slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_read_only_flag = UX_TRUE; + _test_init_cbw_WRITE(UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16, 0, 1); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(buffer, 512, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_read_only_flag = UX_FALSE; + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16 - Case (3) Hn < Do\n"); + _test_init_cbw_WRITE_EX(0x00, 0, UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16, 0, 1); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(buffer, 512, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16 - Case (8) Hi <> Do\n"); + _test_init_cbw_WRITE_EX(0x80, 512, UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16, 0, 1); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(buffer, 512, UX_TRUE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_TRUE); + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + stepinfo(">>>>>>>>>>>>>>> UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16 - Case (9) Ho > Do\n"); + _test_init_cbw_WRITE_EX(0x00, 1024, UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16, 0, 1); + status = _test_send_cbw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_transfer_data(buffer, 1024, UX_FALSE); + if (status != UX_TRANSFER_STALLED) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _test_clear_stall(UX_FALSE); + status = _test_wait_csw(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_host_class_storage_device_reset(storage); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)number_blocks; + (void)lba; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ram_disk_flush = UX_TRUE; + return ram_disk_flush_status; +} \ No newline at end of file diff --git a/test/regression/usbx_ux_device_class_video_basic_tests.c b/test/regression/usbx_ux_device_class_video_basic_tests.c new file mode 100644 index 00000000..6ee0ffe6 --- /dev/null +++ b/test/regression/usbx_ux_device_class_video_basic_tests.c @@ -0,0 +1,1178 @@ +/* This test is designed to test the simple video host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" + +#include "fx_api.h" + +#include "ux_device_class_video.h" +#include "ux_device_stack.h" + +#include "ux_host_class_video.h" +#include "ux_host_class_dummy.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_DEMO_REQUEST_MAX_LENGTH \ + ((UX_HCD_SIM_HOST_MAX_PAYLOAD) > (UX_SLAVE_REQUEST_DATA_MAX_LENGTH) ? \ + (UX_HCD_SIM_HOST_MAX_PAYLOAD) : (UX_SLAVE_REQUEST_DATA_MAX_LENGTH)) + +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_DEMO_REQUEST_MAX_LENGTH + 1) +#define UX_DEMO_MEMORY_SIZE (128*1024) +#define UX_DEMO_ENDPOINT_SIZE 480 + +#define UX_TEST_LOG_SIZE (64) + + +/* Define local/extern function prototypes. */ +static void test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static void tx_test_thread_host_simulation_entry(ULONG); +static void tx_test_thread_slave_simulation_entry(ULONG); + + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +static UX_HOST_CLASS_DUMMY *dummy_control; +static UX_HOST_CLASS_DUMMY *dummy_tx; +static UX_HOST_CLASS_DUMMY *dummy_rx; + +static UX_DEVICE_CLASS_VIDEO *device_video; +static UX_DEVICE_CLASS_VIDEO_STREAM *device_video_tx_stream; +static UX_DEVICE_CLASS_VIDEO_STREAM *device_video_rx_stream; +static UX_DEVICE_CLASS_VIDEO_PARAMETER device_video_parameter; +static UX_DEVICE_CLASS_VIDEO_STREAM_PARAMETER device_video_stream_parameter[2]; + +static UX_SLAVE_TRANSFER *device_video_tx_transfer; +static UX_SLAVE_TRANSFER *device_video_rx_transfer; + +static UX_HOST_CLASS_VIDEO *video; + +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_video_sem_usage; +static ULONG rsc_video_sem_get_count; +static ULONG rsc_video_mutex_usage; +static ULONG rsc_video_mem_usage; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +static struct BUFFER_LOG_STRUCT { + ULONG length; + UCHAR data[256]; +} buffer_log[UX_TEST_LOG_SIZE]; +static ULONG buffer_log_count = 0; +#define SAVE_BUFFER_LOG(buf,siz) do { \ + if (buffer_log_count < UX_TEST_LOG_SIZE) { \ + ULONG __local_size__ = ((siz) > 256) ? 256 : (siz); \ + buffer_log[buffer_log_count].length = (siz); \ + _ux_utility_memory_copy(buffer_log[buffer_log_count].data, (buf), __local_size__); \ + } \ + buffer_log_count ++; \ +} while(0) + +static ULONG test_tx_ack_count = 0xFFFFFFFF; +static ULONG test_tx_ins_count = 0; +static ULONG test_tx_ins_way = 0; + +static struct CALLBACK_INVOKE_LOG_STRUCT { + VOID *func; + VOID *param1; + VOID *param2; + VOID *param3; +} callback_invoke_log[UX_TEST_LOG_SIZE]; +static ULONG callback_invoke_count = 0; + +#define SAVE_CALLBACK_INVOKE_LOG(f,p1,p2,p3) do { \ + if (callback_invoke_count < UX_TEST_LOG_SIZE) { \ + callback_invoke_log[callback_invoke_count].func = (VOID *)(f); \ + callback_invoke_log[callback_invoke_count].param1 = (VOID *)(p1); \ + callback_invoke_log[callback_invoke_count].param2 = (VOID *)(p2); \ + callback_invoke_log[callback_invoke_count].param3 = (VOID *)(p3); \ + callback_invoke_count++; \ + } \ +} while(0) +#define RESET_CALLBACK_INVOKE_LOG() do { \ + callback_invoke_count = 0; \ +} while(0) + +/* Define device framework. */ + +#define W(d) UX_DW0(d), UX_DW1(d) +#define DW(d) UX_DW0(d), UX_DW1(d), UX_DW2(d), UX_DW3(d) + +#define _DEVICE_DESCRIPTOR() \ +/* --------------------------------------- Device Descriptor */ \ +/* 0 bLength, bDescriptorType */ 18, 0x01, \ +/* 2 bcdUSB */ UX_DW0(0x200),UX_DW1(0x200), \ +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, \ +/* 7 bMaxPacketSize0 */ 0x08, \ +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x01, 0x00, \ +/* 12 bcdDevice */ UX_DW0(0x100),UX_DW1(0x100), \ +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, \ +/* 17 bNumConfigurations */ 1, + +#define _DEVICE_QUALIFIER_DESCRIPTOR() \ +/* ----------------------------- Device Qualifier Descriptor */ \ +/* 0 bLength, bDescriptorType */ 10, 0x06, \ +/* 2 bcdUSB */ UX_DW0(0x200),UX_DW1(0x200), \ +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, \ +/* 7 bMaxPacketSize0 */ 8, \ +/* 8 bNumConfigurations */ 1, \ +/* 9 bReserved */ 0, + +#define _CONFIGURE_DESCRIPTOR(total_len,n_ifc,cfg_v) \ +/* -------------------------------- Configuration Descriptor */ \ +/* 0 bLength, bDescriptorType */ 9, 0x02, \ +/* 2 wTotalLength */ UX_DW0(total_len),UX_DW1(total_len),\ +/* 4 bNumInterfaces, bConfigurationValue */ (n_ifc), (cfg_v), \ +/* 6 iConfiguration */ 0, \ +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +#define _IAD_DESCRIPTOR(ifc_0,ifc_cnt,cls,sub,protocol) \ +/* ------------------------ Interface Association Descriptor */ \ +/* 0 bLength, bDescriptorType */ 8, 0x0B, \ +/* 2 bFirstInterface, bInterfaceCount */ (ifc_0), (ifc_cnt), \ +/* 4 bFunctionClass, bFunctionSubClass, bFunctionProtocol */ (cls), (sub), (protocol), \ +/* 7 iFunction */ 0, + +#define _INTERFACE_DESCRIPTOR(ifc,alt,n_ep,cls,sub,protocol) \ +/* ------------------------------------ Interface Descriptor */ \ +/* 0 bLength, bDescriptorType */ 9, 0x04, \ +/* 2 bInterfaceNumber, bAlternateSetting */ (ifc), (alt), \ +/* 4 bNumEndpoints */ (n_ep), \ +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ (cls), (sub), (protocol), \ +/* 8 iInterface */ 0, + +#define _ENDPOINT_DESCRIPTOR(addr,attr,pkt_siz,interval) \ +/* ------------------------------------- Endpoint Descriptor */ \ +/* 0 bLength, bDescriptorType */ 7, 0x05, \ +/* 2 bEndpointAddress, bmAttributes */ (addr), (attr), \ +/* 4 wMaxPacketSize, bInterval */ UX_DW0(pkt_siz),UX_DW1(pkt_siz),(interval), + +#define _VC_DESCRIPTORS_LEN (14+17+9+17+9) +#define _VC_DESCRIPTORS() \ + /*--------------------------- Class VC Interface Descriptor (VC_HEADER). */ \ + 14, 0x24, 0x01, W(0x150), \ + W(_VC_DESCRIPTORS_LEN), /* wTotalLength. */ \ + DW(6000000), /* dwClockFrequency. */ \ + 2, /* bInCollection. */ \ + 1, 2, /* BaInterfaceNr(2). */ \ + /*--------------------------- Input Terminal (VC_INPUT_TERMINAL, Camera) */ \ + 17, 0x24, 0x02, \ + 0x01, /* bTerminalID, ITT_CAMERA */ \ + W(0x201), /* wTerminalType */ \ + 0x00, 0x00, W(0), W(0), W(0), \ + 0x02, W(0), /* bControlSize, bmControls */ \ + /*---------------------------- Output Terminal (VC_OUTPUT_TERMINAL, USB) */ \ + 9, 0x24, 0x03, \ + 0x02, /* bTerminalID */ \ + W(0x0101), /* wTerminalType, TT_STREAMING */ \ + 0x00, 0x01/* bSourceID */, 0x00, \ + /*--------------------------- Input Terminal (VC_INPUT_TERMINAL, USB) */ \ + 17, 0x24, 0x02, \ + 0x03, /* bTerminalID */ \ + W(0x101), /* wTerminalType, TT_STREAMING */ \ + 0x00, 0x00, W(0), W(0), W(0), \ + 0x02, W(0), /* bControlSize, bmControls */ \ + /*---------------------------- Output Terminal (VC_OUTPUT_TERMINAL, DISPLAY) */ \ + 9, 0x24, 0x03, \ + 0x04, /* bTerminalID */ \ + W(0x0301), /* wTerminalType, OTT_DISPLAY */ \ + 0x00, 0x03/* bSourceID */, 0x00, + +#if 0 + /*--------------------------------- Processing Unit (VC_PROCESSING_UNIT) */ \ + 12, 0x24, 0x05, \ + , /* bUnitID */ \ + , /* bSourceID */ \ + W(0), \ + 3 /* bControlSize */, 0, 0, 0 /*bmControls */, \ + 0x00, 0x00, \ + /*--------------------------------- Processing Unit (VC_PROCESSING_UNIT) */ \ + 12, 0x24, 0x05, \ + , /* bUnitID */ \ + , /* bSourceID */ \ + W(0), \ + 3 /* bControlSize */, 0, 0, 0 /*bmControls */, \ + 0x00, 0x00, \ + +#endif + +#define _VS_IN_DESCRIPTORS_LEN (14+11+38) +#define _VS_IN_DESCRIPTORS() \ + /*------------------------- Class VS Header Descriptor (VS_INPUT_HEADER) */ \ + 14, 0x24, 0x01, \ + 0X01, /* bNumFormats */ \ + W(_VS_IN_DESCRIPTORS_LEN), /* wTotalLength */ \ + 0x81, /* bEndpointAddress */ \ + 0x00, \ + 0x02, /* bTerminalLink */ \ + 0x00, /* bStillCaptureMethod */ \ + 0x00, 0x00, /* bTriggerSupport, bTriggerUsage */ \ + 0x01, 0x00, /* bControlSize, bmaControls */ \ + /*------------------------------- VS Format Descriptor (VS_FORMAT_MJPEG) */ \ + 11, 0x24, 0x06, \ + 0x01, /* bFormatIndex */ \ + 0x01, /* bNumFrameDescriptors */ \ + 0x01, /* bmFlags */ \ + 0x01, /* bDefaultFrameIndex */ \ + 0x00, 0x00, 0x00, 0x00, \ + /*--------------------------------- VS Frame Descriptor (VS_FRAME_MJPEG) */ \ + 38, 0x24, 0x07, \ + 0x01, /* bFrameIndex */ \ + 0x03, /* bmCapabilities */ \ + W(176), W(144), /* wWidth, wHeight */ \ + DW(912384), DW(912384), /* dwMinBitRate, dwMaxBitRate */ \ + DW(38016), /* dwMaxVideoFrameBufSize */ \ + DW(666666), /* dwDefaultFrameInterval */ \ + 0x00, /* bFrameIntervalType */ \ + DW(666666), DW(666666), DW(0), /* dwMinFrameInterval, dwMaxFrameInterval, dwFrameIntervalStep */ + +#define _VS_OUT_DESCRIPTORS_LEN (11+11+38) +#define _VS_OUT_DESCRIPTORS() \ + /*------------------------- Class VS Header Descriptor (VS_OUTPUT_HEADER) */ \ + 11, 0x24, 0x02, \ + 0x01, /* bNumFormats */ \ + W(_VS_OUT_DESCRIPTORS_LEN), /* wTotalLength */ \ + 0x02, /* bEndpointAddress */ \ + 0x00, \ + 0x03, /* bTerminalLink */ \ + 0x01, 0x00, /* bControlSize, bmaControls */ \ + /*------------------------------- VS Format Descriptor (VS_FORMAT_MJPEG) */ \ + 11, 0x24, 0x06, \ + 0x01, /* bFormatIndex */ \ + 0x01, /* bNumFrameDescriptors */ \ + 0x01, /* bmFlags */ \ + 0x01, /* bDefaultFrameIndex */ \ + 0x00, 0x00, 0x00, 0x00, \ + /*--------------------------------- VS Frame Descriptor (VS_FRAME_MJPEG) */ \ + 38, 0x24, 0x07, \ + 0x01, /* bFrameIndex */ \ + 0x03, /* bmCapabilities */ \ + W(176), W(144), /* wWidth, wHeight */ \ + DW(912384), DW(912384), /* dwMinBitRate, dwMaxBitRate */ \ + DW(38016), /* dwMaxVideoFrameBufSize */ \ + DW(666666), /* dwDefaultFrameInterval */ \ + 0x00, /* bFrameIntervalType */ \ + DW(666666), DW(666666), DW(0), /* dwMinFrameInterval, dwMaxFrameInterval, dwFrameIntervalStep */ + + +#define _CONFIGURE_DESCRIPTORS_LEN (9+ 8+ 9+_VC_DESCRIPTORS_LEN+ 9+_VS_IN_DESCRIPTORS_LEN+9+7+ 9+_VS_OUT_DESCRIPTORS_LEN+9+7) + +static unsigned char device_framework_full_speed[] = { + _DEVICE_DESCRIPTOR() + _CONFIGURE_DESCRIPTOR(_CONFIGURE_DESCRIPTORS_LEN,3,1) + _IAD_DESCRIPTOR(0,3,0x0E,0x03,0x00) + + _INTERFACE_DESCRIPTOR(0,0,0,0x0E,0x01,0x01) + _VC_DESCRIPTORS() + + _INTERFACE_DESCRIPTOR(1,0,0,0x0E,0x02,0x00) + _VS_IN_DESCRIPTORS() + _INTERFACE_DESCRIPTOR(1,1,1,0x0E,0x02,0x00) + _ENDPOINT_DESCRIPTOR(0x81,0x05,UX_DEMO_ENDPOINT_SIZE,0x01) + + _INTERFACE_DESCRIPTOR(2,0,0,0x0E,0x02,0x00) + _VS_OUT_DESCRIPTORS() + _INTERFACE_DESCRIPTOR(2,1,1,0x0E,0x02,0x00) + _ENDPOINT_DESCRIPTOR(0x02,0x05,UX_DEMO_ENDPOINT_SIZE,0x01) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { + _DEVICE_DESCRIPTOR() + _DEVICE_QUALIFIER_DESCRIPTOR() + _CONFIGURE_DESCRIPTOR(_CONFIGURE_DESCRIPTORS_LEN,3,1) + _IAD_DESCRIPTOR(0,3,0x0E,0x03,0x00) + + _INTERFACE_DESCRIPTOR(0,0,0,0x0E,0x01,0x01) + _VC_DESCRIPTORS() + + _INTERFACE_DESCRIPTOR(1,0,0,0x0E,0x02,0x00) + _VS_IN_DESCRIPTORS() + _INTERFACE_DESCRIPTOR(1,1,1,0x0E,0x02,0x00) + _ENDPOINT_DESCRIPTOR(0x81,0x05,UX_DEMO_ENDPOINT_SIZE,0x01) + + _INTERFACE_DESCRIPTOR(2,0,0,0x0E,0x02,0x00) + _VS_OUT_DESCRIPTORS() + _INTERFACE_DESCRIPTOR(2,1,1,0x0E,0x02,0x00) + _ENDPOINT_DESCRIPTOR(0x02,0x05,UX_DEMO_ENDPOINT_SIZE,0x01) +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + +/* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + +/* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + +/* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Setup requests */ + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; +static UX_TEST_SETUP _GetCfgDescr = UX_TEST_SETUP_GetCfgDescr; +static UX_TEST_SETUP _SetAddress = UX_TEST_SETUP_SetAddress; +static UX_TEST_SETUP _GetDeviceDescriptor = UX_TEST_SETUP_GetDevDescr; +static UX_TEST_SETUP _GetConfigDescriptor = UX_TEST_SETUP_GetCfgDescr; + +/* Interaction define */ + +#ifndef ux_device_class_video_payload_write +static UINT ux_device_class_video_payload_write(UX_DEVICE_CLASS_VIDEO_STREAM *stream, UCHAR *payload, ULONG length) +{ + +UX_SLAVE_ENDPOINT *endpoint; +UX_SLAVE_DEVICE *device; +UCHAR *next_payload_buffer; +ULONG payload_buffer_size; + + + /* Get the pointer to the device. */ + device = &_ux_system_slave -> ux_system_slave_device; + + /* As long as the device is in the CONFIGURED state. */ + if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED) + { + + /* Cannot proceed with command, the interface is down. */ + return(UX_CONFIGURATION_HANDLE_UNKNOWN); + } + + /* Check if endpoint is available. */ + endpoint = stream -> ux_device_class_video_stream_endpoint; + if (endpoint == UX_NULL) + return(UX_ERROR); + + /* Check if endpoint direction is OK (IN). */ + if ((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) == UX_ENDPOINT_OUT) + return(UX_ERROR); + + /* Check payload length. */ + payload_buffer_size = stream -> ux_device_class_video_stream_payload_buffer_size; + if ((payload_buffer_size - 4) < length) + return(UX_ERROR); + + /* Check overflow!! */ + if (stream -> ux_device_class_video_stream_access_pos == stream -> ux_device_class_video_stream_transfer_pos && + stream -> ux_device_class_video_stream_access_pos -> ux_device_class_video_payload_length != 0) + return(UX_BUFFER_OVERFLOW); + + /* Calculate next payload buffer. */ + next_payload_buffer = (UCHAR *)stream -> ux_device_class_video_stream_access_pos; + next_payload_buffer += payload_buffer_size; + if (next_payload_buffer >= stream -> ux_device_class_video_stream_buffer + stream -> ux_device_class_video_stream_buffer_size) + next_payload_buffer = stream -> ux_device_class_video_stream_buffer; + + /* Copy payload. */ + _ux_utility_memory_copy(stream -> ux_device_class_video_stream_access_pos -> ux_device_class_video_payload_data, payload, length); /* Use case of memcpy is verified. */ + stream -> ux_device_class_video_stream_access_pos -> ux_device_class_video_payload_length = length; + + /* Move payload position. */ + stream -> ux_device_class_video_stream_access_pos = (UX_DEVICE_CLASS_VIDEO_PAYLOAD *)next_payload_buffer; + + return(UX_SUCCESS); +} +#endif + +/* Hooks define */ + +static VOID ux_device_class_video_tx_hook(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *p = (UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *)params; +UX_SLAVE_TRANSFER *transfer = (UX_SLAVE_TRANSFER *)p -> parameter; +UCHAR tmp[32] = {'i','n','s','e','r','t','A',0}; + + + (void)params; + // printf("%s:%d tTX\n", UX_TEST_FILE, __LINE__); + + /* Acknowledge payload sent. */ + if (test_tx_ack_count) + { + SAVE_BUFFER_LOG(transfer -> ux_slave_transfer_request_data_pointer, transfer -> ux_slave_transfer_request_requested_length); + transfer -> ux_slave_transfer_request_actual_length = transfer -> ux_slave_transfer_request_requested_length; + transfer -> ux_slave_transfer_request_completion_code = UX_SUCCESS; + ux_test_dcd_sim_slave_transfer_done(transfer, UX_SUCCESS); + } + if (test_tx_ack_count != 0xFFFFFFFF && test_tx_ack_count > 0) + test_tx_ack_count --; + + /* Insert payloads when sent. */ + if (test_tx_ins_count) + { + tmp[6] = (test_tx_ins_count % 26) + 'A'; + if (test_tx_ins_way == 0) + ux_device_class_video_payload_write(device_video_tx_stream, tmp, 32); + else + { + + UCHAR *payload; + ULONG payload_length; + + + ux_device_class_video_write_payload_get(device_video_tx_stream, &payload, &payload_length); + _ux_utility_memory_copy(payload, tmp, 32); + ux_device_class_video_write_payload_commit(device_video_tx_stream, 32); + } + } + if (test_tx_ins_count != 0xFFFFFFFF && test_tx_ins_count > 0) + test_tx_ins_count --; +} + +static VOID ux_device_class_video_rx_hook(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *p = (UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS *)params; +UX_SLAVE_TRANSFER *transfer = (UX_SLAVE_TRANSFER *)p -> parameter; + + + (void)action; + (void)params; + (void)p; + (void)transfer; + // printf("tRX\n"); + device_video_rx_transfer = transfer; +} +static VOID device_video_rx_simulate_one_payload(UCHAR *payload, ULONG payload_length) +{ + UX_TEST_ASSERT(device_video_rx_transfer); + if (payload_length) + { + _ux_utility_memory_copy(device_video_rx_transfer->ux_slave_transfer_request_data_pointer, payload, payload_length); + device_video_rx_transfer->ux_slave_transfer_request_actual_length = payload_length; + device_video_rx_transfer->ux_slave_transfer_request_completion_code = UX_SUCCESS; + } + ux_test_dcd_sim_slave_transfer_done(device_video_rx_transfer, UX_SUCCESS); + _ux_utility_thread_sleep(1); +} + +static UX_TEST_ACTION ux_device_class_video_transfer_hook[] = +{ + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .action_func = ux_device_class_video_tx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x81, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, + { + .usbx_function = UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + .function = UX_DCD_TRANSFER_REQUEST, + .action_func = ux_device_class_video_rx_hook, + .req_setup = UX_NULL, + .req_action = UX_TEST_MATCH_EP, + .req_ep_address = 0x02, + .do_after = UX_FALSE, + .no_return = UX_FALSE, + }, +{ 0 }, +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* 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 ++; + // printf("Error #%d, system_level: %d, system_context: %d, error_code: 0x%x\n", __LINE__, system_level, system_context, error_code); + + if (!error_callback_ignore) + { + { + /* Failed test. */ + 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 VOID device_video_activate(VOID *video_instance) +{ + device_video = (UX_DEVICE_CLASS_VIDEO *)video_instance; + ux_device_class_video_stream_get(device_video, 0, &device_video_tx_stream); + ux_device_class_video_stream_get(device_video, 1, &device_video_rx_stream); + // printf("sVID:%p,%p,%p\n", video_instance, device_video_tx_stream, device_video_rx_stream); +} +static VOID device_video_deactivate(VOID *video_instance) +{ + if ((VOID *)device_video == video_instance) + { + device_video = UX_NULL; + device_video_tx_stream = UX_NULL; + device_video_rx_stream = UX_NULL; + } +} +static VOID device_video_tx_stream_change(UX_DEVICE_CLASS_VIDEO_STREAM *video, ULONG alt) +{ + SAVE_CALLBACK_INVOKE_LOG(device_video_tx_stream_change, video, (ALIGN_TYPE)alt, 0); +} +static VOID device_video_rx_stream_change(UX_DEVICE_CLASS_VIDEO_STREAM *video, ULONG alt) +{ + SAVE_CALLBACK_INVOKE_LOG(device_video_rx_stream_change, video, (ALIGN_TYPE)alt, 0); + + device_video_rx_transfer = UX_NULL; +} +static UINT device_video_vc_control_process(UX_DEVICE_CLASS_VIDEO *video, UX_SLAVE_TRANSFER *transfer) +{ + SAVE_CALLBACK_INVOKE_LOG(device_video_vc_control_process, video, transfer, 0); + return(UX_ERROR); +} +static UINT device_video_vs_control_process(UX_DEVICE_CLASS_VIDEO_STREAM *video, UX_SLAVE_TRANSFER *transfer) +{ + SAVE_CALLBACK_INVOKE_LOG(device_video_vs_control_process, video, transfer, 0); + return(UX_ERROR); +} +static VOID device_video_tx_done(UX_DEVICE_CLASS_VIDEO_STREAM *video, ULONG length) +{ + SAVE_CALLBACK_INVOKE_LOG(device_video_tx_done, video, (ALIGN_TYPE)length, 0); +} +static VOID device_video_rx_done(UX_DEVICE_CLASS_VIDEO_STREAM *video, ULONG length) +{ + SAVE_CALLBACK_INVOKE_LOG(device_video_rx_done, video, (ALIGN_TYPE)length, 0); +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_DUMMY *dummy = (UX_HOST_CLASS_DUMMY *) inst; + + + switch(event) + { + + case UX_DEVICE_INSERTION: + + // printf("hINS:%p,%p:%ld\n", cls, inst, dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber); + switch(dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber) + { + case 0: dummy_control = dummy; break; + case 1: dummy_rx = dummy; break; + case 2: dummy_tx = dummy; break; + } + break; + + case UX_DEVICE_REMOVAL: + + // printf("hRMV:%p,%p:%ld\n", cls, inst, dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber); + switch(dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber) + { + case 0: dummy_control = UX_NULL; break; + case 1: dummy_rx = UX_NULL; break; + case 2: dummy_tx = UX_NULL; break; + } + break; + + default: + break; + } + return 0; +} + + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_video_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running Video Device Basic Functionality Test....................... "); + +#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! + printf("SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + + stepinfo("\n"); + + /* 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(); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* 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_host_change_function); + UX_TEST_CHECK_SUCCESS(status); + + /* Register Audio class. */ + status = ux_host_stack_class_register(_ux_host_class_dummy_name, _ux_host_class_dummy_entry); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Set the parameters for callback when insertion/extraction of a Video device, with IAD. */ +#if defined(UX_DEVICE_STANDALONE) + device_video_stream_parameter[0].ux_device_class_video_stream_parameter_task_function = ux_device_class_video_write_task_function; +#else + device_video_stream_parameter[0].ux_device_class_video_stream_parameter_thread_entry = ux_device_class_video_write_thread_entry; +#endif + device_video_stream_parameter[0].ux_device_class_video_stream_parameter_callbacks.ux_device_class_video_stream_change = device_video_tx_stream_change; + device_video_stream_parameter[0].ux_device_class_video_stream_parameter_callbacks.ux_device_class_video_stream_payload_done = device_video_tx_done; + device_video_stream_parameter[0].ux_device_class_video_stream_parameter_callbacks.ux_device_class_video_stream_request = device_video_vs_control_process; + device_video_stream_parameter[0].ux_device_class_video_stream_parameter_max_payload_buffer_size = UX_DEMO_ENDPOINT_SIZE; + device_video_stream_parameter[0].ux_device_class_video_stream_parameter_max_payload_buffer_nb = 8; +#if defined(UX_DEVICE_STANDALONE) + device_video_stream_parameter[1].ux_device_class_video_stream_parameter_task_function = ux_device_class_video_read_task_function; +#else + device_video_stream_parameter[1].ux_device_class_video_stream_parameter_thread_entry = ux_device_class_video_read_thread_entry; +#endif + device_video_stream_parameter[1].ux_device_class_video_stream_parameter_callbacks.ux_device_class_video_stream_change = device_video_rx_stream_change; + device_video_stream_parameter[1].ux_device_class_video_stream_parameter_callbacks.ux_device_class_video_stream_payload_done = device_video_rx_done; + device_video_stream_parameter[1].ux_device_class_video_stream_parameter_callbacks.ux_device_class_video_stream_request = device_video_vs_control_process; + device_video_stream_parameter[1].ux_device_class_video_stream_parameter_max_payload_buffer_size = UX_DEMO_ENDPOINT_SIZE; + device_video_stream_parameter[1].ux_device_class_video_stream_parameter_max_payload_buffer_nb = 8; + device_video_parameter.ux_device_class_video_parameter_streams = device_video_stream_parameter; + device_video_parameter.ux_device_class_video_parameter_streams_nb = 2; + device_video_parameter.ux_device_class_video_parameter_callbacks.ux_slave_class_video_instance_activate = device_video_activate; + device_video_parameter.ux_device_class_video_parameter_callbacks.ux_slave_class_video_instance_deactivate = device_video_deactivate; + device_video_parameter.ux_device_class_video_parameter_callbacks.ux_device_class_video_request = device_video_vc_control_process; + device_video_parameter.ux_device_class_video_parameter_callbacks.ux_device_class_video_arg = UX_NULL; + +#if 0 + printf("Memory requirement UX_DEVICE_CLASS_:\n"); + printf(" per _VIDEO: %d bytes\n", sizeof(UX_DEVICE_CLASS_VIDEO)); + printf(" per _VIDEO_STREAM: %d bytes\n", sizeof(UX_DEVICE_CLASS_VIDEO_STREAM)); + printf(" per _VIDEO_CONTROL: %d bytes\n", sizeof(UX_DEVICE_CLASS_VIDEO_CONTROL)); + printf("Dynamic memory allocation:\n"); + temp = (device_video_tx_stream_parameter.ux_device_class_video_stream_parameter_max_payload_buffer_size+8) * + device_video_tx_stream_parameter.ux_device_class_video_stream_parameter_max_payload_buffer_nb; + printf(" per _payload_buffer_size: (%ld + 8) * %ld = %ld\n", + device_video_tx_stream_parameter.ux_device_class_video_stream_parameter_max_payload_buffer_size, + device_video_tx_stream_parameter.ux_device_class_video_stream_parameter_max_payload_buffer_nb, + temp); + temp += sizeof(UX_DEVICE_CLASS_VIDEO_STREAM); + printf(" per _stream: _VIDEO_STREAM + _payload_buffer_size = %ld\n", temp); + temp += sizeof(UX_DEVICE_CLASS_VIDEO); + temp *= 2; + printf(" per _video: (_VIDEO + _stream * 1 + _CONTROL * 0) * 2 = %ld\n", temp); +#endif + + /* Initialize the device Audio class. This class owns interfaces starting with 1, 2. */ + status = ux_device_stack_class_register(_ux_system_device_class_video_name, ux_device_class_video_entry, + 1, 0, &device_video_parameter); + UX_TEST_CHECK_SUCCESS(status); + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + UX_TEST_CHECK_SUCCESS(status); + + /* 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); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx demo host simulation", tx_test_thread_host_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_CHECK_SUCCESS(status); + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx demo slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + UX_TEST_CHECK_SUCCESS(status); +} + +static UINT test_wait_until_expected(VOID **ptr, ULONG loop, VOID *expected) +{ + while(loop) + { + _ux_utility_delay_ms(10); + if (*ptr == expected) + return UX_SUCCESS; + } + return UX_ERROR; +} +static UINT test_wait_until_not_expected(VOID **ptr, ULONG loop, VOID *expected) +{ + while(loop) + { + _ux_utility_delay_ms(10); + if (*ptr != expected) + return UX_SUCCESS; + } + return UX_ERROR; +} +#define test_wait_until_not_null(ptr, loop) test_wait_until_not_expected(ptr, loop, UX_NULL) +#define test_wait_until_null(ptr, loop) test_wait_until_expected(ptr, loop, UX_NULL) + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +// ULONG mem_free; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +UX_INTERFACE *interface_inst[3][2]; +// UX_ENDPOINT *control_endpoint; +// UX_TRANSFER *transfer_request; +UCHAR test_cmp[32]; +ULONG temp; +UCHAR *temp_buf; + + + /* Test connect. */ + status = test_wait_until_not_null((void**)&dummy_control, 100); + status |= test_wait_until_not_null((void**)&dummy_tx, 100); + status |= test_wait_until_not_null((void**)&dummy_rx, 100); + status |= test_wait_until_not_null((void**)&device_video, 100); + status |= test_wait_until_not_null((void**)&device_video_rx_stream, 100); + status |= test_wait_until_not_null((void**)&device_video_tx_stream, 100); + UX_TEST_CHECK_SUCCESS(status); + + // /* Test disconnect. */ + // ux_test_dcd_sim_slave_disconnect(); + // ux_test_hcd_sim_host_disconnect(); + + // /* Reset testing counts. */ + // ux_test_utility_sim_mutex_create_count_reset(); + // ux_test_utility_sim_sem_create_count_reset(); + // ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + // /* Save free memory usage. */ + // mem_free = _ux_system->ux_system_regular_memory_pool_free; + // ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + // ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + // tx_thread_sleep(100); + // /* Log create counts for further tests. */ + // rsc_enum_mutex_usage = rsc_mutex_on_set_cfg; + // rsc_enum_sem_usage = rsc_sem_on_set_cfg; + // rsc_enum_mem_usage = mem_free - rsc_mem_free_on_set_cfg; + // /* Log create counts when instances active for further tests. */ + // rsc_cdc_mutex_usage = ux_test_utility_sim_mutex_create_count() - rsc_enum_mutex_usage; + // rsc_cdc_sem_usage = ux_test_utility_sim_sem_create_count() - rsc_enum_sem_usage; + // rsc_cdc_mem_usage = rsc_mem_free_on_set_cfg - _ux_system->ux_system_regular_memory_pool_free; + // stepinfo("mem free: %ld\n", _ux_system->ux_system_regular_memory_pool_free); + + /* Validate configuration descriptors. */ + /* ... */ + + /* Get testing instances. */ + + status = ux_host_stack_device_get(0, &device); + UX_TEST_CHECK_SUCCESS(status); + + // control_endpoint = &device->ux_device_control_endpoint; + // transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + status = ux_host_stack_device_configuration_get(device, 0, &configuration); + UX_TEST_CHECK_SUCCESS(status); + + interface = configuration -> ux_configuration_first_interface; + while(interface) + { + // printf("Interface: %ld.%ld\n", interface -> ux_interface_descriptor.bInterfaceNumber, interface -> ux_interface_descriptor.bAlternateSetting); + interface_inst[interface -> ux_interface_descriptor.bInterfaceNumber][interface -> ux_interface_descriptor.bAlternateSetting] = interface; + interface = interface -> ux_interface_next_interface; + } + + /* Test interface change. */ + /* Reset log. */ + RESET_CALLBACK_INVOKE_LOG(); + status = ux_host_stack_interface_setting_select(interface_inst[1][1]); + status |= ux_host_stack_interface_setting_select(interface_inst[1][0]); + status |= ux_host_stack_interface_setting_select(interface_inst[1][1]); + + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(callback_invoke_count == 3); + UX_TEST_ASSERT(callback_invoke_log[0].func == device_video_tx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == device_video_tx_stream); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (VOID*)1); + UX_TEST_ASSERT(callback_invoke_log[1].func == device_video_tx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == device_video_tx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].param2 == 0); + + RESET_CALLBACK_INVOKE_LOG(); + status = ux_host_stack_interface_setting_select(interface_inst[2][1]); + status |= ux_host_stack_interface_setting_select(interface_inst[2][0]); + status |= ux_host_stack_interface_setting_select(interface_inst[2][1]); + + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(callback_invoke_count == 3); + UX_TEST_ASSERT(callback_invoke_log[0].func == device_video_rx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == device_video_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[0].param2 == (VOID*)1); + UX_TEST_ASSERT(callback_invoke_log[1].func == device_video_rx_stream_change); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == device_video_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].param2 == 0); + + /* Test data streaming. */ + + /* Wrong interface! */ + status = ux_device_class_video_transmission_start(device_video_rx_stream); + status |= ux_device_class_video_reception_start(device_video_tx_stream); + UX_TEST_CHECK_NOT_SUCCESS(status); + + ux_test_link_hooks_from_array(ux_device_class_video_transfer_hook); + + /* ------------------ Write test. */ + + status = ux_device_class_video_payload_write(device_video_tx_stream, "test0", 16); + status |= ux_device_class_video_payload_write(device_video_tx_stream, "test1", 16); + status |= ux_device_class_video_payload_write(device_video_tx_stream, "test2", 16); + status |= ux_device_class_video_payload_write(device_video_tx_stream, "test3", 16); + status |= ux_device_class_video_payload_write(device_video_tx_stream, "test4", 16); + status |= ux_device_class_video_payload_write(device_video_tx_stream, "test5", 16); + status |= ux_device_class_video_payload_write(device_video_tx_stream, "test6", 16); + status |= ux_device_class_video_payload_write(device_video_tx_stream, "test7", 16); + UX_TEST_CHECK_SUCCESS(status); + + error_callback_counter = 0; + status = ux_device_class_video_payload_write(device_video_tx_stream, "test8", 16); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + /* + Keep sending until under-run. + No buffer appended while running. + */ + + buffer_log_count = 0; + test_tx_ack_count = 10; + status = ux_device_class_video_transmission_start(device_video_tx_stream); + UX_TEST_CHECK_SUCCESS(status); + + /* Delay to let thread runs. */ + _ux_utility_delay_ms(100); + + /* Prepare data for checking. */ + _ux_utility_memory_set(test_cmp, 0, 16); + _ux_utility_memory_copy(test_cmp, "test", 4); + + /* 8 frame should be available. */ + for (test_n = 0; test_n < 8; test_n ++) + { + // printf("%ld: %ld: %s\n", test_n, buffer_log[test_n].length, buffer_log[test_n].data); + test_cmp[4] = (UCHAR)(test_n + '0'); + + UX_TEST_ASSERT(buffer_log[test_n].length == 16); + + status = _ux_utility_memory_compare(buffer_log[test_n].data, test_cmp, 6); + UX_TEST_CHECK_SUCCESS(status); + } + /* Then under-run, 0 length packets. */ + for(;test_n < buffer_log_count; test_n ++) + { + // printf("%ld: %ld\n", test_n, buffer_log[test_n].length); + UX_TEST_ASSERT(buffer_log[test_n].length == 0); + } + + /* + Keep sending until under-run. + Specific number of buffer appended while running. + */ + + for (test_tx_ins_way = 0; test_tx_ins_way < 2; test_tx_ins_way ++) + { + + /* Switch interface to clean up status. */ + status = ux_host_stack_interface_setting_select(interface_inst[1][0]); + status |= ux_host_stack_interface_setting_select(interface_inst[1][1]); + + status = ux_device_class_video_payload_write(device_video_tx_stream, "test0", 20); + status |= ux_device_class_video_payload_write(device_video_tx_stream, "test1", 20); + status |= ux_device_class_video_payload_write(device_video_tx_stream, "test2", 20); + status |= ux_device_class_video_payload_write(device_video_tx_stream, "test3", 20); + UX_TEST_CHECK_SUCCESS(status); + + test_tx_ins_count = 10; + test_tx_ack_count = 20; + buffer_log_count = 0; + status = ux_device_class_video_transmission_start(device_video_tx_stream); + UX_TEST_CHECK_SUCCESS(status); + + /* Delay to let thread runs. */ + _ux_utility_delay_ms(300); + + /* Prepare data for checking. */ + _ux_utility_memory_set(test_cmp, 0, 32); + + /* 4 frame should be available. */ + _ux_utility_memory_copy(test_cmp, "test", 4); + for (test_n = 0; test_n < 4; test_n ++) + { + // printf("%ld: %ld: %s\n", test_n, buffer_log[test_n].length, buffer_log[test_n].data); + test_cmp[4] = (UCHAR)(test_n + '0'); + + UX_TEST_ASSERT(buffer_log[test_n].length == 20); + + status = _ux_utility_memory_compare(buffer_log[test_n].data, test_cmp, 6); + UX_TEST_CHECK_SUCCESS(status); + } + /* 10 more frame should be available. */ + _ux_utility_memory_copy(test_cmp, "insert", 6); + for (; test_n < 14; test_n ++) + { + // printf("%ld: %ld: %s\n", test_n, buffer_log[test_n].length, buffer_log[test_n].data); + test_cmp[6] = (UCHAR)(((10 - (test_n - 4)) % 26) + 'A'); + + UX_TEST_ASSERT(buffer_log[test_n].length == 32); + + status = _ux_utility_memory_compare(buffer_log[test_n].data, test_cmp, 8); + UX_TEST_CHECK_SUCCESS(status); + } + /* Then under-run, 0 length packets. */ + for(;test_n < buffer_log_count; test_n ++) + { + // printf("%ld: %ld\n", test_n, buffer_log[test_n].length); + UX_TEST_ASSERT(buffer_log[test_n].length == 0); + } + } + + UX_TEST_ASSERT(device_video_tx_stream->ux_device_class_video_stream_transfer_pos == device_video_tx_stream->ux_device_class_video_stream_access_pos); + + + /* ------------------ Read test. */ + + UX_TEST_ASSERT(device_video_rx_transfer == UX_NULL); + + temp = 0; + status = ux_device_class_video_read_payload_get(device_video_rx_stream, &temp_buf, &temp); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + status = ux_device_class_video_reception_start(device_video_rx_stream); + UX_TEST_CHECK_SUCCESS(status); + _ux_utility_thread_sleep(1); + + UX_TEST_ASSERT(device_video_rx_transfer != UX_NULL); + + status = ux_device_class_video_read_payload_get(device_video_rx_stream, &temp_buf, &temp); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, status); + + RESET_CALLBACK_INVOKE_LOG(); + + device_video_rx_simulate_one_payload("012345", 6); + status = ux_device_class_video_read_payload_get(device_video_rx_stream, &temp_buf, &temp); + UX_TEST_CHECK_SUCCESS(status); + for (test_n = 0; test_n < 6; test_n ++) + { + UX_TEST_ASSERT(temp_buf[test_n] == (test_n + '0')); + } + ux_device_class_video_read_payload_free(device_video_rx_stream); + + device_video_rx_simulate_one_payload("012345", 6); + device_video_rx_simulate_one_payload("67", 2); + device_video_rx_simulate_one_payload("89", 2); + + status = ux_device_class_video_read_payload_get(device_video_rx_stream, &temp_buf, &temp); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(temp == 6); + for (test_n = 0; test_n < 6; test_n ++) + { + UX_TEST_ASSERT(temp_buf[test_n] == (test_n + '0')); + } + ux_device_class_video_read_payload_free(device_video_rx_stream); + status = ux_device_class_video_read_payload_get(device_video_rx_stream, &temp_buf, &temp); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(temp == 2); + for (; test_n < 8; test_n ++) + { + UX_TEST_ASSERT(temp_buf[test_n-6] == (test_n + '0')); + } + ux_device_class_video_read_payload_free(device_video_rx_stream); + status = ux_device_class_video_read_payload_get(device_video_rx_stream, &temp_buf, &temp); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(temp == 2); + for (; test_n < 10; test_n ++) + { + UX_TEST_ASSERT(temp_buf[test_n-8] == (test_n + '0')); + } + ux_device_class_video_read_payload_free(device_video_rx_stream); + + UX_TEST_ASSERT(callback_invoke_count == 4); + UX_TEST_ASSERT(callback_invoke_log[0].func == device_video_rx_done); + UX_TEST_ASSERT(callback_invoke_log[0].param1 == device_video_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[1].func == device_video_rx_done); + UX_TEST_ASSERT(callback_invoke_log[1].param1 == device_video_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[2].func == device_video_rx_done); + UX_TEST_ASSERT(callback_invoke_log[2].param1 == device_video_rx_stream); + UX_TEST_ASSERT(callback_invoke_log[3].func == device_video_rx_done); + UX_TEST_ASSERT(callback_invoke_log[3].param1 == device_video_rx_stream); + + RESET_CALLBACK_INVOKE_LOG(); + error_callback_counter = 0; + for (test_n = 0; test_n < 10; test_n ++) + { + test_cmp[0] = (UCHAR)(test_n + '0'); + device_video_rx_simulate_one_payload(test_cmp, 1); + } + + UX_TEST_ASSERT(callback_invoke_count == 10); + UX_TEST_ASSERT(error_callback_counter == 3); + for (test_n = 0; test_n < 7; test_n ++) + { + status = ux_device_class_video_read_payload_get(device_video_rx_stream, &temp_buf, &temp); + UX_TEST_CHECK_SUCCESS(status); + UX_TEST_ASSERT(temp == 1); + UX_TEST_ASSERT(temp_buf[0] == (test_n + '0')); + ux_device_class_video_read_payload_free(device_video_rx_stream); + } + UX_TEST_CHECK_SUCCESS(ux_device_class_video_read_payload_get(device_video_rx_stream, &temp_buf, &temp)); + UX_TEST_ASSERT(temp == 1); + UX_TEST_ASSERT(temp_buf[0] == '9'); + ux_device_class_video_read_payload_free(device_video_rx_stream); + UX_TEST_CHECK_CODE(UX_BUFFER_OVERFLOW, ux_device_class_video_read_payload_get(device_video_rx_stream, &temp_buf, &temp)); + + + /* Wait pending threads. */ + _ux_utility_thread_sleep(1); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + ux_device_stack_class_unregister(_ux_system_device_class_video_name, ux_device_class_video_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + while(1) + { + +#if defined(UX_DEVICE_STANDALONE) + + /* Standalone background task. */ + ux_system_tasks_run(); +#else + + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); +#endif + } +} diff --git a/test/regression/usbx_ux_device_stack_alternate_setting_get_test.c b/test/regression/usbx_ux_device_stack_alternate_setting_get_test.c new file mode 100644 index 00000000..b99b1d6b --- /dev/null +++ b/test/regression/usbx_ux_device_stack_alternate_setting_get_test.c @@ -0,0 +1,482 @@ +/* This test is designed to test the ux_device_stack_alternate_setting_get. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +/* HID mouse related descriptors */ + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +#define LSB(x) (x & 0x00ff) +#define MSB(x) ((x & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors 9+7+7=23 bytes. */ +#define DPUMP_IFC_DESC_ALL(ifc, bulk_in_epa, bulk_out_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x02, 0x99, 0x99, 0x99, 0x00,\ + /* Endpoint descriptor (Bulk Out) */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Bulk In) */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00, +#define DPUMP_IFC_DESC_ALL_LEN 23 + +/* HID Mouse interface descriptors 9+9=18 bytes */ +#define HID_MOUSE_IFC0_DESC_ALL(ifc) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH), +#define HID_MOUSE_IFC0_DESC_ALL_LEN 18 + +/* HID Mouse interface descriptors 9+9+7=25 bytes */ +#define HID_MOUSE_IFC1_DESC_ALL(ifc, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x01, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_MOUSE_IFC1_DESC_ALL_LEN 25 + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR expect_errors = UX_FALSE; + + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+9+7 =25 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02) + /* HID 9+9 + 9+9+7=43 */ + HID_MOUSE_IFC0_DESC_ALL(1) + HID_MOUSE_IFC1_DESC_ALL(1, 0x83) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN, 2, 1) + /* DPUMP */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02) + /* HID */ + HID_MOUSE_IFC0_DESC_ALL(1) + HID_MOUSE_IFC1_DESC_ALL(1, 0x83) +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Simulation actions. */ + +static UX_TEST_SIM_ENTRY_ACTION dcd_endpoint_create_fail[] = { +/* 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_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ 0 } +}; + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (!expect_errors) + { + if (error_code != UX_DEVICE_HANDLE_UNKNOWN) + { + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } + } +} + +static UINT test_ux_device_class_hid_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + return UX_SUCCESS; + // return _ux_device_class_hid_entry(command); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_stack_alternate_setting_get_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; +UX_SLAVE_CLASS_HID_PARAMETER hid_parameter; + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_alternate_setting_get Test.................. ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_alternate_setting_get Test.................. ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_alternate_setting_get Test.................. ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_alternate_setting_get Test.................. ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = ux_test_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = ux_test_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Initialize the hid class parameters. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_REPORT_LENGTH; + hid_parameter.ux_device_class_hid_parameter_callback = UX_NULL; + hid_parameter.ux_slave_class_hid_instance_activate = UX_NULL; + + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, test_ux_device_class_hid_entry, + 1, 1, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_alternate_setting_get Test.................. ERROR #6\n"); + test_control_return(1); + } +#endif + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_alternate_setting_get Test.................. ERROR #7\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_alternate_setting_get Test.................. ERROR #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test host simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_device_stack_alternate_setting_get Test.................. ERROR #8\n"); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + +UINT status; +UX_SLAVE_DEVICE *device; +UX_SLAVE_INTERFACE *interface; + + /* Inform user. */ + printf("Running ux_device_stack_alternate_setting_get Test.................. "); + + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Enumeration check. */ + if (dpump_slave == UX_NULL) + { + + printf("ERROR #%d: Enum fail\n", __LINE__); + test_control_return(1); + } + + /* Slave device. */ + device = &_ux_system_slave->ux_system_slave_device; + + /* Expect errors so skip them in error handler. */ + expect_errors = UX_TRUE; + + interface = device -> ux_slave_device_first_interface; + device -> ux_slave_device_first_interface = UX_NULL; + status = _ux_device_stack_alternate_setting_get(0); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: expect error in case no interface\n", __LINE__); + error_counter ++; + } + device -> ux_slave_device_first_interface = interface; + + /* Break on errors. */ + expect_errors = UX_TRUE; + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static VOID ux_test_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID ux_test_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_device_stack_alternate_setting_set_test.c b/test/regression/usbx_ux_device_stack_alternate_setting_set_test.c new file mode 100644 index 00000000..7ee18072 --- /dev/null +++ b/test/regression/usbx_ux_device_stack_alternate_setting_set_test.c @@ -0,0 +1,599 @@ +/* This test is designed to test the ux_device_stack_alternate_setting_set. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +/* HID mouse related descriptors */ + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +#define LSB(x) (x & 0x00ff) +#define MSB(x) ((x & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x20, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors 9+7+7=23 bytes. */ +#define DPUMP_IFC_DESC_ALL(ifc, bulk_in_epa, bulk_out_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x02, 0x99, 0x99, 0x99, 0x00,\ + /* Endpoint descriptor (Bulk Out) */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Bulk In) */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00, +#define DPUMP_IFC_DESC_ALL_LEN 23 + +/* HID Mouse interface descriptors 9+9=18 bytes */ +#define HID_MOUSE_IFC0_DESC_ALL(ifc) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH), +#define HID_MOUSE_IFC0_DESC_ALL_LEN 18 + +/* HID Mouse interface descriptors 9+9+7=25 bytes */ +#define HID_MOUSE_IFC1_DESC_ALL(ifc, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x01, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH),\ + /* Endpoint descriptor (Interrupt), wMaxPacketSize:0x08, n_trans:01 */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x08, 0x08, +#define HID_MOUSE_IFC1_DESC_ALL_LEN 25 + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR expect_errors = UX_FALSE; + + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+9+7 =25 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02) + /* HID 9+9 + 9+9+7=43 */ + HID_MOUSE_IFC0_DESC_ALL(1) + HID_MOUSE_IFC1_DESC_ALL(1, 0x83) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN, 2, 1) + /* DPUMP */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02) + /* HID */ + HID_MOUSE_IFC0_DESC_ALL(1) + HID_MOUSE_IFC1_DESC_ALL(1, 0x83) +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Simulation actions. */ + +static UX_TEST_SIM_ENTRY_ACTION dcd_endpoint_create_fail[] = { +/* 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_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ 0 } +}; + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (!expect_errors) + { + if (error_code != UX_DEVICE_HANDLE_UNKNOWN) + { + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } + } +} + +static UINT test_ux_device_class_hid_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + return UX_SUCCESS; + // return _ux_device_class_hid_entry(command); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_stack_alternate_setting_set_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; +UX_SLAVE_CLASS_HID_PARAMETER hid_parameter; + + + /* Inform user. */ + printf("Running ux_device_stack_alternate_setting_set Test.................. "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + 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(UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry); + + /* Check for error. */ + 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 */ + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = ux_test_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = ux_test_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Initialize the hid class parameters. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_REPORT_LENGTH; + hid_parameter.ux_device_class_hid_parameter_callback = UX_NULL; + hid_parameter.ux_slave_class_hid_instance_activate = UX_NULL; + + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, test_ux_device_class_hid_entry, + 1, 1, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#endif + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test host simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + +UINT status; +UX_SLAVE_DEVICE *device; +UX_SLAVE_CLASS *class; +UX_SLAVE_INTERFACE *interface; +UX_SLAVE_ENDPOINT *endpoint; +UINT ux_slave_class_status; +ULONG endpoints_pool_number; + + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Enumeration check. */ + if (dpump_slave == UX_NULL) + { + + printf("ERROR #%d: Enum fail\n", __LINE__); + test_control_return(1); + } + + /* Slave device. */ + device = &_ux_system_slave->ux_system_slave_device; + + /* Expect errors so skip them in error handler. */ + expect_errors = UX_TRUE; + +#if UX_TEST_MULTI_IFC_ON + /* UX_MEMORY_INSUFFICIENT: + limit endpoint pool size so no free endpoint in pool to generate error. + */ + endpoints_pool_number = device->ux_slave_device_endpoints_pool_number; + device->ux_slave_device_endpoints_pool_number = 0; + + /* Invoke and check status. */ + status = _ux_device_stack_alternate_setting_set(1, 1); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("ERROR #%d: Expect UX_MEMORY_INSUFFICIENT but get %x\n", __LINE__, status); + error_counter ++; + } + /* Restore. */ + device->ux_slave_device_endpoints_pool_number = endpoints_pool_number; +#endif + + /* UX_DCD_CREATE_ENDPOINT fail: + set DCD action to generate endpoint creation error. + */ + ux_test_dcd_sim_slave_set_actions(dcd_endpoint_create_fail); + +#if UX_TEST_MULTI_CLS_ON && UX_TEST_MULTI_IFC_ON + + /* Invoke and check status. */ + status = _ux_device_stack_alternate_setting_set(1, 1); + if (status != UX_ERROR) + { + + printf("ERROR #%d: Expect UX_ERROR but get %x\n", __LINE__, status); + error_counter ++; + } + + if (device->ux_slave_device_first_interface->ux_slave_interface_next_interface->ux_slave_interface_first_endpoint) + { + + printf("ERROR #%d: Expect no endpoints\n", __LINE__); + error_counter ++; + } + /* No action replacement. */ + ux_test_dcd_sim_slave_set_actions(UX_NULL); + + /* UX_NO_CLASS_MATCH: + No class driver registered for the class. + */ + class = _ux_system_slave -> ux_system_slave_interface_class_array[1]; + _ux_system_slave -> ux_system_slave_interface_class_array[1] = UX_NULL; + + /* Invoke and check status. */ + status = _ux_device_stack_alternate_setting_set(1, 1); + if (status != UX_NO_CLASS_MATCH) + { + + printf("ERROR #%d: Expect UX_NO_CLASS_MATCH but get %x\n", __LINE__, status); + error_counter ++; + } + _ux_system_slave -> ux_system_slave_interface_class_array[1] = class; + + /* Select alternate setting 0. */ + status = _ux_device_stack_alternate_setting_set(1, 0); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: Expect success but get %x\n", __LINE__, status); + error_counter ++; + } + + ux_slave_class_status = class->ux_slave_class_status; + class->ux_slave_class_status = UX_UNUSED; + + /* Invoke and check status. */ + status = _ux_device_stack_alternate_setting_set(1, 1); + if (status != UX_NO_CLASS_MATCH) + { + + printf("ERROR #%d: Expect UX_NO_CLASS_MATCH but get %x\n", __LINE__, status); + error_counter ++; + } + class->ux_slave_class_status = ux_slave_class_status; + + /* case: device_framework_length == 0 */ + _ux_system_slave -> ux_system_slave_device_framework_length = 0; + status = _ux_device_stack_alternate_setting_set(1, 0); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: Expect error but get %x\n", __LINE__, status); + error_counter ++; + } + _ux_system_slave -> ux_system_slave_device_framework_length = _ux_system_slave -> ux_system_slave_device_framework_length_high_speed; + + /* Normal case: switch alternate setting several times */ + status = _ux_device_stack_alternate_setting_set(1, 0); + status |= _ux_device_stack_alternate_setting_set(1, 1); + status |= _ux_device_stack_alternate_setting_set(1, 0); + status |= _ux_device_stack_alternate_setting_set(1, 1); + UX_TEST_CHECK_SUCCESS(status); + + /* Endpoint 0x83 should be available and ready to use */ + interface = class->ux_slave_class_interface; + UX_TEST_ASSERT(interface != UX_NULL); + + endpoint = interface->ux_slave_interface_first_endpoint; + UX_TEST_ASSERT(endpoint != UX_NULL); + + UX_TEST_ASSERT(endpoint->ux_slave_endpoint_descriptor.bEndpointAddress == 0x83); + UX_TEST_ASSERT(endpoint->ux_slave_endpoint_state == 0x00); +#if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 0 + UX_TEST_ASSERT(endpoint->ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer != UX_NULL); +#else + /* HID has no implement of alternate setting change, buffer not assigned. */ + UX_TEST_ASSERT(endpoint->ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer == UX_NULL); +#endif +#if !defined(UX_DEVICE_STANDALONE) + UX_TEST_ASSERT(endpoint->ux_slave_endpoint_transfer_request.ux_slave_transfer_request_semaphore.tx_semaphore_id != 0); + UX_TEST_ASSERT(endpoint->ux_slave_endpoint_transfer_request.ux_slave_transfer_request_semaphore.tx_semaphore_count == 0); +#endif + UX_TEST_ASSERT(endpoint->ux_slave_endpoint_transfer_request.ux_slave_transfer_request_transfer_length == 16); + +#endif /* #if UX_MAX_SLAVE_CLASS_DRIVER > 1 */ + + /* Break on errors. */ + expect_errors = UX_TRUE; + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static VOID ux_test_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID ux_test_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_device_stack_bos_test.c b/test/regression/usbx_ux_device_stack_bos_test.c new file mode 100644 index 00000000..1393b162 --- /dev/null +++ b/test/regression/usbx_ux_device_stack_bos_test.c @@ -0,0 +1,365 @@ +/* This test is designed to test the BOS. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +/* Define USBX test global variables. */ + +#define DW3(x) (((x) >> 24) & 0xFFu) +#define DW2(x) (((x) >> 16) & 0xFFu) +#define DW1(x) (((x) >> 8) & 0xFFu) +#define DW0(x) ( (x) & 0xFFu) +#define W1(x) (((x) >> 8) & 0xFFu) +#define W0(x) ( (x) & 0xFFu) + +#define _DEVICE_DESCRIPTOR \ + /* Device descriptor. */ \ + 18, UX_DEVICE_DESCRIPTOR_ITEM, \ + W0(0x201), W1(0x201), \ + UX_CLASS_BILLBOARD_CLASS, \ + UX_CLASS_BILLBOARD_SUBCLASS, \ + UX_CLASS_BILLBOARD_PROTOCOL, \ + 64, \ + W0(0xec08), W1(0xec08), \ + W0(0x0001), W1(0x0001), \ + W0(0x0001), W1(0x0001), \ + 0, 0, 0, \ + 1 + +#define _DEVICE_QUALIFIER_DESCRIPTOR \ + /* Device Qualifier Descriptor. */ \ + 10, UX_DEVICE_QUALIFIER_DESCRIPTOR_ITEM,\ + W0(0x201), W1(0x201), \ + UX_CLASS_BILLBOARD_CLASS, \ + UX_CLASS_BILLBOARD_SUBCLASS, \ + UX_CLASS_BILLBOARD_PROTOCOL, \ + 8, \ + 1, \ + 0 + +#define _CONFIGURATION_DESCRIPTOR \ + /* Configuration Descriptor. */ \ + 9, UX_CONFIGURATION_DESCRIPTOR_ITEM,\ + W0(18), W1(18), \ + 1, 1, \ + 0, 0xc0, 0x32 + +#define _INTERFACE_DESCRIPTOR \ + /* Interface Descriptor. */ \ + 9, UX_INTERFACE_DESCRIPTOR_ITEM,\ + 0, 0, 0, \ + UX_CLASS_BILLBOARD_CLASS, \ + UX_CLASS_BILLBOARD_SUBCLASS, \ + UX_CLASS_BILLBOARD_PROTOCOL, \ + 0 + +#define _BOS_DESCRIPTORS_LENGTH (5+7+56+8+8+8) +#define _BOS_DESCRIPTORS \ + /* BOS descriptor. */ \ + 5, UX_BOS_DESCRIPTOR_ITEM, \ + W0(_BOS_DESCRIPTORS_LENGTH), W1(_BOS_DESCRIPTORS_LENGTH), 1,\ + /* USB 2.0 Extension descriptor */ \ + 7, UX_DEVICE_CAPABILITY_DESCRIPTOR_ITEM, UX_CAPABILITY_USB_2_0_EXTENSION, \ + DW0(0x00000002u), DW1(0x00000002u), DW2(0x00000002u), DW3(0x00000002u), \ + /* Billboard Capability Descriptor Example (44+3*4=56) */\ + 56, UX_DEVICE_CAPABILITY_DESCRIPTOR_ITEM, UX_CAPABILITY_BILLBOARD, 0, \ + 1, 0, \ + W0(0), W1(0), \ + 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + W0(0x0000), W0(0x0000), \ + 0x00, 0x00, \ + W0(0x8087), W1(0x8087), 0x00, 0x00, \ + W0(0x8087), W1(0x8087), 0x01, 0x00, \ + W0(0xFF01), W1(0xFF01), 0x00, 0x00, \ + /* Billboard Alternate Mode Capability Descriptor Examples */\ + 8, UX_DEVICE_CAPABILITY_DESCRIPTOR_ITEM, UX_CAPABILITY_BILLBOARD_EX, \ + 0, DW0(0x00000010), DW1(0x00000010), DW2(0x00000010), DW3(0x00000010), \ + 8, UX_DEVICE_CAPABILITY_DESCRIPTOR_ITEM, UX_CAPABILITY_BILLBOARD_EX, \ + 1, DW0(0x00000002), DW1(0x00000002), DW2(0x00000002), DW3(0x00000002), \ + 8, UX_DEVICE_CAPABILITY_DESCRIPTOR_ITEM, UX_CAPABILITY_BILLBOARD_EX, \ + 2, DW0(0x000C00C5), DW1(0x000C00C5), DW2(0x000C00C5), DW3(0x000C00C5) + + +static UCHAR device_framework_full_speed[] = { + + _DEVICE_DESCRIPTOR, + _BOS_DESCRIPTORS, + _CONFIGURATION_DESCRIPTOR, + _INTERFACE_DESCRIPTOR, +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + _DEVICE_DESCRIPTOR, + _BOS_DESCRIPTORS, + _DEVICE_QUALIFIER_DESCRIPTOR, + _CONFIGURATION_DESCRIPTOR, + _INTERFACE_DESCRIPTOR, +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_host_simulation; +static TX_THREAD ux_test_thread_slave_simulation; +static void ux_test_thread_host_simulation_entry(ULONG); +static void ux_test_thread_slave_simulation_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (error_code != UX_DEVICE_HANDLE_UNKNOWN && + error_code != UX_DEVICE_ENUMERATION_FAILURE) + { + /* 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); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_stack_bos_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; + + + printf("Running ux_device_stack BOS Test...................................."); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + 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(UX_NULL); + + /* Check for error. */ + 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 */ + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%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 #%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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_host_simulation, "test host simulation", ux_test_thread_host_simulation_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void ux_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +INT i; +UX_DEVICE *device; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; + + + /* Wait device connection. */ + for (i = 0; i < 10; i ++) + { + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + break; + ux_utility_delay_ms(10); + } + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait until enumeration retries end. */ + ux_utility_delay_ms(1000); + + /* Test BOS request. */ + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_requested_length = 0xFF; + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = UX_BOS_DESCRIPTOR_ITEM << 8; + transfer_request -> ux_transfer_request_index = 0; + + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: 0x%x\n", __LINE__, status); + error_counter ++; + } + if (transfer_request->ux_transfer_request_actual_length != _BOS_DESCRIPTORS_LENGTH) + { + + printf("ERROR #%d: 0x%x\n", __LINE__, status); + error_counter ++; + } + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_ux_device_stack_class_control_request_test.c b/test/regression/usbx_ux_device_stack_class_control_request_test.c new file mode 100644 index 00000000..cbd27da2 --- /dev/null +++ b/test/regression/usbx_ux_device_stack_class_control_request_test.c @@ -0,0 +1,227 @@ +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" +#include "ux_test.h" +#include "ux_device_stack.h" +#include "ux_test_utility_sim.h" + + +static UX_SLAVE_TRANSFER transfer_request; +static UX_SYSTEM_SLAVE system_slave; +static UX_SLAVE_CLASS slave_classes[UX_MAX_SLAVE_INTERFACES]; +static UX_SLAVE_INTERFACE slave_interfaces[UX_MAX_SLAVE_INTERFACES]; + +static UINT test_entry_count = 0; +static UINT test_entry_class[UX_MAX_SLAVE_INTERFACES] = {0, 0, 0, 0}; +static inline void _test_entry_log_reset(void) +{ + test_entry_class[0] = 0; + test_entry_class[1] = 0; + test_entry_class[2] = 0; + test_entry_class[3] = 0; + test_entry_count = 0; +} +#define TEST_ENTRY_LOG_SAVE(c) \ + if (test_entry_count < UX_MAX_SLAVE_INTERFACES) { test_entry_class[test_entry_count++] = c; } +#define TEST_ENTRY_LOG_CHECK_FAIL(c1,c2,c3,c4) \ + (test_entry_class[0] != c1) || (test_entry_class[1] != c2) || \ + (test_entry_class[2] != c3) || (test_entry_class[3] != c4) + +typedef struct _REQ_ACCEPTED { + UCHAR type; + UCHAR request; +} REQ_ACCEPTED; +typedef struct _CLASS_REQ_ACCEPTED { + UCHAR bClass; + UCHAR n_req; + REQ_ACCEPTED *req; +} CLASS_REQ_ACCEPTED; +static REQ_ACCEPTED cdc_acm_req[] = { + {0x21, 0x00}, /* SEND_ENCAPSULATED_COMMAND */ + {0xA1, 0x01}, /* GET_ENCAPSULATED_RESPONSE */ + {0x21, 0x02}, /* SET_COMM_FEATURE */ + {0xA1, 0x03}, /* GET_COMM_FEATURE */ + {0x21, 0x04}, /* CLEAR_COMM_FEATURE */ + {0x21, 0x05}, /* SET_LINE_CODING */ + {0xA1, 0x06}, /* GET_LINE_CODING */ + {0x21, 0x07}, /* SET_CONTROL_LINE_STATE */ + {0x21, 0x08}, /* SEND_BREAK */ +}; +static REQ_ACCEPTED printer_req[] = { + {0xA1, 0x00}, /* GET_DEVICE_ID */ + {0xA1, 0x01}, /* GET_PORT_STATUS */ + {0x21, 0x02}, /* SOFT_RESET */ +}; +static REQ_ACCEPTED storage_req[] = { + {0x21, 0xFF}, /* Bulk-Only Reset */ + {0xA1, 0xFE}, /* Get Max LUN */ +}; +static REQ_ACCEPTED hid_req[] = { + {0xA1, 0x01}, /* GET_REPORT */ + {0xA1, 0x02}, /* GET_IDLE */ + {0xA1, 0x03}, /* GET_PROTOCOL */ + {0x21, 0x09}, /* SET_REPORT */ + {0x21, 0x0A}, /* SET_IDLE */ + {0x21, 0x0B}, /* SET_PROTOCOL */ +}; +static CLASS_REQ_ACCEPTED class_req_accepted[] = { + {0x02, sizeof(cdc_acm_req)/sizeof(REQ_ACCEPTED), cdc_acm_req}, + {0x07, sizeof(printer_req)/sizeof(REQ_ACCEPTED), printer_req}, + {0x08, sizeof(storage_req)/sizeof(REQ_ACCEPTED), storage_req}, + {0x03, sizeof(hid_req)/sizeof(REQ_ACCEPTED), hid_req}, +}; + +UINT _test_class_entry(struct UX_SLAVE_CLASS_COMMAND_STRUCT *cmd) +{ +UX_SLAVE_DEVICE *device = &_ux_system_slave -> ux_system_slave_device; +UX_SLAVE_CLASS *cmd_class = cmd -> ux_slave_class_command_class_ptr; +UX_SLAVE_TRANSFER *transfer = &transfer_request; +INT i, j; + + stepinfo(" entry call: %p (%x)\n", cmd_class, (unsigned)cmd_class -> ux_slave_class_interface->ux_slave_interface_descriptor.bInterfaceClass); + TEST_ENTRY_LOG_SAVE(cmd_class -> ux_slave_class_interface->ux_slave_interface_descriptor.bInterfaceClass); + for (i = 0; i < sizeof(class_req_accepted)/sizeof(CLASS_REQ_ACCEPTED); i++) + { + if (cmd_class->ux_slave_class_interface->ux_slave_interface_descriptor.bInterfaceClass == class_req_accepted[i].bClass) + { + for (j = 0; j < class_req_accepted[i].n_req; j++) + { + if (transfer->ux_slave_transfer_request_setup[UX_SETUP_REQUEST] == class_req_accepted[i].req[j].request && + transfer->ux_slave_transfer_request_setup[UX_SETUP_REQUEST_TYPE] == class_req_accepted[i].req[j].type) + { + return(UX_SUCCESS); + } + } + } + } + return (UX_NO_CLASS_MATCH); +} + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_stack_class_control_request_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status = 0; +UCHAR request_type = UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; +UCHAR request = 0; +INT i; + + + /* Inform user. */ + printf("Running USB Device Stack Class Control Request Process Test ........ "); + if (UX_MAX_SLAVE_INTERFACES < 4) + { + printf("Supported number of interface: %d (<4)\n", UX_MAX_SLAVE_INTERFACES); + printf("Skipped\n"); + test_control_return(0); + return; + } + + _ux_system_slave = &system_slave; + for (i = 0; i < UX_MAX_SLAVE_INTERFACES; i++) + { + if (i > 3) + { + system_slave.ux_system_slave_interface_class_array[i] = UX_NULL; + continue; + } + system_slave.ux_system_slave_interface_class_array[i] = &slave_classes[i]; + slave_classes[i].ux_slave_class_interface = &slave_interfaces[i]; + slave_classes[i].ux_slave_class_entry_function = _test_class_entry; + slave_interfaces[i].ux_slave_interface_descriptor.bInterfaceClass = 0x00; + } + stepinfo("class array: %p %p %p %p ...\n", + system_slave.ux_system_slave_interface_class_array[0], + system_slave.ux_system_slave_interface_class_array[1], + system_slave.ux_system_slave_interface_class_array[2], + system_slave.ux_system_slave_interface_class_array[3]); + +struct _test_struct { + /* Interface */ + UCHAR ifc_class[4]; /* 2:CDC, 7:PRINT, 8:MSC, 3:HID */ + /* Input */ + UCHAR setup[8]; + /* Output check */ + UINT status; + UCHAR cmd_class[4]; /* 2:CDC, 7:PRINT, 8:MSC, 3:HID */ +} tests[] = { + /* class type req value index length return class */ + { {0x07, 0x02, 0x03, 0x08}, {0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, UX_SUCCESS, {0x07, 0x00, 0x00, 0x00}}, + { {0x07, 0x02, 0x03, 0x08}, {0xA1, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}, UX_SUCCESS, {0x07, 0x00, 0x00, 0x00}}, + { {0x07, 0x02, 0x03, 0x08}, {0xA1, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00}, UX_ERROR, {0x00, 0x00, 0x00, 0x00}}, + { {0x07, 0x02, 0x03, 0x08}, {0xA1, 0x00, 0x00, 0x00, 0x05, 0x01, 0x00, 0x00}, UX_ERROR, {0x00, 0x00, 0x00, 0x00}}, + { {0x07, 0x02, 0x03, 0x08}, {0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, UX_NO_CLASS_MATCH, {0x07, 0x00, 0x00, 0x00}}, + { {0x07, 0x02, 0x03, 0x08}, {0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}, UX_SUCCESS, {0x02, 0x00, 0x00, 0x00}}, + { {0x07, 0x02, 0x03, 0x08}, {0x21, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00}, UX_NO_CLASS_MATCH, {0x03, 0x00, 0x00, 0x00}}, + { {0x07, 0x02, 0x03, 0x08}, {0x21, 0x0A, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00}, UX_SUCCESS, {0x03, 0x00, 0x00, 0x00}}, + { {0x07, 0x02, 0x03, 0x08}, {0xA1, 0xFE, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00}, UX_SUCCESS, {0x08, 0x00, 0x00, 0x00}}, + { {0x07, 0x02, 0x03, 0x08}, {0xA1, 0xFE, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00}, UX_ERROR, {0x00, 0x00, 0x00, 0x00}}, + + /* class type req value index length return class */ + { {0x02, 0x07, 0x03, 0x08}, {0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, UX_NO_CLASS_MATCH, {0x02, 0x00, 0x00, 0x00}}, + { {0x02, 0x07, 0x03, 0x08}, {0xA1, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00}, UX_SUCCESS, {0x02, 0x07, 0x00, 0x00}}, + { {0x02, 0x07, 0x03, 0x08}, {0x21, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00}, UX_SUCCESS, {0x02, 0x00, 0x00, 0x00}}, + { {0x02, 0x07, 0x03, 0x08}, {0xA1, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}, UX_SUCCESS, {0x07, 0x00, 0x00, 0x00}}, + { {0x02, 0x07, 0x03, 0x08}, {0xA1, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00}, UX_NO_CLASS_MATCH, {0x02, 0x00, 0x00, 0x00}}, + { {0x02, 0x07, 0x03, 0x08}, {0xA1, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00}, UX_SUCCESS, {0x03, 0x00, 0x00, 0x00}}, + { {0x02, 0x07, 0x03, 0x08}, {0xA1, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00}, UX_ERROR, {0x00, 0x00, 0x00, 0x00}}, + + /* class type req value index length return class */ + { {0x03, 0x08, 0x07, 0x02}, {0xA1, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00}, UX_SUCCESS, {0x03, 0x07, 0x00, 0x00}}, + { {0x03, 0x08, 0x07, 0x02}, {0xA1, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00}, UX_NO_CLASS_MATCH, {0x03, 0x00, 0x00, 0x00}}, + { {0x03, 0x08, 0x07, 0x02}, {0xA1, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00}, UX_ERROR, {0x00, 0x00, 0x00, 0x00}}, +}; + for (i = 0; i < sizeof(tests)/sizeof(struct _test_struct); i ++) + { + + _test_entry_log_reset(); + + slave_interfaces[0].ux_slave_interface_descriptor.bInterfaceClass = tests[i].ifc_class[0]; + slave_interfaces[1].ux_slave_interface_descriptor.bInterfaceClass = tests[i].ifc_class[1]; + slave_interfaces[2].ux_slave_interface_descriptor.bInterfaceClass = tests[i].ifc_class[2]; + slave_interfaces[3].ux_slave_interface_descriptor.bInterfaceClass = tests[i].ifc_class[3]; + + transfer_request.ux_slave_transfer_request_completion_code = UX_SUCCESS; + transfer_request.ux_slave_transfer_request_setup[0] = tests[i].setup[0]; + transfer_request.ux_slave_transfer_request_setup[UX_SETUP_REQUEST] = tests[i].setup[UX_SETUP_REQUEST]; + transfer_request.ux_slave_transfer_request_setup[UX_SETUP_INDEX] = tests[i].setup[UX_SETUP_INDEX]; + transfer_request.ux_slave_transfer_request_setup[UX_SETUP_INDEX + 1] = tests[i].setup[UX_SETUP_INDEX + 1]; + + stepinfo(" test #%2d: {%x %x %x %x} {%x %x .. %x %x ..} %x {%x %x %x %x}\n", i, + tests[i].ifc_class[0], tests[i].ifc_class[1], tests[i].ifc_class[2], tests[i].ifc_class[3], + tests[i].setup[0], tests[i].setup[UX_SETUP_REQUEST], tests[i].setup[UX_SETUP_INDEX], tests[i].setup[UX_SETUP_INDEX + 1], + tests[i].status, tests[i].cmd_class[0], tests[i].cmd_class[1], tests[i].cmd_class[2], tests[i].cmd_class[3]); + + status = _ux_device_stack_control_request_process(&transfer_request); + if (status != tests[i].status) + { + printf("ERROR #%d: %2d {%x %x %x %x} {%x %x .. %x %x ..}, status = %x, expected %x\n", __LINE__, + i, tests[i].ifc_class[0], tests[i].ifc_class[1], tests[i].ifc_class[2], tests[i].ifc_class[3], + tests[i].setup[0], tests[i].setup[UX_SETUP_REQUEST], tests[i].setup[UX_SETUP_INDEX], tests[i].setup[UX_SETUP_INDEX + 1], + status, tests[i].status); + test_control_return(1); + return; + } + if (TEST_ENTRY_LOG_CHECK_FAIL(tests[i].cmd_class[0], tests[i].cmd_class[1], tests[i].cmd_class[2], tests[i].cmd_class[3])) + { + printf("ERROR #%d: %2d {%x %x %x %x} {%x %x .. %x %x ..}, class call {%x %x %x %x}, expected {%x %x %x %x}\n", __LINE__, + i, tests[i].ifc_class[0], tests[i].ifc_class[1], tests[i].ifc_class[2], tests[i].ifc_class[3], + tests[i].setup[0], tests[i].setup[UX_SETUP_REQUEST], tests[i].setup[UX_SETUP_INDEX], tests[i].setup[UX_SETUP_INDEX + 1], + test_entry_class[0], test_entry_class[1], test_entry_class[2], test_entry_class[3], + tests[i].cmd_class[0], tests[i].cmd_class[1], tests[i].cmd_class[2], tests[i].cmd_class[3]); + test_control_return(1); + return; + } + } + + printf("SUCCESS!\n"); + test_control_return(0); + + return; +} diff --git a/test/regression/usbx_ux_device_stack_class_register_test.c b/test/regression/usbx_ux_device_stack_class_register_test.c new file mode 100644 index 00000000..1dd27856 --- /dev/null +++ b/test/regression/usbx_ux_device_stack_class_register_test.c @@ -0,0 +1,518 @@ +/* This test is designed to test the ux_device_stack_class_register. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +/* HID mouse related descriptors */ + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +#define LSB(x) (x & 0x00ff) +#define MSB(x) ((x & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x20, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors 9+7+7=23 bytes. */ +#define DPUMP_IFC_DESC_ALL(ifc, bulk_in_epa, bulk_out_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x02, 0x99, 0x99, 0x99, 0x00,\ + /* Endpoint descriptor (Bulk Out) */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Bulk In) */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00, +#define DPUMP_IFC_DESC_ALL_LEN 23 + +/* HID Mouse interface descriptors 9+9=18 bytes */ +#define HID_MOUSE_IFC0_DESC_ALL(ifc) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH), +#define HID_MOUSE_IFC0_DESC_ALL_LEN 18 + +/* HID Mouse interface descriptors 9+9+7=25 bytes */ +#define HID_MOUSE_IFC1_DESC_ALL(ifc, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x01, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_MOUSE_IFC1_DESC_ALL_LEN 25 + +/* CDC-ACM interfaces descriptors 8 +9+5+4+5+5+7 +9+7+7=66 bytes */ +#define CDC_ACM_IFCES_DESC_ALL(ifc, interrupt_epa, bulk_in_epa, bulk_out_epa) \ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (ifc), 0x02, 0x02, 0x02, 0x00, 0x00,\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (ifc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06,\ + (ifc), /* Master interface */\ + (ifc+1), /* Slave interface */\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03,\ + (ifc+1), /* Data interface */\ + /* Interrupt endpoint descriptor 7 bytes */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 15,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (ifc+1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint descriptor 7 bytes */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor 7 bytes */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00, +#define CDC_ACM_IFCES_DESC_ALL_LEN 66 + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR expect_errors = UX_FALSE; + + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN + CDC_ACM_IFCES_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+9+7 =25 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02) + /* HID 9+9 + 9+9+7=43 */ + HID_MOUSE_IFC0_DESC_ALL(1) + HID_MOUSE_IFC1_DESC_ALL(1, 0x83) + /* CDC-ACM */ + CDC_ACM_IFCES_DESC_ALL(2, 0x86, 0x85, 0x04) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN + CDC_ACM_IFCES_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+9+7 =25 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02) + /* HID 9+9 + 9+9+7=43 */ + HID_MOUSE_IFC0_DESC_ALL(1) + HID_MOUSE_IFC1_DESC_ALL(1, 0x83) + /* CDC-ACM */ + CDC_ACM_IFCES_DESC_ALL(2, 0x86, 0x85, 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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Simulation actions. */ + +static UX_TEST_SIM_ENTRY_ACTION dcd_endpoint_create_fail[] = { +/* 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_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ 0 } +}; + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (!expect_errors) + { + if (error_code != UX_DEVICE_HANDLE_UNKNOWN) + { + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } + } +} + +static UINT test_ux_device_class_hid_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + return UX_SUCCESS; + // return _ux_device_class_hid_entry(command); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_stack_class_register_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; +UX_SLAVE_CLASS_HID_PARAMETER hid_parameter; + + /* Inform user. */ + printf("Running ux_device_stack_class_register Test......................... "); + stepinfo("\n"); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + 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(UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry); + + /* Check for error. */ + 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 */ + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = ux_test_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = ux_test_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Initialize the hid class parameters. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_REPORT_LENGTH; + hid_parameter.ux_device_class_hid_parameter_callback = UX_NULL; + hid_parameter.ux_slave_class_hid_instance_activate = UX_NULL; + + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, test_ux_device_class_hid_entry, + 1, 1, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#endif + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test host simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + +UINT status; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; +UCHAR invalid_class_name[UX_MAX_CLASS_NAME_LENGTH+2]; + + /* Inform user. */ + stepinfo(">>>>>>>>> ENUM check\n"); + + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Enumeration check. */ + if (dpump_slave == UX_NULL) + { + + printf("ERROR #%d: Enum fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>> Disconnect\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Expect errors so skip them in error handler. */ + expect_errors = UX_TRUE; + + stepinfo(">>>>>>>>> ux_device_stack_class_register - error if class_name exceed UX_MAX_CLASS_NAME_LENGTH\n"); + _ux_utility_memory_set(invalid_class_name, 'a', sizeof(invalid_class_name)); + _ux_utility_memory_copy(invalid_class_name, _ux_system_slave_class_dpump_name, 20); + status = ux_device_stack_class_register(invalid_class_name, _ux_device_class_dpump_entry, + 2, 0, ¶meter); + if (status != UX_ERROR) + { + printf("ERROR %d: expect error %d\n", __LINE__, UX_ERROR); + error_counter ++; + } + + /* Break on errors. */ + expect_errors = UX_TRUE; + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static VOID ux_test_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID ux_test_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_device_stack_class_unregister_test.c b/test/regression/usbx_ux_device_stack_class_unregister_test.c new file mode 100644 index 00000000..275f1927 --- /dev/null +++ b/test/regression/usbx_ux_device_stack_class_unregister_test.c @@ -0,0 +1,518 @@ +/* This test is designed to test the ux_device_stack_class_unregister. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +/* HID mouse related descriptors */ + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +#define LSB(x) (x & 0x00ff) +#define MSB(x) ((x & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x20, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors 9+7+7=23 bytes. */ +#define DPUMP_IFC_DESC_ALL(ifc, bulk_in_epa, bulk_out_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x02, 0x99, 0x99, 0x99, 0x00,\ + /* Endpoint descriptor (Bulk Out) */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Bulk In) */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00, +#define DPUMP_IFC_DESC_ALL_LEN 23 + +/* HID Mouse interface descriptors 9+9=18 bytes */ +#define HID_MOUSE_IFC0_DESC_ALL(ifc) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH), +#define HID_MOUSE_IFC0_DESC_ALL_LEN 18 + +/* HID Mouse interface descriptors 9+9+7=25 bytes */ +#define HID_MOUSE_IFC1_DESC_ALL(ifc, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x01, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_MOUSE_IFC1_DESC_ALL_LEN 25 + +/* CDC-ACM interfaces descriptors 8 +9+5+4+5+5+7 +9+7+7=66 bytes */ +#define CDC_ACM_IFCES_DESC_ALL(ifc, interrupt_epa, bulk_in_epa, bulk_out_epa) \ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (ifc), 0x02, 0x02, 0x02, 0x00, 0x00,\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (ifc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06,\ + (ifc), /* Master interface */\ + (ifc+1), /* Slave interface */\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03,\ + (ifc+1), /* Data interface */\ + /* Interrupt endpoint descriptor 7 bytes */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 15,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (ifc+1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint descriptor 7 bytes */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor 7 bytes */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00, +#define CDC_ACM_IFCES_DESC_ALL_LEN 66 + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR expect_errors = UX_FALSE; + + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN + CDC_ACM_IFCES_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+9+7 =25 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02) + /* HID 9+9 + 9+9+7=43 */ + HID_MOUSE_IFC0_DESC_ALL(1) + HID_MOUSE_IFC1_DESC_ALL(1, 0x83) + /* CDC-ACM */ + CDC_ACM_IFCES_DESC_ALL(2, 0x86, 0x85, 0x04) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN + CDC_ACM_IFCES_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+9+7 =25 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02) + /* HID 9+9 + 9+9+7=43 */ + HID_MOUSE_IFC0_DESC_ALL(1) + HID_MOUSE_IFC1_DESC_ALL(1, 0x83) + /* CDC-ACM */ + CDC_ACM_IFCES_DESC_ALL(2, 0x86, 0x85, 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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Simulation actions. */ + +static UX_TEST_SIM_ENTRY_ACTION dcd_endpoint_create_fail[] = { +/* 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_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ 0 } +}; + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (!expect_errors) + { + if (error_code != UX_DEVICE_HANDLE_UNKNOWN) + { + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } + } +} + +static UINT test_ux_device_class_hid_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + return UX_SUCCESS; + // return _ux_device_class_hid_entry(command); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_stack_class_unregister_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; +UX_SLAVE_CLASS_HID_PARAMETER hid_parameter; + + /* Inform user. */ + printf("Running ux_device_stack_class_unregister Test....................... "); + stepinfo("\n"); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + 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(UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry); + + /* Check for error. */ + 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 */ + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = ux_test_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = ux_test_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Initialize the hid class parameters. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_REPORT_LENGTH; + hid_parameter.ux_device_class_hid_parameter_callback = UX_NULL; + hid_parameter.ux_slave_class_hid_instance_activate = UX_NULL; + + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, test_ux_device_class_hid_entry, + 1, 1, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#endif + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test host simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + +UINT status; +UCHAR invalid_class_name[UX_MAX_CLASS_NAME_LENGTH+2]; + + /* Inform user. */ + stepinfo(">>>>>>>>> ENUM check\n"); + + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Enumeration check. */ + if (dpump_slave == UX_NULL) + { + + printf("ERROR #%d: Enum fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>> Disconnect\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Expect errors so skip them in error handler. */ + expect_errors = UX_TRUE; + +#if !defined(UX_NAME_REFERENCED_BY_POINTER) + stepinfo(">>>>>>>>> _ux_device_stack_class_unregister - error if class_name exceed UX_MAX_CLASS_NAME_LENGTH\n"); + _ux_utility_memory_set(invalid_class_name, 'a', sizeof(invalid_class_name)); + _ux_utility_memory_copy(invalid_class_name, _ux_system_slave_class_dpump_name, 20); + status = _ux_device_stack_class_unregister(invalid_class_name, _ux_device_class_dpump_entry); + if (status != UX_ERROR) + { + printf("ERROR %d: expect error %d\n", __LINE__, UX_ERROR); + error_counter ++; + } +#endif + + /* Break on errors. */ + expect_errors = UX_TRUE; + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static VOID ux_test_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID ux_test_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_device_stack_clear_feature_coverage_test.c b/test/regression/usbx_ux_device_stack_clear_feature_coverage_test.c new file mode 100644 index 00000000..bc4c1806 --- /dev/null +++ b/test/regression/usbx_ux_device_stack_clear_feature_coverage_test.c @@ -0,0 +1,33 @@ +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" +#include "ux_test.h" +#include "ux_device_stack.h" +#include "ux_test_utility_sim.h" + +extern UX_SYSTEM_SLAVE *_ux_system_slave; +static UX_SYSTEM_SLAVE system_slave; +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_stack_clear_feature_coverage_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status = 0; + + + /* Inform user. */ + printf("Running USB Device Stack Clear Feature Coverage Test ............... "); + + _ux_system_slave = &system_slave; + + _ux_device_stack_clear_feature(UX_REQUEST_TARGET_DEVICE, 0, 0); + + printf(" Passed\n"); + test_control_return(0); + return; +} diff --git a/test/regression/usbx_ux_device_stack_configuration_set_test.c b/test/regression/usbx_ux_device_stack_configuration_set_test.c new file mode 100644 index 00000000..6707e39e --- /dev/null +++ b/test/regression/usbx_ux_device_stack_configuration_set_test.c @@ -0,0 +1,501 @@ +/* This test is designed to test the ux_device_stack_configuration_set. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +/* HID mouse related descriptors */ + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +#define LSB(x) (x & 0x00ff) +#define MSB(x) ((x & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x20, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors 9+7+7=23 bytes. */ +#define DPUMP_IFC_DESC_ALL(ifc, bulk_in_epa, bulk_out_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x02, 0x99, 0x99, 0x99, 0x00,\ + /* Endpoint descriptor (Bulk Out) */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Bulk In) */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00, +#define DPUMP_IFC_DESC_ALL_LEN 23 + +/* HID Mouse interface descriptors 9+9=18 bytes */ +#define HID_MOUSE_IFC0_DESC_ALL(ifc) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH), +#define HID_MOUSE_IFC0_DESC_ALL_LEN 18 + +/* HID Mouse interface descriptors 9+9+7=25 bytes */ +#define HID_MOUSE_IFC1_DESC_ALL(ifc, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x01, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_MOUSE_IFC1_DESC_ALL_LEN 25 + +/* CDC-ACM interfaces descriptors 8 +9+5+4+5+5+7 +9+7+7=66 bytes */ +#define CDC_ACM_IFCES_DESC_ALL(ifc, interrupt_epa, bulk_in_epa, bulk_out_epa) \ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (ifc), 0x02, 0x02, 0x02, 0x00, 0x00,\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (ifc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06,\ + (ifc), /* Master interface */\ + (ifc+1), /* Slave interface */\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03,\ + (ifc+1), /* Data interface */\ + /* Interrupt endpoint descriptor 7 bytes */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 15,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (ifc+1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint descriptor 7 bytes */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor 7 bytes */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00, +#define CDC_ACM_IFCES_DESC_ALL_LEN 66 + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR expect_errors = UX_FALSE; + + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN + CDC_ACM_IFCES_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+9+7 =25 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02) + /* HID 9+9 + 9+9+7=43 */ + HID_MOUSE_IFC0_DESC_ALL(1) + HID_MOUSE_IFC1_DESC_ALL(1, 0x83) + /* CDC-ACM */ + CDC_ACM_IFCES_DESC_ALL(2, 0x86, 0x85, 0x04) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN + CDC_ACM_IFCES_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+9+7 =25 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02) + /* HID 9+9 + 9+9+7=43 */ + HID_MOUSE_IFC0_DESC_ALL(1) + HID_MOUSE_IFC1_DESC_ALL(1, 0x83) + /* CDC-ACM */ + CDC_ACM_IFCES_DESC_ALL(2, 0x86, 0x85, 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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Simulation actions. */ + +static UX_TEST_SIM_ENTRY_ACTION dcd_endpoint_create_fail[] = { +/* 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_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ 0 } +}; + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (!expect_errors) + { + if (error_code != UX_DEVICE_HANDLE_UNKNOWN) + { + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } + } +} + +static UINT test_ux_device_class_hid_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + return UX_SUCCESS; + // return _ux_device_class_hid_entry(command); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_stack_configuration_set_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; +UX_SLAVE_CLASS_HID_PARAMETER hid_parameter; + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_configuration_set Test...................... ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_configuration_set Test...................... ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_configuration_set Test...................... ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_configuration_set Test...................... ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = ux_test_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = ux_test_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Initialize the hid class parameters. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_REPORT_LENGTH; + hid_parameter.ux_device_class_hid_parameter_callback = UX_NULL; + hid_parameter.ux_slave_class_hid_instance_activate = UX_NULL; + + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, test_ux_device_class_hid_entry, + 1, 1, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_configuration_set Test...................... ERROR #6\n"); + test_control_return(1); + } +#endif + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_configuration_set Test...................... ERROR #7\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_configuration_set Test...................... ERROR #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test host simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_device_stack_configuration_set Test...................... ERROR #8\n"); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + +UX_SLAVE_DEVICE *device; + + /* Inform user. */ + printf("Running ux_device_stack_configuration_set Test...................... "); + + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Enumeration check. */ + if (dpump_slave == UX_NULL) + { + + printf("ERROR #%d: Enum fail\n", __LINE__); + test_control_return(1); + } + + /* Slave device. */ + device = &_ux_system_slave->ux_system_slave_device; + + /* Expect errors so skip them in error handler. */ + expect_errors = UX_TRUE; + + + /* Break on errors. */ + expect_errors = UX_TRUE; + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static VOID ux_test_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID ux_test_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_device_stack_control_request_process_coverage_test.c b/test/regression/usbx_ux_device_stack_control_request_process_coverage_test.c new file mode 100644 index 00000000..75ee1900 --- /dev/null +++ b/test/regression/usbx_ux_device_stack_control_request_process_coverage_test.c @@ -0,0 +1,56 @@ +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" +#include "ux_test.h" +#include "ux_device_stack.h" +#include "ux_test_utility_sim.h" + + +static UX_SLAVE_TRANSFER transfer_request; +static UX_SYSTEM_SLAVE system_slave; +static UX_SLAVE_CLASS slave_class1; +static UX_SLAVE_INTERFACE slave_interface; + +UINT _test_class_entry(struct UX_SLAVE_CLASS_COMMAND_STRUCT *cmd) +{ + return 0; +} + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_stack_control_request_process_coverage_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status = 0; +UCHAR request_type = UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; +UCHAR request = 0; + + + + /* Inform user. */ + printf("Running USB Device Stack Control Request Process Coverage Test ..... "); + + + _ux_system_slave = &system_slave; + transfer_request.ux_slave_transfer_request_completion_code = UX_SUCCESS; + transfer_request.ux_slave_transfer_request_setup[0] = request_type; + transfer_request.ux_slave_transfer_request_setup[UX_SETUP_REQUEST] = request; + + transfer_request.ux_slave_transfer_request_setup[UX_SETUP_INDEX] = 0; + transfer_request.ux_slave_transfer_request_setup[UX_SETUP_INDEX + 1] = 1; + system_slave.ux_system_slave_interface_class_array[0] = &slave_class1; + slave_class1.ux_slave_class_interface = &slave_interface; + slave_class1.ux_slave_class_entry_function = _test_class_entry; + slave_interface.ux_slave_interface_descriptor.bInterfaceClass = 0x7; + _ux_device_stack_control_request_process(&transfer_request); + + printf("SUCCESS!\n"); + test_control_return(0); + + return; +} diff --git a/test/regression/usbx_ux_device_stack_control_request_process_test.c b/test/regression/usbx_ux_device_stack_control_request_process_test.c new file mode 100644 index 00000000..7c38523b --- /dev/null +++ b/test/regression/usbx_ux_device_stack_control_request_process_test.c @@ -0,0 +1,598 @@ +/* This test is designed to test the ux_device_stack_control_request_process. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +/* HID mouse related descriptors */ + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +#define LSB(x) (x & 0x00ff) +#define MSB(x) ((x & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x20, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors 9+7+7=23 bytes. */ +#define DPUMP_IFC_DESC_ALL(ifc, bulk_in_epa, bulk_out_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x02, 0x99, 0x99, 0x99, 0x00,\ + /* Endpoint descriptor (Bulk Out) */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Bulk In) */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00, +#define DPUMP_IFC_DESC_ALL_LEN 23 + +/* HID Mouse interface descriptors 9+9=18 bytes */ +#define HID_MOUSE_IFC0_DESC_ALL(ifc) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH), +#define HID_MOUSE_IFC0_DESC_ALL_LEN 18 + +/* HID Mouse interface descriptors 9+9+7=25 bytes */ +#define HID_MOUSE_IFC1_DESC_ALL(ifc, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x01, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_MOUSE_IFC1_DESC_ALL_LEN 25 + +/* CDC-ACM interfaces descriptors 8 +9+5+4+5+5+7 +9+7+7=66 bytes */ +#define CDC_ACM_IFCES_DESC_ALL(ifc, interrupt_epa, bulk_in_epa, bulk_out_epa) \ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (ifc), 0x02, 0x02, 0x02, 0x00, 0x00,\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (ifc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06,\ + (ifc), /* Master interface */\ + (ifc+1), /* Slave interface */\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03,\ + (ifc+1), /* Data interface */\ + /* Interrupt endpoint descriptor 7 bytes */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 15,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (ifc+1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint descriptor 7 bytes */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor 7 bytes */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00, +#define CDC_ACM_IFCES_DESC_ALL_LEN 66 + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR expect_errors = UX_FALSE; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN + CDC_ACM_IFCES_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+9+7 =25 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02) + /* HID 9+9 + 9+9+7=43 */ + HID_MOUSE_IFC0_DESC_ALL(1) + HID_MOUSE_IFC1_DESC_ALL(1, 0x83) + /* CDC-ACM */ + CDC_ACM_IFCES_DESC_ALL(2, 0x86, 0x85, 0x04) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN + CDC_ACM_IFCES_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+9+7 =25 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02) + /* HID 9+9 + 9+9+7=43 */ + HID_MOUSE_IFC0_DESC_ALL(1) + HID_MOUSE_IFC1_DESC_ALL(1, 0x83) + /* CDC-ACM */ + CDC_ACM_IFCES_DESC_ALL(2, 0x86, 0x85, 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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Simulation actions. */ + +static UX_TEST_SIM_ENTRY_ACTION dcd_endpoint_create_fail[] = { +/* 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_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ 0 } +}; + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (!expect_errors) + { + if (error_code != UX_DEVICE_HANDLE_UNKNOWN) + { + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %x\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } + } +} + +static UINT test_ux_device_class_hid_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + return UX_SUCCESS; + // return _ux_device_class_hid_entry(command); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_stack_control_request_process_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; +UX_SLAVE_CLASS_HID_PARAMETER hid_parameter; + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_control_request_process Test................ ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_control_request_process Test................ ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_control_request_process Test................ ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_control_request_process Test................ ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = ux_test_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = ux_test_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Initialize the hid class parameters. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_REPORT_LENGTH; + hid_parameter.ux_device_class_hid_parameter_callback = UX_NULL; + hid_parameter.ux_slave_class_hid_instance_activate = UX_NULL; + + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, test_ux_device_class_hid_entry, + 1, 1, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_control_request_process Test................ ERROR #6\n"); + test_control_return(1); + } +#endif + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_control_request_process Test................ ERROR #7\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_control_request_process Test................ ERROR #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test host simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_device_stack_control_request_process Test................ ERROR #8\n"); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + +UINT status; + +UX_SLAVE_DEVICE *slave_device; +UX_SLAVE_ENDPOINT *slave_endpoint; +UX_SLAVE_TRANSFER *slave_transfer_request; + +UX_DEVICE *device; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; + + /* Inform user. */ + printf("Running ux_device_stack_control_request_process Test................ "); + + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Enumeration check. */ + if (dpump_slave == UX_NULL) + { + + printf("ERROR #%d: Enum fail\n", __LINE__); + test_control_return(1); + } + + /* Device. */ + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Expect errors. */ + expect_errors = UX_TRUE; + + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = 0xFF; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_value = 0; + + /* Issue class/vendor request, index 0 - class registered. */ + transfer_request -> ux_transfer_request_index = 0; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED && status != UX_SUCCESS) + { + + printf("ERROR #%d: expect error but got %x\n", __LINE__, status); + error_counter ++; + } + + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED && status != UX_SUCCESS) + { + + printf("ERROR #%d: expect error but got %x\n", __LINE__, status); + error_counter ++; + } + + /* Issue class/vendor request, index 2 - class not registered. */ + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_index = 2; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + + printf("ERROR #%d: expect error but got %x\n", __LINE__, status); + error_counter ++; + } + + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + + printf("ERROR #%d: expect error but got %x\n", __LINE__, status); + error_counter ++; + } + + /* Issue class/vendor request, index 20 - invalid interface. */ + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_index = 20; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + + printf("ERROR #%d: expect error but got %x\n", __LINE__, status); + error_counter ++; + } + + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + + printf("ERROR #%d: expect error but got %x\n", __LINE__, status); + error_counter ++; + } + + /* Slave device. */ + slave_device = &_ux_system_slave->ux_system_slave_device; + /* Device control endpoint. */ + slave_endpoint = &slave_device -> ux_slave_device_control_endpoint; + /* Endpoint transfer request. */ + slave_transfer_request = &slave_endpoint -> ux_slave_endpoint_transfer_request; + + /* Error case: ux_slave_transfer_request_completion_code error. */ + slave_transfer_request->ux_slave_transfer_request_completion_code = UX_ERROR; + status = _ux_device_stack_control_request_process(slave_transfer_request); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: expect error but got %x\n", __LINE__, status); + error_counter ++; + } + + expect_errors = UX_FALSE; + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static VOID ux_test_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID ux_test_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_device_stack_descriptor_send_test.c b/test/regression/usbx_ux_device_stack_descriptor_send_test.c new file mode 100644 index 00000000..b04da6ff --- /dev/null +++ b/test/regression/usbx_ux_device_stack_descriptor_send_test.c @@ -0,0 +1,471 @@ +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; +static UCHAR buffer[UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH * 2]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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, + 0xff, /* Set the length to something very large. */ + 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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +static VOID set_configure_descriptor_length(ULONG length) +{ + device_framework_full_speed[0x12 + 2] = LSB(length); + device_framework_full_speed[0x12 + 3] = MSB(length); + device_framework_high_speed[0x12 + 0x0a + 2] = LSB(length); + device_framework_high_speed[0x12 + 0x0a + 3] = LSB(length); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_stack_descriptor_send_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_device_stack_descriptor_send 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, error code: 0x%x\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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: 0x%x\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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_KEYBOARD *keyboard; +UX_ENDPOINT *endpoint; +UX_TRANSFER *transfer_request; +UCHAR *hid_class_descriptor = device_framework_high_speed + 0x2E; + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + while(1) + { + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + if (hid_client && hid_client -> ux_host_class_hid_client_local_instance != UX_NULL) + break; + + tx_thread_sleep(10); + } + + + + /* Get the keyboard instance */ + keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)hid_client -> ux_host_class_hid_client_local_instance; + + /* Get default endpoint. */ + endpoint = &hid->ux_host_class_hid_device->ux_device_control_endpoint; + + /* Get the transfer request. */ + transfer_request = &endpoint->ux_endpoint_transfer_request; + +#ifdef UX_DEVICE_ENABLE_GET_STRING_WITH_ZERO_LANGUAGE_ID + /************************************************** + * Test case: Get string descriptor with zero language ID. Only tested if UX_DEVICE_ENABLE_GET_STRING_WITH_ZERO_LANGUAGE_ID is defined. + **************************************************/ + string_framework[3] = 12; + /* Create a transfer request for getting the string descriptor with zero . */ + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_requested_length = 64; + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = UX_STRING_DESCRIPTOR_ITEM << 8 | 3; + transfer_request -> ux_transfer_request_index = 0; + + /* Send request to HCD layer. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + string_framework[3] = 0xff; +#endif + + /* Modify configuration descriptor total length to generate error. */ + set_configure_descriptor_length(UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH+1); + + /************************************************** + * Test case: 'case: UX_OTHER_SPEED_DESCRIPTOR_ITEM' + * 'if (length > UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH)' + **************************************************/ + + /* Create a transfer request for the HID class descriptor. */ + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_requested_length = UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH+1; + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = UX_OTHER_SPEED_DESCRIPTOR_ITEM << 8; + transfer_request -> ux_transfer_request_index = 0; + + /* Send request to HCD layer. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status == UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /************************************************** + * Test case: 'case: UX_CONFIGURATION_DESCRIPTOR_ITEM' + * 'if (length > UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH)' + **************************************************/ + + /* Create a transfer request for the HID class descriptor. */ + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_requested_length = UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH+1; + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = UX_CONFIGURATION_DESCRIPTOR_ITEM << 8; + transfer_request -> ux_transfer_request_index = 0; + + /* Send request to HCD layer. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status == UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /************************************************** + * Test case: language ID framework is too large for device to send. + **************************************************/ + + /* Make the language ID framework too large. */ + _ux_system_slave->ux_system_slave_language_id_framework_length = UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH + 1; + + /* Create a transfer request for the HID class descriptor. */ + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_requested_length = 0xffff; + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = UX_STRING_DESCRIPTOR_ITEM << 8 | 0; + transfer_request -> ux_transfer_request_index = 0; + + /* Send request to HCD layer. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status == UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /************************************************** + * 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 +#else + + /* Make the language ID framework too large. */ + _ux_system_slave->ux_system_slave_language_id_framework_length = UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH + 1; + + /* Create a transfer request for the HID class descriptor. */ + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_requested_length = 0xffff; + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = UX_STRING_DESCRIPTOR_ITEM << 8 | 1; + transfer_request -> ux_transfer_request_index = 0x0409; + + /* Send request to HCD layer. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status == UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } +#endif + + /* 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_device_stack_endpoint_stall_test.c b/test/regression/usbx_ux_device_stack_endpoint_stall_test.c new file mode 100644 index 00000000..d721b1e9 --- /dev/null +++ b/test/regression/usbx_ux_device_stack_endpoint_stall_test.c @@ -0,0 +1,478 @@ +/* This test is designed to test the ux_device_stack_endpoint_stall. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +/* HID mouse related descriptors */ + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +#define LSB(x) (x & 0x00ff) +#define MSB(x) ((x & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors 9+7+7=23 bytes. */ +#define DPUMP_IFC_DESC_ALL(ifc, bulk_in_epa, bulk_out_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x02, 0x99, 0x99, 0x99, 0x00,\ + /* Endpoint descriptor (Bulk Out) */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Bulk In) */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00, +#define DPUMP_IFC_DESC_ALL_LEN 23 + +/* HID Mouse interface descriptors 9+9=18 bytes */ +#define HID_MOUSE_IFC0_DESC_ALL(ifc) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH), +#define HID_MOUSE_IFC0_DESC_ALL_LEN 18 + +/* HID Mouse interface descriptors 9+9+7=25 bytes */ +#define HID_MOUSE_IFC1_DESC_ALL(ifc, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x01, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_MOUSE_IFC1_DESC_ALL_LEN 25 + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR expect_errors = UX_FALSE; + + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + 2*DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+9+7 =25 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02) + DPUMP_IFC_DESC_ALL(1, 0x83, 0x04) + /* HID 9+9 + 9+9+7=43 */ + HID_MOUSE_IFC0_DESC_ALL(2) + HID_MOUSE_IFC1_DESC_ALL(2, 0x85) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + CFG_DESC(CFG_DESC_LEN + 2*DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+9+7 =25 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02) + DPUMP_IFC_DESC_ALL(1, 0x83, 0x04) + /* HID 9+9 + 9+9+7=43 */ + HID_MOUSE_IFC0_DESC_ALL(2) + HID_MOUSE_IFC1_DESC_ALL(2, 0x85) +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (!expect_errors) + { + if (error_code != UX_DEVICE_HANDLE_UNKNOWN) + { + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } + } +} + +static UINT test_ux_device_class_hid_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + return UX_SUCCESS; + // return _ux_device_class_hid_entry(command); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_stack_endpoint_stall_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; +UX_SLAVE_CLASS_HID_PARAMETER hid_parameter; + + + /* Inform user. */ + printf("Running ux_device_stack_endpoint_stall Test......................... "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = ux_test_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = ux_test_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 1, ¶meter); + + /* Initialize the hid class parameters. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_REPORT_LENGTH; + hid_parameter.ux_device_class_hid_parameter_callback = UX_NULL; + hid_parameter.ux_slave_class_hid_instance_activate = UX_NULL; + + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, test_ux_device_class_hid_entry, + 1, 2, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #6\n"); + test_control_return(1); + } +#endif + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #7\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test host simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #8\n"); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + +UINT status; +UX_SLAVE_DEVICE *device; +UX_SLAVE_INTERFACE *interface; +UX_SLAVE_ENDPOINT *endpoint; + + + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Enumeration check. */ + if (dpump_slave == UX_NULL) + { + printf("ERROR #%d: Enum fail\n", __LINE__); + test_control_return(1); + } + + /* Slave device. */ + device = &_ux_system_slave->ux_system_slave_device; + + /* Confirm first interfaces are connected. */ + interface = device->ux_slave_device_first_interface; + + /* Get endpoint. */ + endpoint = interface->ux_slave_interface_first_endpoint; + + if (endpoint == UX_NULL) + { + printf("ERROR #%d: endpoint not available\n", __LINE__); + test_control_return(1); + } + + ux_test_hcd_sim_host_disconnect(); + ux_test_dcd_sim_slave_disconnect(); + + status = ux_device_stack_endpoint_stall(endpoint); + if (status != UX_ERROR) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + error_counter ++; + } + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static VOID ux_test_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID ux_test_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_device_stack_get_status_test.c b/test/regression/usbx_ux_device_stack_get_status_test.c new file mode 100644 index 00000000..2c83db09 --- /dev/null +++ b/test/regression/usbx_ux_device_stack_get_status_test.c @@ -0,0 +1,515 @@ +/* This test is designed to test the ux_device_stack_get_status. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +/* HID mouse related descriptors */ + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +#define LSB(x) (x & 0x00ff) +#define MSB(x) ((x & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x00, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors 9+7+7+7+7=37 bytes. */ +#define DPUMP_IFC_DESC_ALL(ifc, bulk_in_epa, bulk_out_epa, int_in_epa, int_out_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x04, 0x99, 0x99, 0x99, 0x00,\ + /* Endpoint descriptor (Bulk Out) */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Bulk In) */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Interrupt Out) */\ + 0x07, 0x05, (int_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Interrupt In) */\ + 0x07, 0x05, (int_in_epa), 0x02, 0x40, 0x00, 0x00, +#define DPUMP_IFC_DESC_ALL_LEN 37 + +/* HID Mouse interface descriptors 9+9=18 bytes */ +#define HID_MOUSE_IFC0_DESC_ALL(ifc) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH), +#define HID_MOUSE_IFC0_DESC_ALL_LEN 18 + +/* HID Mouse interface descriptors 9+9+7=25 bytes */ +#define HID_MOUSE_IFC1_DESC_ALL(ifc, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x01, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_MOUSE_IFC1_DESC_ALL_LEN 25 + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR expect_errors = UX_FALSE; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+7+7+7+7 =37 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02, 0x83, 0x04) + /* HID 9+9 + 9+9+7=43 */ + HID_MOUSE_IFC0_DESC_ALL(1) + HID_MOUSE_IFC1_DESC_ALL(1, 0x85) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+7+7+7+7 =37 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02, 0x83, 0x04) + /* HID 9+9 + 9+9+7=43 */ + HID_MOUSE_IFC0_DESC_ALL(1) + HID_MOUSE_IFC1_DESC_ALL(1, 0x85) +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Simulation actions. */ + +static UX_TEST_SIM_ENTRY_ACTION dcd_endpoint_status_fail[] = { +/* 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_DCD_ENDPOINT_STATUS, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ 0 } +}; + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (!expect_errors) + { + if (error_code != UX_DEVICE_HANDLE_UNKNOWN) + { + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } + } +} + +static UINT test_ux_device_class_hid_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + return UX_SUCCESS; + // return _ux_device_class_hid_entry(command); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_stack_get_status_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; +UX_SLAVE_CLASS_HID_PARAMETER hid_parameter; + + printf("Running ux_device_stack_get_status Test............................. "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = ux_test_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = ux_test_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Initialize the hid class parameters. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_REPORT_LENGTH; + hid_parameter.ux_device_class_hid_parameter_callback = UX_NULL; + hid_parameter.ux_slave_class_hid_instance_activate = UX_NULL; + + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, test_ux_device_class_hid_entry, + 1, 1, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #6\n"); + test_control_return(1); + } +#endif + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #7\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test host simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #8\n"); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + +UINT status; +UX_DEVICE *device; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; + + /* Inform user. */ + + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Enumeration check. */ + if (dpump_slave == UX_NULL) + { + + printf("ERROR #%d: Enum fail\n", __LINE__); + test_control_return(1); + } + + /* Get device, control endpoint and transfer request. */ + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Issue GetDeviceStatus. */ + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_requested_length = 64; + transfer_request -> ux_transfer_request_function = UX_GET_STATUS; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = 0; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: GetDeviceStatus fail\n", __LINE__); + error_counter ++; + } + if (buffer[0] != 0) + { + + printf("ERROR #%d: GetDeviceStatus %x but expect 0\n", __LINE__, buffer[0]); + error_counter ++; + } + + expect_errors = UX_TRUE; + + /* Issue GetEndpointStatus. */ + ux_test_dcd_sim_slave_set_actions(dcd_endpoint_status_fail); + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_ENDPOINT; + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = 0x81; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + + printf("ERROR #%d: GetEndpointStatus(0x81) expect UX_TRANSFER_STALLED but got 0x%x\n", __LINE__, status); + error_counter ++; + } + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static VOID ux_test_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID ux_test_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_device_stack_initialize_test.c b/test/regression/usbx_ux_device_stack_initialize_test.c new file mode 100644 index 00000000..3ee634cc --- /dev/null +++ b/test/regression/usbx_ux_device_stack_initialize_test.c @@ -0,0 +1,264 @@ +/* This test is designed to test the ux_device_stack_initialize */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +/* HID mouse related descriptors */ + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +#define LSB(x) (x & 0x00ff) +#define MSB(x) ((x & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x20, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors 9+7+7=23 bytes. */ +#define DPUMP_IFC_DESC_ALL(ifc, bulk_in_epa, bulk_out_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x02, 0x99, 0x99, 0x99, 0x00,\ + /* Endpoint descriptor (Bulk Out) */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Bulk In) */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00, +#define DPUMP_IFC_DESC_ALL_LEN 23 + +/* HID Mouse interface descriptors 9+9=18 bytes */ +#define HID_MOUSE_IFC0_DESC_ALL(ifc) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH), +#define HID_MOUSE_IFC0_DESC_ALL_LEN 18 + +/* HID Mouse interface descriptors 9+9+7=25 bytes */ +#define HID_MOUSE_IFC1_DESC_ALL(ifc, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x01, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_MOUSE_IFC1_DESC_ALL_LEN 25 + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+9+7 =25 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02) + /* HID 9+9 + 9+9+7=43 */ + HID_MOUSE_IFC0_DESC_ALL(0x11) + HID_MOUSE_IFC1_DESC_ALL(0x11, 0x83) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN, 2, 1) + /* DPUMP */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02) + /* HID */ + HID_MOUSE_IFC0_DESC_ALL(0x11) + HID_MOUSE_IFC1_DESC_ALL(0x11, 0x83) +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Simulation actions. */ + +static UX_TEST_SIM_ENTRY_ACTION dcd_endpoint_create_fail[] = { +/* 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_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ 0 } +}; + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_stack_initialize_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; +UX_SLAVE_CLASS_HID_PARAMETER hid_parameter; + + + /* Inform user. */ + printf("Running ux_device_stack_initialize Test.................. "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + +#if !defined(UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE) && (UX_MAX_SLAVE_INTERFACE <= 16) + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status == UX_MEMORY_INSUFFICIENT) { + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } else { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#else + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +#endif +} diff --git a/test/regression/usbx_ux_device_stack_interface_delete_test.c b/test/regression/usbx_ux_device_stack_interface_delete_test.c new file mode 100644 index 00000000..5bab843d --- /dev/null +++ b/test/regression/usbx_ux_device_stack_interface_delete_test.c @@ -0,0 +1,491 @@ +/* This test is designed to test the ux_device_stack_interface_delete. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +/* HID mouse related descriptors */ + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +#define LSB(x) (x & 0x00ff) +#define MSB(x) ((x & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors 9+7+7=23 bytes. */ +#define DPUMP_IFC_DESC_ALL(ifc, bulk_in_epa, bulk_out_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x02, 0x99, 0x99, 0x99, 0x00,\ + /* Endpoint descriptor (Bulk Out) */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Bulk In) */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00, +#define DPUMP_IFC_DESC_ALL_LEN 23 + +/* HID Mouse interface descriptors 9+9=18 bytes */ +#define HID_MOUSE_IFC0_DESC_ALL(ifc) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH), +#define HID_MOUSE_IFC0_DESC_ALL_LEN 18 + +/* HID Mouse interface descriptors 9+9+7=25 bytes */ +#define HID_MOUSE_IFC1_DESC_ALL(ifc, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x01, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_MOUSE_IFC1_DESC_ALL_LEN 25 + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR expect_errors = UX_FALSE; + + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + 2*DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+9+7 =25 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02) + DPUMP_IFC_DESC_ALL(1, 0x83, 0x04) + /* HID 9+9 + 9+9+7=43 */ + HID_MOUSE_IFC0_DESC_ALL(2) + HID_MOUSE_IFC1_DESC_ALL(2, 0x85) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + CFG_DESC(CFG_DESC_LEN + 2*DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+9+7 =25 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02) + DPUMP_IFC_DESC_ALL(1, 0x83, 0x04) + /* HID 9+9 + 9+9+7=43 */ + HID_MOUSE_IFC0_DESC_ALL(2) + HID_MOUSE_IFC1_DESC_ALL(2, 0x85) +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (!expect_errors) + { + if (error_code != UX_DEVICE_HANDLE_UNKNOWN) + { + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } + } +} + +static UINT test_ux_device_class_hid_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + return UX_SUCCESS; + // return _ux_device_class_hid_entry(command); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_stack_interface_delete_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; +UX_SLAVE_CLASS_HID_PARAMETER hid_parameter; + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_interface_delete Test....................... ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_interface_delete Test....................... ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_interface_delete Test....................... ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_interface_delete Test....................... ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = ux_test_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = ux_test_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 1, ¶meter); + + /* Initialize the hid class parameters. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_REPORT_LENGTH; + hid_parameter.ux_device_class_hid_parameter_callback = UX_NULL; + hid_parameter.ux_slave_class_hid_instance_activate = UX_NULL; + + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, test_ux_device_class_hid_entry, + 1, 2, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_interface_delete Test....................... ERROR #6\n"); + test_control_return(1); + } +#endif + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_interface_delete Test....................... ERROR #7\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_interface_delete Test....................... ERROR #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test host simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_device_stack_interface_delete Test....................... ERROR #8\n"); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + +UX_SLAVE_DEVICE *device; +UX_SLAVE_INTERFACE *interface; +UX_SLAVE_INTERFACE *interfaces[3]; +INT i; + + /* Inform user. */ + printf("Running ux_device_stack_interface_delete Test....................... "); + + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Enumeration check. */ + if (dpump_slave == UX_NULL) + { + + printf("ERROR #%d: Enum fail\n", __LINE__); + test_control_return(1); + } +#if UX_TEST_MULTI_IFC_ON + /* Slave device. */ + device = &_ux_system_slave->ux_system_slave_device; + + /* Confirm at least 3 interfaces are connected. */ + interface = device->ux_slave_device_first_interface; + for (i = 0; i < 3; i ++) + { + + if (interface) + { + + interfaces[i] = interface; + interface = interface->ux_slave_interface_next_interface; + } + else + break; + } + if (i < 3) + { + + printf("ERROR #%d: expect 3 interfaces or more\n", __LINE__); + test_control_return(1); + } +#endif +#if 0 /* USBX-102 we are not supporting this case (delete from tail). */ + /* Delete interface from last one. */ + for (; i; i --) + { + + interface = interfaces[i - 1]; + status = _ux_device_stack_interface_delete(interface); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: interface %d delete fail\n", __LINE__, i); + error_counter ++; + } + } +#endif + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static VOID ux_test_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID ux_test_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_device_stack_interface_set_test.c b/test/regression/usbx_ux_device_stack_interface_set_test.c new file mode 100644 index 00000000..12c45bb5 --- /dev/null +++ b/test/regression/usbx_ux_device_stack_interface_set_test.c @@ -0,0 +1,545 @@ +/* This test is designed to test the ux_device_stack_interface_set. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +/* HID mouse related descriptors */ + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +#define LSB(x) (x & 0x00ff) +#define MSB(x) ((x & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors 9+7+7+7+7=37 bytes. */ +#define DPUMP_IFC_DESC_ALL(ifc, bulk_in_epa, bulk_out_epa, int_in_epa, int_out_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x04, 0x99, 0x99, 0x99, 0x00,\ + /* Endpoint descriptor (Bulk Out) */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Bulk In) */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Interrupt Out) */\ + 0x07, 0x05, (int_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Interrupt In) */\ + 0x07, 0x05, (int_in_epa), 0x02, 0x40, 0x00, 0x00, +#define DPUMP_IFC_DESC_ALL_LEN 37 + +/* HID Mouse interface descriptors 9+9=18 bytes */ +#define HID_MOUSE_IFC0_DESC_ALL(ifc) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH), +#define HID_MOUSE_IFC0_DESC_ALL_LEN 18 + +/* HID Mouse interface descriptors 9+9+7=25 bytes */ +#define HID_MOUSE_IFC1_DESC_ALL(ifc, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x01, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_MOUSE_IFC1_DESC_ALL_LEN 25 + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR expect_errors = UX_FALSE; + + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+7+7+7+7 =37 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02, 0x83, 0x04) + /* HID 9+9 + 9+9+7=43 */ + HID_MOUSE_IFC0_DESC_ALL(1) + HID_MOUSE_IFC1_DESC_ALL(1, 0x85) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+7+7+7+7 =37 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02, 0x83, 0x04) + /* HID 9+9 + 9+9+7=43 */ + HID_MOUSE_IFC0_DESC_ALL(1) + HID_MOUSE_IFC1_DESC_ALL(1, 0x85) +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Simulation actions. */ + +static UX_TEST_SIM_ENTRY_ACTION dcd_endpoint_create_fail[] = { +/* 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_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_SUCCESS , UX_NULL, + UX_TRUE}, +{ UX_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ UX_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ UX_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ UX_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ 0 } +}; + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (!expect_errors) + { + if (error_code != UX_DEVICE_HANDLE_UNKNOWN) + { + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } + } +} + +static UINT test_ux_device_class_hid_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + return UX_SUCCESS; + // return _ux_device_class_hid_entry(command); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_stack_interface_set_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; +UX_SLAVE_CLASS_HID_PARAMETER hid_parameter; + +#if !(UX_TEST_MULTI_IFC_ON) + printf("Running ux_device_stack_interface_set Test.......................... SKIP!"); + test_control_return(0); + return; +#endif + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_interface_set Test.......................... ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_interface_set Test.......................... ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_interface_set Test.......................... ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_interface_set Test.......................... ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = ux_test_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = ux_test_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Initialize the hid class parameters. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_REPORT_LENGTH; + hid_parameter.ux_device_class_hid_parameter_callback = UX_NULL; + hid_parameter.ux_slave_class_hid_instance_activate = UX_NULL; + + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, test_ux_device_class_hid_entry, + 1, 1, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_interface_set Test.......................... ERROR #6\n"); + test_control_return(1); + } +#endif + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_interface_set Test.......................... ERROR #7\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_interface_set Test.......................... ERROR #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test host simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_device_stack_interface_set Test.......................... ERROR #8\n"); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + +UINT status; +UX_SLAVE_DEVICE *device; +ULONG endpoints_pool_number; + + /* Inform user. */ + printf("Running ux_device_stack_interface_set Test.......................... "); + + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Enumeration check. */ + if (dpump_slave == UX_NULL) + { + + printf("ERROR #%d: Enum fail\n", __LINE__); + test_control_return(1); + } + + /* Slave device. */ + device = &_ux_system_slave->ux_system_slave_device; + + /* Expect errors so skip them in error handler. */ + expect_errors = UX_TRUE; + + /* Unconfigure. */ + status = _ux_device_stack_configuration_set(0); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: Unconfigure fail\n", __LINE__); + test_control_return(1); + } + + /* Limit endpoints pool to generate error. */ + endpoints_pool_number = device->ux_slave_device_endpoints_pool_number; + device->ux_slave_device_endpoints_pool_number = 0; + + /* Configure. */ + status = _ux_device_stack_configuration_set(1); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: Configure fail code %x\n", __LINE__, status); + test_control_return(1); + } + device->ux_slave_device_endpoints_pool_number = endpoints_pool_number; + + /* Unconfigure. */ + status = _ux_device_stack_configuration_set(0); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: Unconfigure fail\n", __LINE__); + test_control_return(1); + } + + /* Endpoint creation fail on other than EP0. */ + ux_test_dcd_sim_slave_set_actions(dcd_endpoint_create_fail); + + /* Configure. */ + status = _ux_device_stack_configuration_set(1); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: Configure fail code %x\n", __LINE__, status); + test_control_return(1); + } + + /* No actions. */ + ux_test_dcd_sim_slave_set_actions(UX_NULL); + + /* Break on errors. */ + expect_errors = UX_TRUE; + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static VOID ux_test_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID ux_test_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_device_stack_interface_start_test.c b/test/regression/usbx_ux_device_stack_interface_start_test.c new file mode 100644 index 00000000..3e325eab --- /dev/null +++ b/test/regression/usbx_ux_device_stack_interface_start_test.c @@ -0,0 +1,504 @@ +/* This test is designed to test the ux_device_stack_interface_start. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +/* HID mouse related descriptors */ + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +#define LSB(x) (x & 0x00ff) +#define MSB(x) ((x & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors 9+7+7+7+7=37 bytes. */ +#define DPUMP_IFC_DESC_ALL(ifc, bulk_in_epa, bulk_out_epa, int_in_epa, int_out_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x04, 0x99, 0x99, 0x99, 0x00,\ + /* Endpoint descriptor (Bulk Out) */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Bulk In) */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Interrupt Out) */\ + 0x07, 0x05, (int_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Interrupt In) */\ + 0x07, 0x05, (int_in_epa), 0x02, 0x40, 0x00, 0x00, +#define DPUMP_IFC_DESC_ALL_LEN 37 + +/* HID Mouse interface descriptors 9+9=18 bytes */ +#define HID_MOUSE_IFC0_DESC_ALL(ifc) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH), +#define HID_MOUSE_IFC0_DESC_ALL_LEN 18 + +/* HID Mouse interface descriptors 9+9+7=25 bytes */ +#define HID_MOUSE_IFC1_DESC_ALL(ifc, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x01, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_MOUSE_IFC1_DESC_ALL_LEN 25 + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR expect_errors = UX_FALSE; + + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+7+7+7+7 =37 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02, 0x83, 0x04) + /* HID 9+9 + 9+9+7=43 */ + HID_MOUSE_IFC0_DESC_ALL(1) + HID_MOUSE_IFC1_DESC_ALL(1, 0x85) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+7+7+7+7 =37 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02, 0x83, 0x04) + /* HID 9+9 + 9+9+7=43 */ + HID_MOUSE_IFC0_DESC_ALL(1) + HID_MOUSE_IFC1_DESC_ALL(1, 0x85) +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Simulation actions. */ + +static UX_TEST_SIM_ENTRY_ACTION dcd_endpoint_create_fail[] = { +/* 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_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_SUCCESS , UX_NULL, + UX_TRUE}, +{ UX_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ UX_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ UX_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ UX_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ 0 } +}; + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (!expect_errors) + { + if (error_code != UX_DEVICE_HANDLE_UNKNOWN) + { + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } + } +} + +static UINT test_ux_device_class_hid_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + switch(command->ux_slave_class_command_request) + { + case UX_SLAVE_CLASS_COMMAND_INITIALIZE: + case UX_SLAVE_CLASS_COMMAND_QUERY: + return UX_SUCCESS; + + default: + return UX_NO_CLASS_MATCH; + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_stack_interface_start_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; +UX_SLAVE_CLASS_HID_PARAMETER hid_parameter; + + +#if !(UX_TEST_MULTI_IFC_ON) + printf("Running ux_device_stack_interface_start Test........................ SKIP!"); + test_control_return(0); + return; +#endif + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_interface_start Test........................ ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_interface_start Test........................ ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_interface_start Test........................ ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_interface_start Test........................ ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = ux_test_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = ux_test_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Initialize the hid class parameters. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_REPORT_LENGTH; + hid_parameter.ux_device_class_hid_parameter_callback = UX_NULL; + hid_parameter.ux_slave_class_hid_instance_activate = UX_NULL; + + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, test_ux_device_class_hid_entry, + 1, 1, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_interface_start Test........................ ERROR #6\n"); + test_control_return(1); + } +#endif + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_interface_start Test........................ ERROR #7\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_device_stack_interface_start Test........................ ERROR #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test host simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_device_stack_interface_start Test........................ ERROR #8\n"); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + +UX_SLAVE_DEVICE *device; + + /* Inform user. */ + printf("Running ux_device_stack_interface_start Test........................ "); + + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Enumeration check. */ + if (dpump_slave == UX_NULL) + { + + printf("ERROR #%d: Enum fail\n", __LINE__); + test_control_return(1); + } + + /* Slave device. */ + device = &_ux_system_slave->ux_system_slave_device; + + /* Expect errors so skip them in error handler. */ + expect_errors = UX_TRUE; + + /* Break on errors. */ + expect_errors = UX_FALSE; + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static VOID ux_test_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID ux_test_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_device_stack_remote_wakeup_test.c b/test/regression/usbx_ux_device_stack_remote_wakeup_test.c new file mode 100644 index 00000000..a9391674 --- /dev/null +++ b/test/regression/usbx_ux_device_stack_remote_wakeup_test.c @@ -0,0 +1,741 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" + +#include "ux_host_class_cdc_acm.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#include "ux_host_stack.h" + +/* Define constants. */ +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bmAttributes, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + (bmAttributes), 0x00, +#define CFG_DESC_LEN 9 + +#define IAD_DESC(bIfc) \ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (bIfc), 0x02, 0x02, 0x02, 0x00, 0x00, +#define IAD_DESC_LEN 8 + +#define CDC_IFC_DESC_ALL(bIfc, bIntIn, bBulkIn, bBulkOut)\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (bIfc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06, (bIfc), (bIfc + 1),\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03, (bIfc + 1),\ + /* Endpoint interrupt in descriptor 7 bytes */\ + 0x07, 0x05, (bIntIn), 0x03, 0x40, 0x00, 0x10,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (bIfc + 1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint bulk in descriptor 7 bytes */\ + 0x07, 0x05, (bBulkIn), 0x02, 0x40, 0x00, 0x01,\ + /* Endpoint bulk out descriptor 7 bytes */\ + 0x07, 0x05, (bBulkOut), 0x02, 0x40, 0x00, 0x01, +#define CDC_IFC_DESC_ALL_LEN (9+5+4+5+5+7+ 9+7+7) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +static UCHAR cdc_acm_slave_change; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; + +static ULONG error_counter; + +static ULONG error_callback_counter; +static UCHAR error_callback_ignore; + +static ULONG call_counter; + +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +/* Define device framework. */ + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Configuration 1 descriptor 9 bytes, total 75 bytes */ + CFG_DESC(CFG_DESC_LEN + IAD_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 0x40, 1) + /* IAD 8 bytes */ + IAD_DESC(0) + /* CDC_ACM interfaces */ + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor 10 bytes */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor 9 bytes, total 75-8=67 bytes */ + CFG_DESC(CFG_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 0x60, 1) + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +/* DCD simulator. */ + +static VOID UX_DCD_CHANGE_STATE_is_called(UX_TEST_ACTION *action, VOID *_params) +{ + call_counter ++; +} + +static UX_TEST_DCD_SIM_ACTION monitor_UX_DCD_CHANGE_STATE[] = { +/* 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_DCD_CHANGE_STATE, NULL, + UX_FALSE, 0, + 0, 0, UX_NULL, 0, 0, + UX_SUCCESS, UX_DCD_CHANGE_STATE_is_called}, +{ 0 } +}; + +static UINT break_on_cdc_acm_all_ready(VOID) +{ +UINT status; +UINT i; +UX_HOST_CLASS *class; +UX_HOST_CLASS_CDC_ACM *cdc_acm; + + /* Find the main cdc_acm container */ + status = ux_host_stack_class_get(_ux_system_host_class_cdc_acm_name, &class); + if (status != UX_SUCCESS) + /* Do not break. */ + return 0; + + /* Find class instances. */ + for (i = 0; i < 2; i ++) + { + status = ux_host_stack_class_instance_get(class, i, (void **) &cdc_acm); + if (status != UX_SUCCESS) + /* Do not break. */ + return 0; + + switch(cdc_acm->ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass) + { + + case UX_HOST_CLASS_CDC_CONTROL_CLASS: + cdc_acm_host_control = cdc_acm; + break; + + case UX_HOST_CLASS_CDC_DATA_CLASS: + cdc_acm_host_data = cdc_acm; + break; + + default: + break; + } + } + + if (cdc_acm_host_control == UX_NULL || cdc_acm_host_data == UX_NULL) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_host_data->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_slave == UX_NULL) + /* Do not break. */ + return 0; + + /* All found, break. */ + return 1; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + cdc_acm_host_data = UX_NULL; + cdc_acm_host_control = UX_NULL; + + return 1; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; +} + +static VOID test_ux_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); + } + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_stack_remote_wakeup_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + printf("Running ux_device_stack_ Remote Wakeup 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register CDC ACM class */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_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); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 2,0, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 3,0, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#endif + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register HCD for test */ + 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(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_DEVICE *device; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; + + stepinfo("\n"); + + /* Test connect. */ + stepinfo(">>>>>>>>>>>>>>>> Test connect (FS)\n"); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + ux_test_breakable_sleep(100, break_on_cdc_acm_all_ready); + if (!(cdc_acm_host_control && cdc_acm_host_data && cdc_acm_slave)) + { + + printf("ERROR #%d: connect fail\n", __LINE__); + test_control_return(1); + } + + /* Get device instance. */ + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Build transfer request. */ + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_index = 0; + + error_callback_ignore = UX_TRUE; + + stepinfo(">>>>>>>>>>>>>>>> GetDeviceStatus(), no error\n"); + + transfer_request -> ux_transfer_request_function = UX_GET_STATUS; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_requested_length = 2; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: GetDeviceStatus() code 0x%x\n", __LINE__, status); + error_counter ++; + } + + stepinfo(">>>>>>>>>>>>>>>> SetDeviceFeature(DEVICE_REMOTE_WAKEUP), error\n"); + + transfer_request -> ux_transfer_request_function = UX_SET_FEATURE; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = 1; + transfer_request -> ux_transfer_request_requested_length = 0; + status = ux_host_stack_transfer_request(transfer_request); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: SetDeviceFeature(DEVICE_REMOTE_WAKEUP) code 0x%x\n", __LINE__, status); + error_counter ++; + } + + stepinfo(">>>>>>>>>>>>>>>> ClearDeviceFeature(DEVICE_REMOTE_WAKEUP), error\n"); + + transfer_request -> ux_transfer_request_function = UX_CLEAR_FEATURE; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = 1; + status = ux_host_stack_transfer_request(transfer_request); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: ClearDeviceFeature(DEVICE_REMOTE_WAKEUP) code 0x%x\n", __LINE__, status); + error_counter ++; + } + + stepinfo(">>>>>>>>>>>>>>>> Test connect (HS)\n"); + + ux_test_hcd_sim_host_disconnect(); + ux_test_dcd_sim_slave_disconnect(); + ux_test_breakable_sleep(100, break_on_removal); + + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + ux_test_breakable_sleep(100, break_on_cdc_acm_all_ready); + + if (!(cdc_acm_host_control && cdc_acm_host_data && cdc_acm_slave)) + { + + printf("ERROR #%d: connect fail\n", __LINE__); + test_control_return(1); + } + + /* Get device instance. */ + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Build transfer request. */ + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_index = 0; + + stepinfo(">>>>>>>>>>>>>>>> SetDeviceFeature(DEVICE_REMOTE_WAKEUP), OK\n"); + + transfer_request -> ux_transfer_request_function = UX_SET_FEATURE; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = 1; + transfer_request -> ux_transfer_request_requested_length = 0; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: SetDeviceFeature(DEVICE_REMOTE_WAKEUP) code 0x%x\n", __LINE__, status); + error_counter ++; + } + + stepinfo(">>>>>>>>>>>>>>>> GetDeviceStatus(), 0x02 - remote wakeup enabled\n"); + + transfer_request -> ux_transfer_request_function = UX_GET_STATUS; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_requested_length = 2; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: GetDeviceStatus() code 0x%x\n", __LINE__, status); + error_counter ++; + } + if ((buffer[0] & 0x02u) == 0) + { + + printf("ERROR #%d: remote wakeup disabled\n", __LINE__); + error_counter ++; + } + + stepinfo(">>>>>>>>>>>>>>>> _ux_device_stack_host_wakeup(), UX_DCD_CHANGE_STATE called, OK\n"); + + call_counter = 0; + ux_test_dcd_sim_slave_set_actions(monitor_UX_DCD_CHANGE_STATE); + status = _ux_device_stack_host_wakeup(); + if (call_counter == 0) + { + + printf("ERROR #%d: UX_DCD_CHANGE_STATE not called\n", __LINE__); + error_counter ++; + } + + stepinfo(">>>>>>>>>>>>>>>> ClearDeviceFeature(DEVICE_REMOTE_WAKEUP), OK\n"); + + transfer_request -> ux_transfer_request_function = UX_CLEAR_FEATURE; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = 1; + transfer_request -> ux_transfer_request_requested_length = 0; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: ClearDeviceFeature(DEVICE_REMOTE_WAKEUP) code 0x%x\n", __LINE__, status); + error_counter ++; + } + + stepinfo(">>>>>>>>>>>>>>>> GetDeviceStatus(), 0x02 - remote wakeup disabled\n"); + + transfer_request -> ux_transfer_request_function = UX_GET_STATUS; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_requested_length = 2; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: GetDeviceStatus() code 0x%x\n", __LINE__, status); + error_counter ++; + } + if ((buffer[0] & 0x02u) != 0) + { + + printf("ERROR #%d: remote wakeup enabled\n", __LINE__); + error_counter ++; + } + + stepinfo(">>>>>>>>>>>>>>>> _ux_device_stack_host_wakeup(), UX_DCD_CHANGE_STATE not called, fail\n"); + + call_counter = 0; + ux_test_dcd_sim_slave_set_actions(monitor_UX_DCD_CHANGE_STATE); + status = _ux_device_stack_host_wakeup(); + if (status == 0) + { + + printf("ERROR #%d: expect fail\n", __LINE__); + error_counter ++; + } + if (call_counter > 0) + { + + printf("ERROR #%d: UX_DCD_CHANGE_STATE called\n", __LINE__); + error_counter ++; + } + + error_callback_ignore = UX_FALSE; + + stepinfo(">>>>>>>>>>>>>>>> Deinitialize\n"); + + /* Deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + + /* Deinitialize the device side of usbx. */ + _ux_device_stack_uninitialize(); + + /* And finally the usbx system resources. */ + _ux_system_uninitialize(); + + stepinfo(">>>>>>>>>>>>>>>> Dump results\n"); + + if (error_counter > 0) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + +void tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Sleep so ThreadX on Win32 will delete this thread. */ + ux_utility_delay_ms(100); + } +} diff --git a/test/regression/usbx_ux_device_stack_set_feature_test.c b/test/regression/usbx_ux_device_stack_set_feature_test.c new file mode 100644 index 00000000..bd9aa856 --- /dev/null +++ b/test/regression/usbx_ux_device_stack_set_feature_test.c @@ -0,0 +1,590 @@ +/* This test is designed to test the ux_device_stack_transfer_request. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +/* HID mouse related descriptors */ + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +#define LSB(x) (x & 0x00ff) +#define MSB(x) ((x & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors 9+7+7+7=30 bytes. */ +#define DPUMP_IFC_DESC_ALL(ifc, bulk_in_epa, bulk_out_epa, int_in_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x03, 0x99, 0x99, 0x99, 0x00,\ + /* Endpoint descriptor (Bulk Out) */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Bulk In) */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Interrupt In) */\ + 0x07, 0x05, (int_in_epa), 0x02, 0x40, 0x00, 0x00, +#define DPUMP_IFC_DESC_ALL_LEN 30 + +/* HID Mouse interface descriptors 9+9+7=25 bytes */ +#define HID_MOUSE_IFC_DESC_ALL(ifc, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x01, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_MOUSE_IFC_DESC_ALL_LEN 25 + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR expect_errors = UX_FALSE; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+7+7+7 =30 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02, 0x83) + /* HID 9+9+7 =25 */ + HID_MOUSE_IFC_DESC_ALL(1, 0x84) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+7+7+7 =30 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02, 0x83) + /* HID 9+9+7 =25 */ + HID_MOUSE_IFC_DESC_ALL(1, 0x84) +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Simulation actions. */ + +static UX_TEST_SIM_ENTRY_ACTION dcd_endpoint_create_fail[] = { +/* 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_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_SUCCESS , UX_NULL, + UX_TRUE}, +{ UX_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ UX_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ UX_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ UX_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ 0 } +}; + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (!expect_errors) + { + if (error_code != UX_DEVICE_HANDLE_UNKNOWN) + { + /* 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 test_ux_device_class_hid_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + switch(command->ux_slave_class_command_request) + { + case UX_SLAVE_CLASS_COMMAND_INITIALIZE: + case UX_SLAVE_CLASS_COMMAND_QUERY: + return UX_SUCCESS; + + default: + return UX_NO_CLASS_MATCH; + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_stack_set_feature_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; +UX_SLAVE_CLASS_HID_PARAMETER hid_parameter; + + /* Inform user. */ + printf("Running ux_device_stack_set_feature Test............................ "); +#if !(UX_TEST_MULTI_IFC_ON) + printf("SKIP!"); + test_control_return(0); + return; +#endif + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = ux_test_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = ux_test_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Initialize the hid class parameters. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_REPORT_LENGTH; + hid_parameter.ux_device_class_hid_parameter_callback = UX_NULL; + hid_parameter.ux_slave_class_hid_instance_activate = UX_NULL; + + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, test_ux_device_class_hid_entry, + 1, 1, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #6\n"); + test_control_return(1); + } +#endif + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #7\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test host simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #8\n"); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + +UINT status; +UX_DEVICE *device; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_SLAVE_DEVICE *slave_device; +UX_SLAVE_TRANSFER *slave_transfer_request; + + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Enumeration check. */ + if (dpump_slave == UX_NULL) + { + + printf("ERROR #%d: Enum fail\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Test HNP requests */ + stepinfo(">>>>>>>>>>>>>>>> Test SetFeature(UX_OTG_FEATURE_A_HNP_SUPPORT)\n"); + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_SET_FEATURE; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = UX_OTG_FEATURE_A_HNP_SUPPORT; + transfer_request -> ux_transfer_request_index = 0; +#ifdef UX_OTG_SUPPORT + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: SetFeature(UX_OTG_FEATURE_A_HNP_SUPPORT) fail\n", __LINE__); + error_counter ++; + } + if ((_ux_system_otg -> ux_system_otg_slave_set_feature_flag & UX_OTG_FEATURE_A_HNP_SUPPORT) == 0) + { + printf("ERROR #%d: SetFeature(UX_OTG_FEATURE_A_HNP_SUPPORT) not changing status\n", __LINE__); + error_counter ++; + } +#else + expect_errors = UX_TRUE; + status = ux_host_stack_transfer_request(transfer_request); + expect_errors = UX_FALSE; + if (status == UX_SUCCESS) + { + printf("ERROR #%d: SetFeature(UX_OTG_FEATURE_A_HNP_SUPPORT) must fail\n", __LINE__); + error_counter ++; + } +#endif + + /* Test HNP requests */ + stepinfo(">>>>>>>>>>>>>>>> Test SetFeature(UX_OTG_FEATURE_B_HNP_ENABLE)\n"); + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_SET_FEATURE; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = UX_OTG_FEATURE_B_HNP_ENABLE; + transfer_request -> ux_transfer_request_index = 0; +#ifdef UX_OTG_SUPPORT + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: SetFeature(UX_OTG_FEATURE_B_HNP_ENABLE) fail\n", __LINE__); + error_counter ++; + } + if ((_ux_system_otg -> ux_system_otg_slave_set_feature_flag & UX_OTG_FEATURE_B_HNP_ENABLE) == 0) + { + + printf("ERROR #%d: SetFeature(UX_OTG_FEATURE_B_HNP_ENABLE) not changing status\n", __LINE__); + error_counter ++; + } +#else + expect_errors = UX_TRUE; + status = ux_host_stack_transfer_request(transfer_request); + expect_errors = UX_FALSE; + if (status == UX_SUCCESS) + { + printf("ERROR #%d: SetFeature(UX_OTG_FEATURE_B_HNP_ENABLE) must fail\n", __LINE__); + error_counter ++; + } +#endif + + /* Test HNP requests */ + stepinfo(">>>>>>>>>>>>>>>> Test SetFeature(UX_OTG_FEATURE_A_ALT_HNP_SUPPORT)\n"); + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_SET_FEATURE; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = UX_OTG_FEATURE_A_ALT_HNP_SUPPORT; + transfer_request -> ux_transfer_request_index = 0; +#if 0 /* defined(UX_OTG_SUPPORT) */ /* No support yet. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: SetFeature(UX_OTG_FEATURE_A_ALT_HNP_SUPPORT) fail\n", __LINE__); + error_counter ++; + } +#else + expect_errors = UX_TRUE; + status = ux_host_stack_transfer_request(transfer_request); + expect_errors = UX_FALSE; + if (status == UX_SUCCESS) + { + printf("ERROR #%d: SetFeature(UX_OTG_FEATURE_A_ALT_HNP_SUPPORT) must fail\n", __LINE__); + error_counter ++; + } +#endif + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static VOID ux_test_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID ux_test_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_device_stack_standard_request_tests.c b/test/regression/usbx_ux_device_stack_standard_request_tests.c new file mode 100644 index 00000000..18ce0311 --- /dev/null +++ b/test/regression/usbx_ux_device_stack_standard_request_tests.c @@ -0,0 +1,2158 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" + +#include "ux_host_class_cdc_acm.h" +#include "ux_host_stack.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.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_CDC_ACM_CONNECTION_DELAY ((UX_RH_ENUMERATION_RETRY + 1)*UX_HOST_CLASS_CDC_ACM_DEVICE_INIT_DELAY) +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (96*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +#define UX_DEMO_VENDOR_REQUEST 0x54 + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_simulation0; +static TX_THREAD tx_test_thread_simulation1; +static VOID tx_test_thread_simulation0_entry(ULONG); +static VOID tx_test_thread_simulation1_entry(ULONG); +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +static VOID ux_test_hcd_entry_should_not_be_called(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_disconnect(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +static UINT test_ux_device_class_cdc_acm_entry(UX_SLAVE_CLASS_COMMAND *command); + +static UINT test_ms_vendor_request(ULONG request, ULONG request_value, ULONG request_index, ULONG request_length, + UCHAR *transfer_request_buffer, ULONG *transfer_request_length); + +static VOID ux_test_dcd_entry_is_called(UX_TEST_ACTION *action, VOID *params); + +static UINT test_ux_device_class_cdc_acm_read_halt(UX_SLAVE_CLASS_CDC_ACM *cdc_acm); + +static UINT test_ux_host_class_cdc_acm_write(UX_HOST_CLASS_CDC_ACM *cdc_acm, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); +static UINT test_ux_host_class_cdc_acm_write_halt_clear(UX_HOST_CLASS_CDC_ACM *cdc_acm); + + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +static UCHAR cdc_acm_slave_change; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; +static UCHAR cdc_acm_slave_reading = UX_TRUE; + +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_mem_alloc_count; +static ULONG rsc_enum_sem_usage; +static ULONG rsc_enum_sem_get_count; +static ULONG rsc_enum_mutex_usage; + +static UINT class_entry_rc = UX_SUCCESS; + +static UINT vendor_req_rc = UX_SUCCESS; + +static UX_SLAVE_CLASS_HID_PARAMETER hid_parameter; + +/* HID mouse related descriptors */ + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +#define LSB(x) (x & 0x00ff) +#define MSB(x) ((x & 0xff00) >> 8) + +/* HID Mouse interface descriptors 9+9+7=25 bytes */ +#define HID_MOUSE_IFC_DESC_ALL(ifc, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_MOUSE_IFC_DESC_ALL_LEN 25 + +/* Storage related descriptors 9+7+7=23 bytes */ +#define MS_IFC_DESC_ALL(ifc, bulk_in_epa, bulk_out_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x03, 0x08, 0x06, 0x50, 0x00,\ + /* Endpoint descriptor (Bulk In) */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Bulk Out) */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00, +#define MS_IFC_DESC_ALL_LEN 23 + +/* CDC IAD 8 bytes */ +#define CDC_IAD_DESC(comm_ifc) \ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (comm_ifc), 0x02, 0x02, 0x02, 0x00, 0x00, +#define CDC_IAD_DESC_LEN 8 + +/* CDC Communication interface descriptors 9+5+4+5+5+7=35 bytes */ +#define CDC_COMM_IFC_DESC_ALL(comm_ifc, data_ifc, interrupt_epa) \ + /* Communication Class Interface Descriptor. 9 bytes. */\ + 0x09, 0x04, (comm_ifc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06,\ + (comm_ifc), /* Master interface */\ + (data_ifc), /* Slave interface */\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03,\ + (data_ifc), /* Data interface */\ + /* Endpoint 0x83 descriptor 7 bytes */\ + 0x07, 0x05, (interrupt_epa),\ + 0x03,\ + 0x08, 0x00,\ + 15, +#define CDC_COMM_IFC_DESC_ALL_LEN 35 + +/* CDC Data interface descriptors 9+7+7=23 bytes */ +#define CDC_DATA_IFC_DESC_ALL(ifc, bulk_in_epa, bulk_out_epa) \ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (ifc),\ + 0x00, /* bAlternateSetting */\ + 0x02, /* bNumEndpoints */\ + 0x0A, 0x00, 0x00,\ + 0x00,\ + /* Endpoint bulk IN descriptor 7 bytes */\ + 0x07, 0x05, (bulk_in_epa),\ + 0x02,\ + 0x40, 0x00,\ + 0x00,\ + /* Endpoint bulk OUT descriptor 7 bytes */\ + 0x07, 0x05, (bulk_out_epa),\ + 0x02,\ + 0x40, 0x00,\ + 0x00, +#define CDC_DATA_IFC_DESC_ALL_LEN 23 + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* Define device framework. */ + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Configuration 1 descriptor 9 bytes */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0xE0, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Endpoint 0x83 descriptor 7 bytes */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, + 0x02, + 0x40, 0x00, + 0x00, + + /* Configuration 2 descriptor 9 bytes */ + 0x09, 0x02, (0x4b + 28 + 46), 0x00, + 0x02, 0x02, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x01, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Endpoint 0x83 descriptor 7 bytes */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + 0x0A, 0x00, 0x00, + 0x00, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x01, /* bAlternateSetting */ + 0x02, /* bNumEndpoints */ + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, + 0x02, + 0x40, 0x00, + 0x00, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x02, /* bAlternateSetting */ + 0x04, /* bNumEndpoints */ + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x85 descriptor 7 bytes */ + 0x07, 0x05, 0x85, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x04 descriptor 7 bytes */ + 0x07, 0x05, 0x04, + 0x02, + 0x40, 0x00, + 0x00, + + /* Configuration 3: CDC + CDC */ + CFG_DESC(CFG_DESC_LEN+2*(CDC_IAD_DESC_LEN+CDC_COMM_IFC_DESC_ALL_LEN+CDC_DATA_IFC_DESC_ALL_LEN), 4, 3) + CDC_IAD_DESC(0) + CDC_COMM_IFC_DESC_ALL(0, 1, 0x83) + CDC_DATA_IFC_DESC_ALL(1, 0x81, 0x02) + CDC_IAD_DESC(2) + CDC_COMM_IFC_DESC_ALL(2, 3, 0x86) + CDC_DATA_IFC_DESC_ALL(3, 0x84, 0x05) + + /* Configuration 4: HID + HID */ + CFG_DESC(CFG_DESC_LEN+2*(HID_MOUSE_IFC_DESC_ALL_LEN), 2, 4) + HID_MOUSE_IFC_DESC_ALL(0, 0x81) + HID_MOUSE_IFC_DESC_ALL(1, 0x82) + +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor */ + 0x09, 0x02, (0x4b+5), 0x00, + 0x02, 0x01, 0x00, + 0xE0, 0x00, + + /* OTG Descriptor. */ + 0x05, 0x09, 0x03, 0x02, 0x00, + + /* Interface association descriptor. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor */ + 0x05, 0x24, 0x06, + 0x00, + 0x01, + + /* Call Management Functional Descriptor */ + 0x05, 0x24, 0x01, + 0x00, + 0x01, + + /* Endpoint 0x83 descriptor */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 15, + + /* Data Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor */ + 0x07, 0x05, 0x81, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor */ + 0x07, 0x05, 0x02, + 0x02, + 0x40, 0x00, + 0x00, + + /* Configuration 2 descriptor 9 bytes */ + 0x09, 0x02, (0x4b + 28 + 46), 0x00, + 0x02, 0x02, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x01, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Endpoint 0x83 descriptor 7 bytes */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 15, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, + 0x00, + 0x0A, 0x00, 0x00, + 0x00, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x01, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, + 0x02, + 0x40, 0x00, + 0x00, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x02, /* bAlternateSetting */ + 0x04, /* bNumEndpoints */ + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x85 descriptor 7 bytes */ + 0x07, 0x05, 0x85, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x04 descriptor 7 bytes */ + 0x07, 0x05, 0x04, + 0x02, + 0x40, 0x00, + 0x00, + + /* Configuration 3: CDC + CDC */ + CFG_DESC(CFG_DESC_LEN+2*(CDC_IAD_DESC_LEN+CDC_COMM_IFC_DESC_ALL_LEN+CDC_DATA_IFC_DESC_ALL_LEN), 4, 3) + CDC_IAD_DESC(0) + CDC_COMM_IFC_DESC_ALL(0, 1, 0x83) + CDC_DATA_IFC_DESC_ALL(1, 0x81, 0x02) + CDC_IAD_DESC(2) + CDC_COMM_IFC_DESC_ALL(2, 3, 0x86) + CDC_DATA_IFC_DESC_ALL(3, 0x84, 0x05) + + /* Configuration 4: HID + HID */ + CFG_DESC(CFG_DESC_LEN+2*(HID_MOUSE_IFC_DESC_ALL_LEN), 2, 4) + HID_MOUSE_IFC_DESC_ALL(0, 0x81) + HID_MOUSE_IFC_DESC_ALL(1, 0x82) + +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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_DEMO_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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Simulation actions. */ + +static UX_TEST_SIM_ENTRY_ACTION dcd_transfer_is_called[] = { +/* 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_DCD_TRANSFER_REQUEST, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , ux_test_dcd_entry_is_called}, +{ 0 } +}; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static VOID ux_test_dcd_entry_is_called(UX_TEST_ACTION *action, VOID *params) +{ + error_counter ++; +} + +static UINT test_ms_vendor_request(ULONG request, ULONG request_value, ULONG request_index, ULONG request_length, + UCHAR *transfer_request_buffer, ULONG *transfer_request_length) +{ + return vendor_req_rc; +} + + +static UINT test_ux_device_class_cdc_acm_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + if (class_entry_rc != UX_SUCCESS) + return class_entry_rc; + + switch (command -> ux_slave_class_command_request) + { + case UX_SLAVE_CLASS_COMMAND_CHANGE: + return UX_SUCCESS; + default: break; + } + return _ux_device_class_cdc_acm_entry(command); +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +static VOID ux_test_hcd_entry_should_not_be_called(UX_TEST_ACTION *action, VOID *params) +{ + + error_counter ++; +} + +static VOID ux_test_hcd_entry_disconnect(UX_TEST_ACTION *action, VOID *params) +{ + + ux_test_dcd_sim_slave_disconnect(); +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_enum_sem_get_count = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +static UINT test_ux_device_class_cdc_acm_read_halt(UX_SLAVE_CLASS_CDC_ACM *cdc_acm) +{ +UX_SLAVE_ENDPOINT *endpoint; +UX_SLAVE_INTERFACE *interface; + + /* This is the first time we are activated. We need the interface to the class. */ + interface = cdc_acm -> ux_slave_class_cdc_acm_interface; + + /* Locate the endpoints. */ + endpoint = interface -> ux_slave_interface_first_endpoint; + + /* Check the endpoint direction, if OUT we have the correct endpoint. */ + if ((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) != UX_ENDPOINT_OUT) + { + + /* So the next endpoint has to be the OUT endpoint. */ + endpoint = endpoint -> ux_slave_endpoint_next_endpoint; + } + + return ux_device_stack_endpoint_stall(endpoint); +} + +extern UINT _ux_host_stack_endpoint_reset(UX_ENDPOINT *endpoint); +static UINT test_ux_host_class_cdc_acm_write_halt_clear(UX_HOST_CLASS_CDC_ACM *cdc_acm) +{ + return _ux_host_stack_endpoint_reset(cdc_acm->ux_host_class_cdc_acm_bulk_out_endpoint); +} + +static UINT test_ux_host_class_cdc_acm_write(UX_HOST_CLASS_CDC_ACM *cdc_acm, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length) +{ +UX_TRANSFER *transfer_request; +UINT status; +ULONG transfer_request_length; + + /* Start by resetting the actual length of the transfer. */ + *actual_length = 0; + + /* Get the pointer to the bulk out endpoint transfer request. */ + transfer_request = &cdc_acm -> ux_host_class_cdc_acm_bulk_out_endpoint -> ux_endpoint_transfer_request; + + /* Program the maximum authorized length for this transfer_request. */ + if (requested_length > transfer_request -> ux_transfer_request_maximum_length) + transfer_request_length = transfer_request -> ux_transfer_request_maximum_length; + else + transfer_request_length = requested_length; + + /* Initialize the transfer_request. */ + transfer_request -> ux_transfer_request_data_pointer = data_pointer; + transfer_request -> ux_transfer_request_requested_length = transfer_request_length; + + /* Perform the transfer. */ + status = ux_host_stack_transfer_request(transfer_request); + + /* If the transfer is successful, we need to wait for the transfer request to be completed. */ + if (status == UX_SUCCESS) + { + + /* Wait for the completion of the transfer request. */ + status = _ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, UX_HOST_CLASS_CDC_ACM_CLASS_TRANSFER_TIMEOUT); + + /* Update the length of the actual data transferred. We do this after the + abort of the transfer_request in case some data actually went out. */ + *actual_length += transfer_request -> ux_transfer_request_actual_length; + + /* If the semaphore did not succeed we probably have a time out. */ + if (status != UX_SUCCESS) + { + + /* All transfers pending need to abort. There may have been a partial transfer. */ + ux_host_stack_transfer_request_abort(transfer_request); + + /* Set the completion code. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + + /* Error trap. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_TIMEOUT); + + /* If trace is enabled, insert this event into the trace buffer. */ + UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_TRANSFER_TIMEOUT, transfer_request, 0, 0, UX_TRACE_ERRORS, 0, 0) + + } + + /* Report completion code. */ + status = transfer_request -> ux_transfer_request_completion_code; + } + + /* Return status. */ + return(status); +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_device_stack_standard_request_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + printf("Running Host & Device Standard Request Test......................... "); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_count_reset(); + 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_mem_alloc_error_generation_stop(); + 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(); + + /* 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 #1\n"); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* 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 #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, test_ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, test_ux_device_class_cdc_acm_entry, + 1,2, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if(status!=UX_SUCCESS) + { + + printf(" ERROR #7\n"); + test_control_return(1); + } +#endif + + /* Initialize the hid class parameters. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_REPORT_LENGTH; + hid_parameter.ux_device_class_hid_parameter_callback = UX_NULL; + hid_parameter.ux_slave_class_hid_instance_activate = UX_NULL; + + /* Initilize the device hid class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 4, 0, (VOID *)&hid_parameter); + // status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + // 4, 1, (VOID *)&hid_parameter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if(status!=UX_SUCCESS) + { + + printf("Error on line %d, error code: %x\n", __LINE__, status); + test_control_return(1); + } +#endif + + /* MS extensions. */ + status = _ux_device_stack_microsoft_extension_register(UX_DEMO_VENDOR_REQUEST, test_ms_vendor_request); + + if(status!=UX_SUCCESS) + { + + printf(" ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #8\n"); + test_control_return(1); + } + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + if (status != UX_SUCCESS) + { + + printf(" ERROR #2\n"); + test_control_return(1); + } + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_entry); + if (status != UX_SUCCESS) + { + + printf(" ERROR #3\n"); + 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 #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_simulation0, "tx test simulation 0", tx_test_thread_simulation0_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #9\n"); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_simulation1, "tx test simulation 1", tx_test_thread_simulation1_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #10\n"); + test_control_return(1); + } +} + +void tx_test_thread_simulation0_entry(ULONG arg) +{ +UINT status; +ULONG actual_length; +UX_DEVICE *device; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_SLAVE_TRANSFER *slave_transfer_request; + + stepinfo("\n"); + + /* Wait for first enumeration to complete. */ + stepinfo(">>>>>>>>>>>>>>>> Wait for first enumeration completion\n"); + while (cdc_acm_host_control == UX_NULL || cdc_acm_host_data == UX_NULL || cdc_acm_slave == UX_NULL) + tx_thread_sleep(10); + + /* Wait for instances to be live. */ + tx_thread_sleep(10); + + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Test connect. Note that we must switch to high speed for tests. */ + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + tx_thread_sleep(UX_CDC_ACM_CONNECTION_DELAY); + if (cdc_acm_host_control == UX_NULL || cdc_acm_host_data == UX_NULL || cdc_acm_slave == UX_NULL) + { + + printf("ERROR #%d: connection not detected\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + slave_transfer_request = &_ux_system_slave->ux_system_slave_device.ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request; + + /* Test bulk stall handling */ + stepinfo(">>>>>>>>>>>>>>>> Test Bulk OUT STALL\n"); + /* Start waiting stall on device side */ + status = test_ux_host_class_cdc_acm_write(cdc_acm_host_data, "TSTALL\n", 7, &actual_length); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: Bulk OUT fail: %x\n", __LINE__, status); + test_control_return(1); + } + + /* Check endpoint stalled */ + status = test_ux_host_class_cdc_acm_write(cdc_acm_host_data, "TEST\n", 5, &actual_length); + if (status != UX_TRANSFER_STALLED) + { + + printf("ERROR #%d: Bulk OUT not stalled: %x\n", __LINE__, status); + test_control_return(1); + } + + /* Clear halt */ + status = test_ux_host_class_cdc_acm_write_halt_clear(cdc_acm_host_data); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: Stall clear fail: %x\n", __LINE__, status); + test_control_return(1); + } + + /* Check endpoint good */ + status = test_ux_host_class_cdc_acm_write(cdc_acm_host_data, "TEST\n", 5, &actual_length); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: Bulk OUT failed: %x\n", __LINE__, status); + test_control_return(1); + } + + /* Test normal requests */ + stepinfo(">>>>>>>>>>>>>>>> Test GetDeviceDescriptor\n"); + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_requested_length = 64; + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = UX_DEVICE_DESCRIPTOR_ITEM << 8; + transfer_request -> ux_transfer_request_index = 0; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: GetDeviceDescriptor(64) fail\n", __LINE__); + test_control_return(1); + } + if (transfer_request->ux_transfer_request_actual_length != 18) + { + + printf("ERROR #%d: GetDeviceDescriptor(64) actual length is not 18\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test GetDeviceQualifierDescriptor\n"); + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_requested_length = 8; + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = UX_DEVICE_QUALIFIER_DESCRIPTOR_ITEM << 8; + transfer_request -> ux_transfer_request_index = 0; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: GetDeviceQualifierDescriptor(8) fail\n", __LINE__); + test_control_return(1); + } + if (transfer_request->ux_transfer_request_actual_length != 8) + { + + printf("ERROR #%d: GetDeviceQualifierDescriptor(8) actual length is not 8\n", __LINE__); + test_control_return(1); + } + + transfer_request -> ux_transfer_request_requested_length = 64; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: GetDeviceQualifierDescriptor(64) fail\n", __LINE__); + test_control_return(1); + } + if (transfer_request->ux_transfer_request_actual_length != 10) + { + + printf("ERROR #%d: GetDeviceQualifierDescriptor(64) actual length is not 10\n", __LINE__); + test_control_return(1); + } + + _ux_system_slave -> ux_system_slave_device_framework = _ux_system_slave -> ux_system_slave_device_framework_full_speed; + _ux_system_slave -> ux_system_slave_device_framework_length = _ux_system_slave -> ux_system_slave_device_framework_length_full_speed; + + status = ux_host_stack_transfer_request(transfer_request); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: GetDeviceQualifierDescriptor(64) should fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test GetOTGDescriptor\n"); + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_requested_length = 64; + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = UX_OTG_DESCRIPTOR_ITEM << 8; + transfer_request -> ux_transfer_request_index = 0; + + status = ux_host_stack_transfer_request(transfer_request); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: GetOTGDescriptor(64) should fail\n", __LINE__); + test_control_return(1); + } + + _ux_system_slave -> ux_system_slave_device_framework = _ux_system_slave -> ux_system_slave_device_framework_high_speed; + _ux_system_slave -> ux_system_slave_device_framework_length = _ux_system_slave -> ux_system_slave_device_framework_length_high_speed; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: GetOTGDescriptor(64) fail: %x\n", __LINE__, status); + test_control_return(1); + } + if (transfer_request->ux_transfer_request_actual_length != 5) + { + + printf("ERROR #%d: GetOTGDescriptor(64) actual length is not 5\n", __LINE__); + test_control_return(1); + } + + transfer_request -> ux_transfer_request_requested_length = 5; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: GetOTGDescriptor(5) fail\n", __LINE__); + test_control_return(1); + } + if (transfer_request->ux_transfer_request_actual_length != 5) + { + + printf("ERROR #%d: GetOTGDescriptor(5) actual length is not 5\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test GetOtherSpeedDescriptor\n"); + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_requested_length = 8; + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = UX_OTHER_SPEED_DESCRIPTOR_ITEM << 8; + transfer_request -> ux_transfer_request_index = 0; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: GetOtherSpeedDescriptor(8) fail\n", __LINE__); + test_control_return(1); + } + + transfer_request -> ux_transfer_request_requested_length = 256; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: GetOtherSpeedDescriptor(256) fail\n", __LINE__); + test_control_return(1); + } + + transfer_request -> ux_transfer_request_value = (UX_OTHER_SPEED_DESCRIPTOR_ITEM << 8) | 10; + status = ux_host_stack_transfer_request(transfer_request); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: GetOtherSpeedDescriptor(10, 256) must fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test GetConfigurationDescriptor\n"); + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_requested_length = 256; + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_index = 0; + + /* Get existing configuration */ + transfer_request -> ux_transfer_request_value = UX_CONFIGURATION_DESCRIPTOR_ITEM << 8; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: GetConfigurationDescriptor(0, 256) fail\n", __LINE__); + test_control_return(1); + } + + /* Get non-existing configuration */ + transfer_request -> ux_transfer_request_value = (UX_CONFIGURATION_DESCRIPTOR_ITEM << 8) | 10; + status = ux_host_stack_transfer_request(transfer_request); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: GetConfigurationDescriptor(10, 256) must fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test GetStringDescriptor\n"); + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_requested_length = 64; + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + + /* Get LangID with big buffer */ + transfer_request -> ux_transfer_request_value = UX_STRING_DESCRIPTOR_ITEM << 8; + transfer_request -> ux_transfer_request_index = 0; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: GetStringDescriptor(0, 64) fail\n", __LINE__); + test_control_return(1); + } + + /* Get LangID with exactly size */ + transfer_request -> ux_transfer_request_requested_length = 4; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: GetStringDescriptor(0, 4) fail\n", __LINE__); + test_control_return(1); + } + + /* Get String with small buffer */ + transfer_request -> ux_transfer_request_index = 0x0409; + transfer_request -> ux_transfer_request_value = (UX_STRING_DESCRIPTOR_ITEM << 8) | 1; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: GetStringDescriptor(1, 4) fail\n", __LINE__); + test_control_return(1); + } + + /* Get String with large buffer */ + transfer_request -> ux_transfer_request_requested_length = 256; + transfer_request -> ux_transfer_request_value = (UX_STRING_DESCRIPTOR_ITEM << 8) | 2; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: GetStringDescriptor(2, 256) fail\n", __LINE__); + test_control_return(1); + } + + /* Get String not existing */ + transfer_request -> ux_transfer_request_value = (UX_STRING_DESCRIPTOR_ITEM << 8) | 10; + status = ux_host_stack_transfer_request(transfer_request); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: GetStringDescriptor(10, 256) must fail\n", __LINE__); + test_control_return(1); + } + + /* Get Manufacturer string descriptor. */ + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_requested_length = 0xff; + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = (UX_STRING_DESCRIPTOR_ITEM << 8) | 0x01; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: GetStringDescriptor(10, 256) must fail\n", __LINE__); + test_control_return(1); + } + + UCHAR string_descriptor_manufacturer_length = *(string_framework + 3); + UCHAR get_string_descriptor_manufacturer_expected[] = { + /* bLength. '2 +' is for bLength and bDescriptorType, '0x0c' is the length of + the string, and '*2' is because it's 16-bit unicode, where each character + is 2 bytes, the LSB is the value, and MSB is 0 (for ascii anyways). */ + (UCHAR)(2 + string_descriptor_manufacturer_length*2), + + /* bDescriptorType */ + 0x03, + + /* "Express Logic" in unicode. */ + 0x45, 0x00, + 0x78, 0x00, + 0x70, 0x00, + 0x72, 0x00, + 0x65, 0x00, + 0x73, 0x00, + 0x20, 0x00, + 0x4c, 0x00, + 0x6f, 0x00, + 0x67, 0x00, + 0x69, 0x00, + 0x63, 0x00, + }; + + /* Ensure the length is correct. */ + if (transfer_request->ux_transfer_request_actual_length != sizeof(get_string_descriptor_manufacturer_expected)) + { + + printf("ERROR on line %d\n", __LINE__); + test_control_return(1); + } + + /* Now check the contents. */ + if (_ux_utility_memory_compare(transfer_request->ux_transfer_request_data_pointer, get_string_descriptor_manufacturer_expected, sizeof(get_string_descriptor_manufacturer_expected))) + { + + printf("ERROR on line %d\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test GetDescriptor(unknown)\n"); + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_requested_length = 64; + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + + /* Get unknown discriptor */ + transfer_request -> ux_transfer_request_value = 11 << 8; + transfer_request -> ux_transfer_request_index = 0; + status = ux_host_stack_transfer_request(transfer_request); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: GetDescriptor(unknown) must fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test GetDescriptor(class)\n"); + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_requested_length = 64; + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_INTERFACE; + + /* Get class discriptor */ + transfer_request -> ux_transfer_request_value = (11 + UX_REQUEST_TYPE_CLASS) << 8; + transfer_request -> ux_transfer_request_index = 0; + status = ux_host_stack_transfer_request(transfer_request); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: GetDescriptor(class) must fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test SetFeature/ClearFeature/GetStatus\n"); + + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_function = UX_SET_FEATURE; + + /* SetDeviceFeature */ + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = UX_REQUEST_FEATURE_DEVICE_REMOTE_WAKEUP; + transfer_request -> ux_transfer_request_index = 0; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: SetDeviceFeature fail\n", __LINE__); + test_control_return(1); + } + + /* SetInterfaceFeature */ + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_INTERFACE; + status = ux_host_stack_transfer_request(transfer_request); + + /* Normal write, should be good. */ + status = test_ux_host_class_cdc_acm_write(cdc_acm_host_data, "TEST\n", 5, &actual_length); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: Bulk OUT status %x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test SetEndpointFeature(0x81)\n"); + + /* SetEndpointFeature to existing endpoint */ + transfer_request -> ux_transfer_request_index = 0x02; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_ENDPOINT; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: SetEndpointFeature(0x81) fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test SetEndpointFeature(0x82)\n"); + + /* SetEndpointFeature to not existing one */ + transfer_request -> ux_transfer_request_index = 0x82; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_ENDPOINT; + status = ux_host_stack_transfer_request(transfer_request); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: SetEndpointFeature(0x82) must fail\n", __LINE__); + test_control_return(1); + } + + /* GetDeviceStatus */ + transfer_request -> ux_transfer_request_requested_length = 64; + transfer_request -> ux_transfer_request_function = UX_GET_STATUS; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_index = 0; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: GetDeviceStatus fail\n", __LINE__); + test_control_return(1); + } + + /* GetDeviceOTGStatus */ + transfer_request -> ux_transfer_request_index = UX_OTG_STATUS_SELECTOR; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: GetDeviceOTGStatus fail\n", __LINE__); + test_control_return(1); + } + + /* GetInterfaceStatus may or may not implement */ + transfer_request -> ux_transfer_request_index = 0; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_INTERFACE; + status = ux_host_stack_transfer_request(transfer_request); + + /* GetEndpointStatus for existing endpoint */ + transfer_request -> ux_transfer_request_index = 0x02; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_ENDPOINT; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: GetEndpointStatus(0x02) fail\n", __LINE__); + test_control_return(1); + } + if (buffer[0] != 1) + { + + printf("ERROR #%d: GetEndpointStatus(0x02) should halt\n", __LINE__); + test_control_return(1); + + } + + /* Write, should return halt. */ + status = test_ux_host_class_cdc_acm_write(cdc_acm_host_data, "TEST\n", 5, &actual_length); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: Bulk OUT status %x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test ClearEndpointFeature(0x02)\n"); + + /* ClearEndpointFeature for existing endpoint */ + transfer_request -> ux_transfer_request_function = UX_CLEAR_FEATURE; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_ENDPOINT; + transfer_request -> ux_transfer_request_index = 0x02; + transfer_request -> ux_transfer_request_requested_length = 0; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: ClearEndpointFeature(0x02) fail\n", __LINE__); + test_control_return(1); + } + + /* GetEndpointStatus for existing endpoint to check if clear is done */ + transfer_request -> ux_transfer_request_function = UX_GET_STATUS; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_ENDPOINT; + transfer_request -> ux_transfer_request_index = 0x02; + transfer_request -> ux_transfer_request_requested_length = 2; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: GetEndpointStatus(0x02) fail\n", __LINE__); + test_control_return(1); + } + if (buffer[0] != 0) + { + + printf("ERROR #%d: GetEndpointStatus(0x02) should clear\n", __LINE__); + test_control_return(1); + + } + + /* Write, should return OK. */ + status = test_ux_host_class_cdc_acm_write(cdc_acm_host_data, "TEST\n", 5, &actual_length); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: Bulk OUT status %x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test ClearEndpointFeature(0x05)\n"); + + /* ClearEndpointFeature on not existing endpoint */ + transfer_request -> ux_transfer_request_function = UX_CLEAR_FEATURE; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_ENDPOINT; + transfer_request -> ux_transfer_request_index = 0x05; + transfer_request -> ux_transfer_request_requested_length = 0; + status = ux_host_stack_transfer_request(transfer_request); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: GetEndpointStatus(0x05) must fail\n", __LINE__); + test_control_return(1); + } + + /* ClearDeviceFeature */ + transfer_request -> ux_transfer_request_function = UX_CLEAR_FEATURE; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_index = 0; + transfer_request -> ux_transfer_request_requested_length = 0; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: ClearDeviceFeature() fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test ClearInterfaceFeature(0x00)\n"); + + /* ClearInterfaceFeature, may or may not implement */ + transfer_request -> ux_transfer_request_function = UX_CLEAR_FEATURE; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_index = 0; + transfer_request -> ux_transfer_request_requested_length = 0; + status = ux_host_stack_transfer_request(transfer_request); + + stepinfo(">>>>>>>>>>>>>>>> Test GetConfiguration\n"); + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_requested_length = 1; + transfer_request -> ux_transfer_request_function = UX_GET_CONFIGURATION; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = 0; + /* GetConfiguration should OK */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: GetConfiguration fail\n", __LINE__); + test_control_return(1); + } + if (buffer[0] != 1) + { + + printf("ERROR #%d: GetConfiguration should return 1\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test SetConfiguration\n"); + transfer_request -> ux_transfer_request_data_pointer = UX_NULL; + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_SET_CONFIGURATION; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = 1; + transfer_request -> ux_transfer_request_index = 0; + /* SetConfiguration should OK */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: SetConfiguration fail\n", __LINE__); + test_control_return(1); + } + + /* SetConfiguration to invalid should fail */ + transfer_request -> ux_transfer_request_value = 10; + status = ux_host_stack_transfer_request(transfer_request); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: SetConfiguration(10) must fail\n", __LINE__); + test_control_return(1); + } + + /* SetConfiguration */ + transfer_request -> ux_transfer_request_value = 3; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: SetConfiguration(3) must pass\n", __LINE__); + test_control_return(1); + } + + /* SetConfiguration */ + transfer_request -> ux_transfer_request_value = 4; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: SetConfiguration(4) must pass\n", __LINE__); + test_control_return(1); + } + + /* Stop reading on device side */ + cdc_acm_slave_reading = UX_FALSE; + + stepinfo(">>>>>>>>>>>>>>>> Test SetInterface/GetInterface\n"); + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_requested_length = 0; + + /* Unonfiguration */ + transfer_request -> ux_transfer_request_function = UX_SET_CONFIGURATION; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = 0; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: SetConfiguration(0) fail\n", __LINE__); + test_control_return(1); + } + + + /* SetInterface must report error */ + transfer_request -> ux_transfer_request_function = UX_SET_INTERFACE; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = 0; + status = ux_host_stack_transfer_request(transfer_request); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: SetInterface must fail when not configured\n", __LINE__); + test_control_return(1); + } + + /* GetInterface must report error */ + transfer_request -> ux_transfer_request_requested_length = 1; + transfer_request -> ux_transfer_request_function = UX_GET_INTERFACE; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_INTERFACE; + status = ux_host_stack_transfer_request(transfer_request); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: GetInterface must fail when not configured\n", __LINE__); + test_control_return(1); + } + + /* Back to normal configuration */ + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_SET_CONFIGURATION; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = 1; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: SetConfiguration(1) fail\n", __LINE__); + test_control_return(1); + } + + transfer_request -> ux_transfer_request_function = UX_SET_INTERFACE; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_INTERFACE; + + /* Good interface */ + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = 0; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: SetInterface(0.0) should be OK\n", __LINE__); + test_control_return(1); + } + + /* Get interface */ + transfer_request -> ux_transfer_request_requested_length = 1; + transfer_request -> ux_transfer_request_function = UX_GET_INTERFACE; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_INTERFACE; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: GetInterface fail %x\n", __LINE__, status); + test_control_return(1); + } + if (buffer[0] != 0) + { + + printf("ERROR #%d: GetInterface must return 0 but not %x\n", __LINE__, buffer[0]); + test_control_return(1); + } + + /* Invalid interface */ + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_SET_INTERFACE; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_INTERFACE; + + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = 2; + status = ux_host_stack_transfer_request(transfer_request); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: SetInterface must fail\n", __LINE__); + test_control_return(1); + } + + /* Invalid alternate setting */ + transfer_request -> ux_transfer_request_value = 2; + transfer_request -> ux_transfer_request_index = 0; + status = ux_host_stack_transfer_request(transfer_request); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: SetInterface should fail\n", __LINE__); + test_control_return(1); + } + + /* SetConfiguration(2) */ + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_SET_CONFIGURATION; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = 2; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: SetConfiguration(2) fail\n", __LINE__); + test_control_return(1); + } + + /* SetInterface(2, 0, 1) */ + transfer_request -> ux_transfer_request_function = UX_SET_INTERFACE; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_value = 1; + transfer_request -> ux_transfer_request_index = 0; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: SetInterface(0,1) should be OK\n", __LINE__); + test_control_return(1); + } + + /* GetInterface(2, 0) */ + transfer_request -> ux_transfer_request_requested_length = 1; + transfer_request -> ux_transfer_request_function = UX_GET_INTERFACE; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_INTERFACE; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: GetInterface must be OK\n", __LINE__); + test_control_return(1); + } + if (buffer[0] != 1) + { + + printf("ERROR #%d: GetInterface must return 1 but not %x\n", __LINE__, buffer[0]); + test_control_return(1); + } + + /* GetInterface(2, 1) */ + transfer_request -> ux_transfer_request_index = 1; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: GetInterface must be OK\n", __LINE__); + test_control_return(1); + } + if (buffer[0] != 0) + { + + printf("ERROR #%d: GetInterface must return 0 but not %x\n", __LINE__, buffer[0]); + test_control_return(1); + } + + /* SetInterface(1, 1), OK or STALL due to no class driver on device side. */ + transfer_request -> ux_transfer_request_function = UX_SET_INTERFACE; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_value = 1; + transfer_request -> ux_transfer_request_index = 1; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS && status != UX_TRANSFER_STALLED) + { + + printf("ERROR #%d: SetInterface(1,1) status %x\n", __LINE__, status); + test_control_return(1); + } + + /* SetInterface(1, 2), OK or STALL due to no class driver on device side. */ + transfer_request -> ux_transfer_request_value = 2; + transfer_request -> ux_transfer_request_index = 1; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS && status != UX_TRANSFER_STALLED) + { + + printf("ERROR #%d: SetInterface(1,2) status %x\n", __LINE__, status); + test_control_return(1); + } + + /* SetInterface(1, 0), OK or STALL due to no class driver on device side. */ + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = 1; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS && status != UX_TRANSFER_STALLED) + { + + printf("ERROR #%d: SetInterface(1,0) status %x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test SetDescriptor\n"); + transfer_request -> ux_transfer_request_data_pointer = UX_NULL; + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_SET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = 0; + /* SetDescriptor should OK or STALL */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS && status != UX_TRANSFER_STALLED) + { + + printf("ERROR #%d: SetDescriptor status %x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test SyncFrame\n"); + transfer_request -> ux_transfer_request_data_pointer = UX_NULL; + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_SYNCH_FRAME; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = 0; + transfer_request -> ux_transfer_request_index = 0; + /* SyncFrame should OK or STALL */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS && status != UX_TRANSFER_STALLED) + { + + printf("ERROR #%d: SyncFrame status %x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test Unknown Request\n"); + /* Unknown request should STALL */ + transfer_request -> ux_transfer_request_function = 20; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + + printf("ERROR #%d: Unknown request status %x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test Class Request\n"); + transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_CDC_ACM_REQ_GET_LINE_CODING; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_DEVICE; + /* Check DCD transfer call */ + error_counter = 0; + ux_test_dcd_sim_slave_set_actions(dcd_transfer_is_called); + /* Process request */ + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: Class request status %x\n", __LINE__, status); + test_control_return(1); + } + if (error_counter == 0) + { + + printf("ERROR #%d: Class request no DCD transfer\n", __LINE__); + test_control_return(1); + } + + class_entry_rc = UX_ERROR; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + + printf("ERROR #%d: Vendor request status %x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test Vendor Request\n"); + transfer_request -> ux_transfer_request_function = 0xEE; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_VENDOR | UX_REQUEST_TARGET_DEVICE; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + + printf("ERROR #%d: Vendor request status %x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test MS Vendor Request\n"); + transfer_request -> ux_transfer_request_function = UX_DEMO_VENDOR_REQUEST; + + vendor_req_rc = UX_ERROR; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + + printf("ERROR #%d: Vendor request status %x\n", __LINE__, status); + test_control_return(1); + } + vendor_req_rc = UX_SUCCESS; + + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: Vendor request status %x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> ux_slave_transfer_request_status_phase_ignore\n"); + /* DCD should not been called */ + slave_transfer_request->ux_slave_transfer_request_status_phase_ignore = UX_TRUE; + error_counter = 0; + ux_test_dcd_sim_slave_set_actions(dcd_transfer_is_called); + status = _ux_device_stack_transfer_request(slave_transfer_request, 18, 18); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: Request not success: %x\n", __LINE__, status); + test_control_return(1); + } + if (error_counter != 0) + { + + printf("ERROR #%d: Unexpected call\n", __LINE__); + test_control_return(1); + } + slave_transfer_request->ux_slave_transfer_request_status_phase_ignore = UX_FALSE; + + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_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 tx_test_thread_simulation1_entry(ULONG arg) +{ + +UINT status; +ULONG actual_length; + + while(1) + { + while(cdc_acm_slave != UX_NULL && cdc_acm_slave_reading) + { + + status = ux_device_class_cdc_acm_read(cdc_acm_slave, buffer, 64, &actual_length); + + if (status == UX_SUCCESS && actual_length) + { + + if (ux_utility_memory_compare("TSTALL\n", buffer, 7) == UX_SUCCESS) + { + + status = test_ux_device_class_cdc_acm_read_halt(cdc_acm_slave); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: set halt fail: %x\n", __LINE__, status); + test_control_return(1); + } + } + } + } + + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); + } +} diff --git a/test/regression/usbx_ux_device_stack_transfer_request_test.c b/test/regression/usbx_ux_device_stack_transfer_request_test.c new file mode 100644 index 00000000..7a54d10d --- /dev/null +++ b/test/regression/usbx_ux_device_stack_transfer_request_test.c @@ -0,0 +1,565 @@ +/* This test is designed to test the ux_device_stack_transfer_request. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +/* HID mouse related descriptors */ + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +#define LSB(x) (x & 0x00ff) +#define MSB(x) ((x & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors 9+7+7+7=30 bytes. */ +#define DPUMP_IFC_DESC_ALL(ifc, bulk_in_epa, bulk_out_epa, int_in_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x03, 0x99, 0x99, 0x99, 0x00,\ + /* Endpoint descriptor (Bulk Out) */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Bulk In) */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Interrupt In) */\ + 0x07, 0x05, (int_in_epa), 0x02, 0x40, 0x00, 0x00, +#define DPUMP_IFC_DESC_ALL_LEN 30 + +/* HID Mouse interface descriptors 9+9+7=25 bytes */ +#define HID_MOUSE_IFC_DESC_ALL(ifc, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x01, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_MOUSE_IFC_DESC_ALL_LEN 25 + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR expect_errors = UX_FALSE; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+7+7+7 =30 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02, 0x83) + /* HID 9+9+7 =25 */ + HID_MOUSE_IFC_DESC_ALL(1, 0x84) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+7+7+7 =30 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02, 0x83) + /* HID 9+9+7 =25 */ + HID_MOUSE_IFC_DESC_ALL(1, 0x84) +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Simulation actions. */ + +static UX_TEST_SIM_ENTRY_ACTION dcd_endpoint_create_fail[] = { +/* 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_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_SUCCESS , UX_NULL, + UX_TRUE}, +{ UX_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ UX_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ UX_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ UX_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ 0 } +}; + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (!expect_errors) + { + if (error_code != UX_DEVICE_HANDLE_UNKNOWN) + { + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } + } +} + +static UINT test_ux_device_class_hid_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + switch(command->ux_slave_class_command_request) + { + case UX_SLAVE_CLASS_COMMAND_INITIALIZE: + case UX_SLAVE_CLASS_COMMAND_QUERY: + return UX_SUCCESS; + + default: + return UX_NO_CLASS_MATCH; + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_device_stack_transfer_request_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; +UX_SLAVE_CLASS_HID_PARAMETER hid_parameter; + + /* Inform user. */ + printf("Running ux_device_stack_transfer_request Test....................... "); +#if !(UX_TEST_MULTI_IFC_ON) + printf("SKIP!"); + test_control_return(0); + return; +#endif + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = ux_test_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = ux_test_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Initialize the hid class parameters. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_REPORT_LENGTH; + hid_parameter.ux_device_class_hid_parameter_callback = UX_NULL; + hid_parameter.ux_slave_class_hid_instance_activate = UX_NULL; + + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, test_ux_device_class_hid_entry, + 1, 1, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #6\n"); + test_control_return(1); + } +#endif + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #7\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test host simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #8\n"); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + +UINT status; +UX_DEVICE *device; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_SLAVE_DEVICE *slave_device; +UX_SLAVE_TRANSFER *slave_transfer_request; + + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Enumeration check. */ + if (dpump_slave == UX_NULL) + { + + printf("ERROR #%d: Enum fail\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Get existing configuration */ + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_requested_length = 256; + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_index = 0; + + transfer_request -> ux_transfer_request_value = UX_CONFIGURATION_DESCRIPTOR_ITEM << 8; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: GetConfigurationDescriptor(0, 256) fail\n", __LINE__); + error_counter ++; + } + + /* Get slave device and transfer request. */ + slave_device = &_ux_system_slave->ux_system_slave_device; + slave_transfer_request = &slave_device->ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request; + + /* Reset configuration. */ + status = ux_host_stack_device_configuration_reset(device); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: Configuration Reset fail\n", __LINE__); + test_control_return(1); + } + /* Confirm it's in addressed state. + See USBX-188, USBX-161 + */ + if (slave_device->ux_slave_device_state != UX_DEVICE_ADDRESSED) + { + // printf("Correct state: %x -> %x (UX_DEVICE_ADDRESSED)\n", slave_device->ux_slave_device_state, UX_DEVICE_ADDRESSED); + slave_device->ux_slave_device_state = UX_DEVICE_ADDRESSED; + } + + /* Get existing configuration */ + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_requested_length = 256; + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_index = 0; + + transfer_request -> ux_transfer_request_value = UX_CONFIGURATION_DESCRIPTOR_ITEM << 8; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: GetConfigurationDescriptor(0, 256) fail\n", __LINE__); + error_counter ++; + } + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + + if (slave_device->ux_slave_device_state != UX_DEVICE_RESET) + { + printf("ERROR #%d: slave state not UX_DEVICE_RESET but 0x%lx\n", __LINE__, slave_device->ux_slave_device_state); + test_control_return(1); + } + + status = ux_device_stack_transfer_request(slave_transfer_request, 8, 8); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: ux_device_stack_transfer_request(8, 8) should fail\n", __LINE__); + error_counter ++; + } + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static VOID ux_test_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID ux_test_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_device_stack_vendor_request_test.c b/test/regression/usbx_ux_device_stack_vendor_request_test.c new file mode 100644 index 00000000..01321e49 --- /dev/null +++ b/test/regression/usbx_ux_device_stack_vendor_request_test.c @@ -0,0 +1,925 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_stack.h" +#include "ux_device_class_dummy.h" + +#include "ux_host_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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (96*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +#define UX_DEMO_VENDOR_REQUEST 0x54 + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_simulation0; +static TX_THREAD tx_test_thread_simulation1; +static VOID tx_test_thread_simulation0_entry(ULONG); +static VOID tx_test_thread_simulation1_entry(ULONG); + +static UINT test_ms_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_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +static UX_DEVICE_CLASS_DUMMY_PARAMETER *parameter; + +static UX_DEVICE *host_device = UX_NULL; + +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_mem_alloc_count; +static ULONG rsc_enum_sem_usage; +static ULONG rsc_enum_sem_get_count; +static ULONG rsc_enum_mutex_usage; + +static UINT class_entry_rc = UX_SUCCESS; + +static UINT vendor_req_call_count = 0; +static UINT vendor_req_rc = UX_SUCCESS; +static UINT vendor_req_ret_len = 0; +static ULONG vendor_req_req_len; +static ULONG vendor_req_buf_len; + +#define LSB(x) ((x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Storage related descriptors 9+7+7=23 bytes */ +#define MS_IFC_DESC_ALL(ifc, bulk_in_epa, bulk_out_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x03, 0x08, 0x06, 0x50, 0x00,\ + /* Endpoint descriptor (Bulk In) */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Bulk Out) */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00, +#define MS_IFC_DESC_ALL_LEN 23 + +/* CDC IAD 8 bytes */ +#define CDC_IAD_DESC(comm_ifc) \ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (comm_ifc), 0x02, 0x02, 0x02, 0x00, 0x00, +#define CDC_IAD_DESC_LEN 8 + +/* CDC Communication interface descriptors 9+5+4+5+5+7=35 bytes */ +#define CDC_COMM_IFC_DESC_ALL(comm_ifc, data_ifc, interrupt_epa) \ + /* Communication Class Interface Descriptor. 9 bytes. */\ + 0x09, 0x04, (comm_ifc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06,\ + (comm_ifc), /* Master interface */\ + (data_ifc), /* Slave interface */\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03,\ + (data_ifc), /* Data interface */\ + /* Endpoint 0x83 descriptor 7 bytes */\ + 0x07, 0x05, (interrupt_epa),\ + 0x03,\ + 0x08, 0x00,\ + 0xFF, +#define CDC_COMM_IFC_DESC_ALL_LEN 35 + +/* CDC Data interface descriptors 9+7+7=23 bytes */ +#define CDC_DATA_IFC_DESC_ALL(ifc, bulk_in_epa, bulk_out_epa) \ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (ifc),\ + 0x00, /* bAlternateSetting */\ + 0x02, /* bNumEndpoints */\ + 0x0A, 0x00, 0x00,\ + 0x00,\ + /* Endpoint bulk IN descriptor 7 bytes */\ + 0x07, 0x05, (bulk_in_epa),\ + 0x02,\ + 0x40, 0x00,\ + 0x00,\ + /* Endpoint bulk OUT descriptor 7 bytes */\ + 0x07, 0x05, (bulk_out_epa),\ + 0x02,\ + 0x40, 0x00,\ + 0x00, +#define CDC_DATA_IFC_DESC_ALL_LEN 23 + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* Define device framework. */ + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Configuration 1 descriptor 9 bytes */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0xE0, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Endpoint 0x83 descriptor 7 bytes */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, + 0x02, + 0x40, 0x00, + 0x00, + + /* Configuration 2 descriptor 9 bytes */ + 0x09, 0x02, (0x4b + 28 + 46), 0x00, + 0x02, 0x02, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x01, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Endpoint 0x83 descriptor 7 bytes */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + 0x0A, 0x00, 0x00, + 0x00, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x01, /* bAlternateSetting */ + 0x02, /* bNumEndpoints */ + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, + 0x02, + 0x40, 0x00, + 0x00, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x02, /* bAlternateSetting */ + 0x04, /* bNumEndpoints */ + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x85 descriptor 7 bytes */ + 0x07, 0x05, 0x85, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x04 descriptor 7 bytes */ + 0x07, 0x05, 0x04, + 0x02, + 0x40, 0x00, + 0x00, + + /* Configuration 3: CDC + CDC */ + CFG_DESC(CFG_DESC_LEN+2*(CDC_IAD_DESC_LEN+CDC_COMM_IFC_DESC_ALL_LEN+CDC_DATA_IFC_DESC_ALL_LEN), 4, 3) + CDC_IAD_DESC(0) + CDC_COMM_IFC_DESC_ALL(0, 1, 0x83) + CDC_DATA_IFC_DESC_ALL(1, 0x81, 0x02) + CDC_IAD_DESC(2) + CDC_COMM_IFC_DESC_ALL(2, 3, 0x86) + CDC_DATA_IFC_DESC_ALL(3, 0x84, 0x05) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor */ + 0x09, 0x02, (0x4b+5), 0x00, + 0x02, 0x01, 0x00, + 0xE0, 0x00, + + /* OTG Descriptor. */ + 0x05, 0x09, 0x03, 0x02, 0x00, + + /* Interface association descriptor. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor */ + 0x05, 0x24, 0x06, + 0x00, + 0x01, + + /* Call Management Functional Descriptor */ + 0x05, 0x24, 0x01, + 0x00, + 0x01, + + /* Endpoint 0x83 descriptor */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor */ + 0x07, 0x05, 0x81, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor */ + 0x07, 0x05, 0x02, + 0x02, + 0x40, 0x00, + 0x00, + + /* Configuration 2 descriptor 9 bytes */ + 0x09, 0x02, (0x4b + 28 + 46), 0x00, + 0x02, 0x02, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x01, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Endpoint 0x83 descriptor 7 bytes */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, + 0x00, + 0x0A, 0x00, 0x00, + 0x00, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x01, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, + 0x02, + 0x40, 0x00, + 0x00, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x02, /* bAlternateSetting */ + 0x04, /* bNumEndpoints */ + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x85 descriptor 7 bytes */ + 0x07, 0x05, 0x85, + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x04 descriptor 7 bytes */ + 0x07, 0x05, 0x04, + 0x02, + 0x40, 0x00, + 0x00, + + /* Configuration 3: CDC + CDC */ + CFG_DESC(CFG_DESC_LEN+2*(CDC_IAD_DESC_LEN+CDC_COMM_IFC_DESC_ALL_LEN+CDC_DATA_IFC_DESC_ALL_LEN), 4, 3) + CDC_IAD_DESC(0) + CDC_COMM_IFC_DESC_ALL(0, 1, 0x83) + CDC_DATA_IFC_DESC_ALL(1, 0x81, 0x02) + CDC_IAD_DESC(2) + CDC_COMM_IFC_DESC_ALL(2, 3, 0x86) + CDC_DATA_IFC_DESC_ALL(3, 0x84, 0x05) +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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_DEMO_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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT test_ms_vendor_request(ULONG request, ULONG request_value, ULONG request_index, ULONG request_length, + UCHAR *transfer_request_buffer, ULONG *transfer_request_length) +{ + vendor_req_req_len = request_length; + vendor_req_buf_len = *transfer_request_length; + *transfer_request_length = vendor_req_ret_len; + return vendor_req_rc; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + + switch(event) + { + + case UX_DEVICE_INSERTION: + break; + + case UX_DEVICE_REMOVAL: + break; + + case UX_DEVICE_CONNECTION: + host_device = (UX_DEVICE *)inst; + break; + case UX_DEVICE_DISCONNECTION: + if (host_device == (UX_DEVICE *)inst) + host_device = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (error_code == UX_DEVICE_ENUMERATION_FAILURE || + error_code == UX_TRANSFER_STALLED) + { + /* It's normal. */ + return; + } + printf("error 0x%x, 0x%x, 0x%x\n", system_level, system_context, error_code); + 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_device_stack_vendor_request_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + printf("Running Device Stack Vendor Request Test............................ "); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_count_reset(); + 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_mem_alloc_error_generation_stop(); + 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(); + + /* 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 #1\n"); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* 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 #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_device_class_dummy_name, _ux_device_class_dummy_entry, + 1, 0, ¶meter); + if(status!=UX_SUCCESS) + { + + printf(" ERROR #7\n"); + test_control_return(1); + } + + /* MS extensions. */ + status = _ux_device_stack_microsoft_extension_register(UX_DEMO_VENDOR_REQUEST, test_ms_vendor_request); + + if(status!=UX_SUCCESS) + { + + printf(" ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #8\n"); + test_control_return(1); + } + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + if (status != UX_SUCCESS) + { + + printf(" ERROR #2\n"); + 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 #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_simulation0, "tx test simulation 0", tx_test_thread_simulation0_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #9\n"); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_simulation1, "tx test simulation 1", tx_test_thread_simulation1_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #10\n"); + test_control_return(1); + } +} + +void tx_test_thread_simulation0_entry(ULONG arg) +{ +UINT status; +ULONG actual_length; +UX_DEVICE *device; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_SLAVE_TRANSFER *slave_transfer_request; + + stepinfo("\n"); + + /* Wait for first enumeration to complete. */ + stepinfo(">>>>>>>>>>>>>>>> Wait for first enumeration completion\n"); + while (host_device == UX_NULL) + tx_thread_sleep(10); + + /* Wait for instances to be live. */ + tx_thread_sleep(10); + + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Test connect. Note that we must switch to high speed for tests. */ + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + tx_thread_sleep(100); + if (host_device == UX_NULL) + { + + printf("ERROR #%d: connection not detected\n", __LINE__); + test_control_return(1); + } + + device = host_device; + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + slave_transfer_request = &_ux_system_slave->ux_system_slave_device.ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request; + + stepinfo(">>>>>>>>>>>>>>>> Test Vendor Request\n"); + transfer_request -> ux_transfer_request_function = 0xEE; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_VENDOR | UX_REQUEST_TARGET_DEVICE; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + + printf("ERROR #%d: Vendor request status %x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test MS Vendor Request\n"); + transfer_request -> ux_transfer_request_function = UX_DEMO_VENDOR_REQUEST; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_VENDOR | UX_REQUEST_TARGET_DEVICE; + + vendor_req_rc = UX_ERROR; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_TRANSFER_STALLED) + { + + printf("ERROR #%d: Vendor request status %x\n", __LINE__, status); + test_control_return(1); + } + vendor_req_rc = UX_SUCCESS; + + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: Vendor request status %x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test vendor request NULL case\n"); + status = _ux_device_stack_microsoft_extension_register(UX_DEMO_VENDOR_REQUEST, UX_NULL); + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d: Vendor callback clear fail\n", __LINE__); + test_control_return(1); + } + vendor_req_call_count = 0; + status = ux_host_stack_transfer_request(transfer_request); + UX_TEST_ASSERT_MESSAGE(status == UX_TRANSFER_STALLED, "ERROR #%d: Vendor request status %x\n", __LINE__, status); + UX_TEST_ASSERT(vendor_req_call_count == 0); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* 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 tx_test_thread_simulation1_entry(ULONG arg) +{ + +UINT status; +ULONG actual_length; + + while(1) + { + + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); + } +} diff --git a/test/regression/usbx_ux_host_basic_memory_tests.c b/test/regression/usbx_ux_host_basic_memory_tests.c new file mode 100644 index 00000000..07ac7cba --- /dev/null +++ b/test/regression/usbx_ux_host_basic_memory_tests.c @@ -0,0 +1,972 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#if 0 /* TODO: Enable/disable stepinfo */ +#define stepinfo printf +#else +#define stepinfo(...) +#endif + +/* Define constants. */ +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +static VOID ux_test_hcd_entry_should_not_be_called(UX_HCD *hcd, UX_TEST_HCD_SIM_ACTION *action, VOID *parameter); +static VOID ux_test_hcd_entry_disconnect(UX_HCD *hcd, UX_TEST_HCD_SIM_ACTION *action, VOID *parameter); +static VOID ux_test_hcd_entry_set_cfg(UX_HCD *hcd, UX_TEST_HCD_SIM_ACTION *action, VOID *parameter); + +/* Define global data structures. */ +UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +UX_HOST_CLASS *class_driver; +UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; +ULONG command_received_count; +UCHAR cdc_acm_reception_buffer[UX_DEMO_RECEPTION_BUFFER_SIZE]; +UCHAR cdc_acm_xmit_buffer[UX_DEMO_XMIT_BUFFER_SIZE]; +UX_HOST_CLASS_CDC_ACM_RECEPTION cdc_acm_reception; +UCHAR *global_reception_buffer; +ULONG global_reception_size; + +UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +UCHAR cdc_acm_slave_change; +UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; +UCHAR buffer[UX_DEMO_BUFFER_SIZE]; +ULONG echo_mode; + +ULONG error_counter; + +ULONG set_cfg_counter; + +ULONG rsc_mem_free_on_set_cfg; +ULONG rsc_sem_on_set_cfg; +ULONG rsc_sem_get_on_set_cfg; +ULONG rsc_mutex_on_set_cfg; + +ULONG rsc_enum_sem_usage; +ULONG rsc_enum_sem_get_count; +ULONG rsc_enum_mutex_usage; +ULONG rsc_enum_mem_usage; + +/* Define device framework. */ + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 93 +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 103 +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Configuration 1 descriptor 9 bytes */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Endpoint 0x83 descriptor 7 bytes */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, /* @ 93 - 14 + 2 = 81 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, /* @ 93 - 7 + 2 = 88 */ + 0x02, + 0x40, 0x00, + 0x00, + +}; + +#define DEVICE_FRAMEWORK_EPA_POS_1_FS (DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 14 + 2) +#define DEVICE_FRAMEWORK_EPA_POS_2_FS (DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 7 + 2) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor */ + 0x05, 0x24, 0x06, + 0x00, + 0x01, + + /* Call Management Functional Descriptor */ + 0x05, 0x24, 0x01, + 0x00, + 0x01, + + /* Endpoint 0x83 descriptor */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor */ + 0x07, 0x05, 0x81, /* @ 103 - 14 + 2 = 91 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor */ + 0x07, 0x05, 0x02, /* @ 103 - 7 + 2 = 98 */ + 0x02, + 0x40, 0x00, + 0x00, + +}; + +#define DEVICE_FRAMEWORK_EPA_POS_1_HS (DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 14 + 2) +#define DEVICE_FRAMEWORK_EPA_POS_2_HS (DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 7 + 2) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 + }; + +static UX_TEST_SETUP _SetAddress = UX_TEST_SETUP_SetAddress; +static UX_TEST_SETUP _GetDeviceDescriptor = UX_TEST_SETUP_GetDevDescr; +static UX_TEST_SETUP _GetConfigDescriptor = UX_TEST_SETUP_GetCfgDescr; +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +/* Test interactions */ + +/* Disconnect on RESET: + * Host still create the EP0 and expects first SETUP request failure. + */ + +static UX_TEST_HCD_SIM_ACTION disconnect_on_reset[] = { +/* 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_RESET_PORT, NULL, + UX_TRUE , UX_TEST_PORT_STATUS_DISC, + 0 , 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_disconnect}, +#if 0 +{ UX_HCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , ux_test_hcd_entry_should_not_be_called}, +#endif +{ UX_HCD_TRANSFER_REQUEST, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, /* Request just fail on disconnect */ +{ UX_HCD_TRANSFER_REQUEST, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ UX_HCD_TRANSFER_REQUEST, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION endpoint0_create_fail[] = { +/* 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_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR}, +{ UX_HCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR}, +{ UX_HCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR}, +{ UX_HCD_TRANSFER_REQUEST, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , ux_test_hcd_entry_should_not_be_called}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION disconnect_on_SetAddress[] = { +/* 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, &_SetAddress, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_ERROR}, +{ UX_HCD_TRANSFER_REQUEST, &_SetAddress, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_ERROR}, +{ UX_HCD_TRANSFER_REQUEST, &_SetAddress, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_ERROR}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION disconnect_on_GetDevDescr[] = { +/* 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, &_GetDeviceDescriptor, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ_V, 0, UX_NULL, 0, 0, + UX_ERROR}, +{ UX_HCD_TRANSFER_REQUEST, &_GetDeviceDescriptor, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ_V, 0, UX_NULL, 0, 0, + UX_ERROR}, +{ UX_HCD_TRANSFER_REQUEST, &_GetDeviceDescriptor, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ_V, 0, UX_NULL, 0, 0, + 0, UX_NULL, + UX_TRUE}, +{ UX_HCD_TRANSFER_REQUEST, &_GetDeviceDescriptor, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ_V, 0, UX_NULL, 0, 0, + UX_ERROR}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION disconnect_on_GetCfgDescr[] = { +/* 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, &_GetConfigDescriptor, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ_V, 0, UX_NULL, 0, 0, + UX_ERROR}, /* First try */ +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ_V, 0, UX_NULL, 0, 0, + UX_ERROR}, /* Second try */ +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ_V, 0, UX_NULL, 0, 0, + UX_SUCCESS, UX_NULL, + UX_TRUE}, /* Last try first run */ +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ_V, 0, UX_NULL, 0, 0, + UX_ERROR}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION disconnect_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_ERROR}, /* First try */ +{ UX_HCD_TRANSFER_REQUEST, &_SetConfigure, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_ERROR}, /* Second try */ +{ UX_HCD_TRANSFER_REQUEST, &_SetConfigure, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_ERROR}, /* Last try */ +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION normal_enum_replace[] = { +/* 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, &_GetDeviceDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 0, 8, 0, + UX_SUCCESS, UX_NULL}, +{ UX_HCD_TRANSFER_REQUEST, &_GetDeviceDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 0, 18, 0, + UX_SUCCESS, UX_NULL}, +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 18, UX_CONFIGURATION_DESCRIPTOR_LENGTH, 0, + UX_SUCCESS, UX_NULL}, +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 18, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 18, 0, + UX_SUCCESS, UX_NULL}, +{ 0 } +} +; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static UINT test_class_cdc_acm_get(void) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_CDC_ACM *cdc_acm_host; + + + /* Find the main cdc_acm container */ + status = ux_host_stack_class_get(_ux_system_host_class_cdc_acm_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* We get the first instance of the cdc_acm device */ + do + { + + status = ux_host_stack_class_instance_get(class, 0, (void **) &cdc_acm_host); + tx_thread_sleep(10); + } while (status != UX_SUCCESS); + + /* We still need to wait for the cdc_acm status to be live */ + while (cdc_acm_host -> ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + tx_thread_sleep(10); + + /* Isolate both the control and data interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_DATA_CLASS) + { + /* This is the data interface. */ + cdc_acm_host_data = cdc_acm_host; + + /* In that case, the second one should be the control interface. */ + status = ux_host_stack_class_instance_get(class, 1, (void **) &cdc_acm_host); + + /* Check error. */ + if (status != UX_SUCCESS) + return(status); + + /* Check for the control interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + + /* This is the control interface. */ + cdc_acm_host_control = cdc_acm_host; + + return(UX_SUCCESS); + + } + } + else + { + /* Check for the control interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + + /* This is the control interface. */ + cdc_acm_host_control = cdc_acm_host; + + /* In that case, the second one should be the data interface. */ + status = ux_host_stack_class_instance_get(class, 1, (void **) &cdc_acm_host); + + /* Check error. */ + if (status != UX_SUCCESS) + return(status); + + /* Check for the data interface. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_DATA_CLASS) + { + + /* This is the data interface. */ + cdc_acm_host_data = cdc_acm_host; + + return(UX_SUCCESS); + + } + } + } + + /* Return ERROR. */ + return(UX_ERROR); +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; +} + +static VOID test_swap_framework_bulk_ep_descriptors(VOID) +{ +UCHAR tmp; + + tmp = device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_1_FS]; + device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_1_FS] = device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_2_FS]; + device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_2_FS] = tmp; + + tmp = device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_1_HS]; + device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_1_HS] = device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_2_HS]; + device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_2_HS] = tmp; +} + + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +static VOID ux_test_hcd_entry_should_not_be_called(UX_HCD *hcd, UX_TEST_HCD_SIM_ACTION *action, VOID *parameter) +{ + + error_counter ++; +} + +static VOID ux_test_hcd_entry_disconnect(UX_HCD *hcd, UX_TEST_HCD_SIM_ACTION *action, VOID *parameter) +{ + + ux_test_dcd_sim_slave_disconnect(); +} + +static VOID ux_test_hcd_entry_set_cfg(UX_HCD *hcd, UX_TEST_HCD_SIM_ACTION *action, VOID *parameter) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = _ux_system->ux_system_regular_memory_pool_free; + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_enum_sem_get_count = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_host_basic_memory_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +ULONG test_n; + + printf("Running Host Basic Memory 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(); + + /* 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 #1\n"); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + if (status != UX_SUCCESS) + { + + printf(" ERROR #2\n"); + test_control_return(1); + } + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_entry); + if (status != UX_SUCCESS) + { + + printf(" ERROR #3\n"); + 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 #4\n"); + 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 #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + + /* Mutex will be created on initialize to protect CDC Bulk IN/OUT */ + for (test_n = 0; test_n < 2; test_n ++) + { + ux_test_utility_sim_mutex_error_generation_start(test_n); + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + /* Mutex error should be reported */ + if(status != UX_MUTEX_ERROR) + { + + printf(" ERROR #6.%ld\n", test_n); + test_control_return(1); + } + } + ux_test_utility_sim_mutex_error_generation_stop(); + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + + if(status!=UX_SUCCESS) + { + + printf(" ERROR #7\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #8\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #9\n"); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #10\n"); + test_control_return(1); + } +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG actual_length; +ULONG test_n; +ULONG mem_free; + + stepinfo("\n"); + + /* Find the cdc_acm class and wait for the link to be up. */ + status = test_class_cdc_acm_get(); + if (status != UX_SUCCESS) + { + + /* DPUMP basic test error. */ + printf("ERROR #11: class not found\n"); + test_control_return(1); + } + if (!cdc_acm_host_control && !cdc_acm_host_data) + { + + printf("ERROR #12: instance not detected\n"); + test_control_return(1); + } + stepinfo("mem free: %ld\n", _ux_system->ux_system_regular_memory_pool_free); + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + if (cdc_acm_host_control || cdc_acm_host_data) + { + + printf("ERROR #13: instance not removed when disconnect"); + test_control_return(1); + } + stepinfo("mem free: %ld\n", _ux_system->ux_system_regular_memory_pool_free); + + /* Reset testing counts. */ + stepinfo(">>>>>>>>>>>>>>>> Test connect & connection resource\n"); + ux_test_utility_sim_mutex_create_count_reset(); + ux_test_utility_sim_sem_create_count_reset(); + ux_test_utility_sim_sem_get_count_reset(); + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + mem_free = _ux_system->ux_system_regular_memory_pool_free; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + tx_thread_sleep(100); + /* Log create counts when SetConfigure for further tests. */ + rsc_enum_mutex_usage = rsc_mutex_on_set_cfg; + rsc_enum_sem_usage = rsc_sem_on_set_cfg; + rsc_enum_sem_get_count = rsc_sem_get_on_set_cfg; + rsc_enum_mem_usage = mem_free - rsc_mem_free_on_set_cfg; + stepinfo("mem free: %ld\n", _ux_system->ux_system_regular_memory_pool_free); + + /* Simulate detach and attach for FS enumeration, + and test possible memory allocation error handlings. + */ + if (rsc_enum_mem_usage) stepinfo(">>>>>>>>>>>>>>>> Memory errors enumeration test\n"); + mem_free = _ux_system->ux_system_regular_memory_pool_free; + for (test_n = 8; test_n <= rsc_enum_mem_usage; test_n += 8) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_enum_mem_usage); + + /* Check memory level */ + if (mem_free != _ux_system->ux_system_regular_memory_pool_free) + { + + printf("ERROR #14.%ld: Memory level different after re-enumerations\n", test_n); + test_control_return(1); + } + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Update memory free level (disconnect) */ + mem_free = _ux_system->ux_system_regular_memory_pool_free; + + /* Set memory free level */ + ux_test_utility_sim_mem_allocate_until(test_n); + + /* Count SetConfigure */ + set_cfg_counter = 0; + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + + /* Connect. */ + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Free memory */ + ux_test_utility_sim_mem_free_all(); + + /* Check error */ + if (set_cfg_counter) + { + + printf("ERROR #15.%ld: device detected when there is memory error\n", test_n); + test_control_return(1); + } + stepinfo("mem free: %ld\n", _ux_system->ux_system_regular_memory_pool_free); + } + if (rsc_enum_mem_usage) stepinfo("\n"); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG requested_length; +ULONG actual_length; +UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_PARAMETER line_coding; +UX_SLAVE_CLASS_CDC_ACM_LINE_STATE_PARAMETER line_state; +UX_SLAVE_CLASS_COMMAND class_command; + +UCHAR data_bit[16]; +VOID* tmp_alloc; +ULONG tmp_alloc_len; + + while(1) + { + + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); + } +} diff --git a/test/regression/usbx_ux_host_class_cdc_acm_activate_test.c b/test/regression/usbx_ux_host_class_cdc_acm_activate_test.c new file mode 100644 index 00000000..4c482d4b --- /dev/null +++ b/test/regression/usbx_ux_host_class_cdc_acm_activate_test.c @@ -0,0 +1,493 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" + +#include "ux_host_class_cdc_acm.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#include "ux_host_stack.h" + +/* Define constants. */ +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +#define CDC_IFC_DESC_ALL(bIfc, bIntIn, bBulkIn, bBulkOut)\ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (bIfc), 0x02, 0x02, 0x02, 0x00, 0x00,\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (bIfc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06, (bIfc), (bIfc + 1),\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03, (bIfc + 1),\ + /* Endpoint interrupt in descriptor 7 bytes */\ + 0x07, 0x05, (bIntIn), 0x02, 0x40, 0x00, 0x00,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (bIfc + 1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint bulk in descriptor 7 bytes */\ + 0x07, 0x05, (bBulkIn), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint bulk out descriptor 7 bytes */\ + 0x07, 0x05, (bBulkOut), 0x02, 0x40, 0x00, 0x00, +#define CDC_IFC_DESC_ALL_LEN (8+ 9+5+4+5+5+7+ 9+7+7) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +static UCHAR cdc_acm_slave_change; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; + +static ULONG error_counter; + +static ULONG error_callback_counter; +static UCHAR error_callback_ignore; + +/* Define device framework. */ + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Configuration 1 descriptor 9 bytes, total 75 bytes */ + CFG_DESC(CFG_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 1) + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor 9 bytes, total 75 bytes */ + CFG_DESC(CFG_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 1) + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT break_on_cdc_acm_all_ready(VOID) +{ +UINT status; +UX_HOST_CLASS *class; + + /* Find the main cdc_acm container */ + status = ux_host_stack_class_get(_ux_system_host_class_cdc_acm_name, &class); + if (status != UX_SUCCESS) + /* Do not break. */ + return 0; + + /* Find class instance. */ + status = ux_host_stack_class_instance_get(class, 0, (void **) &cdc_acm_host_control); + if (status != UX_SUCCESS) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + /* Find class instance. */ + status = ux_host_stack_class_instance_get(class, 1, (void **) &cdc_acm_host_data); + if (status != UX_SUCCESS) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_slave == UX_NULL) + /* Do not break. */ + return 0; + + /* All found, break. */ + return 1; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; +} + +static VOID test_ux_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); + } + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_cdc_acm_activate_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + printf("Running ux_host_class_cdc_acm_activate 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register CDC ACM class */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_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); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register HCD for test */ + 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(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; + + stepinfo("\n"); + + /* Test connect. */ + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + ux_test_breakable_sleep(100, break_on_cdc_acm_all_ready); + if (!(cdc_acm_host_control && cdc_acm_host_data && cdc_acm_slave)) + { + + printf("ERROR #%d: connect fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Deinitialize\n"); + + /* Deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + + /* Deinitialize the device side of usbx. */ + _ux_device_stack_uninitialize(); + + /* And finally the usbx system resources. */ + _ux_system_uninitialize(); + + stepinfo(">>>>>>>>>>>>>>>> Dump results\n"); + + if (error_counter > 0) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + +void tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Sleep so ThreadX on Win32 will delete this thread. */ + ux_utility_delay_ms(100); + } +} diff --git a/test/regression/usbx_ux_host_class_cdc_acm_capabilities_get_test.c b/test/regression/usbx_ux_host_class_cdc_acm_capabilities_get_test.c new file mode 100644 index 00000000..3d1a9cd3 --- /dev/null +++ b/test/regression/usbx_ux_host_class_cdc_acm_capabilities_get_test.c @@ -0,0 +1,582 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" + +#include "ux_host_class_cdc_acm.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#include "ux_host_stack.h" + +/* Define constants. */ +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +#define CDC_IFC_DESC_ALL(bIfc, bIntIn, bBulkIn, bBulkOut)\ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (bIfc), 0x02, 0x02, 0x02, 0x00, 0x00,\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (bIfc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06, (bIfc), (bIfc + 1),\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03, (bIfc + 1),\ + /* Endpoint interrupt in descriptor 7 bytes */\ + 0x07, 0x05, (bIntIn), 0x02, 0x40, 0x00, 0x00,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (bIfc + 1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint bulk in descriptor 7 bytes */\ + 0x07, 0x05, (bBulkIn), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint bulk out descriptor 7 bytes */\ + 0x07, 0x05, (bBulkOut), 0x02, 0x40, 0x00, 0x00, +#define CDC_IFC_DESC_ALL_LEN (8+ 9+5+4+5+5+7+ 9+7+7) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +static UCHAR cdc_acm_slave_change; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; + +static ULONG error_counter; + +static ULONG error_callback_counter; +static UCHAR error_callback_ignore; + +/* Define device framework. */ + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Configuration 1 descriptor 9 bytes, total 75 bytes */ + CFG_DESC(CFG_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 1) + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor 9 bytes, total 75 bytes */ + CFG_DESC(CFG_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 1) + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +static UX_TEST_SETUP _GetCfgDescr = UX_TEST_SETUP_GetCfgDescr; + +static UX_TEST_HCD_SIM_ACTION error_on_GetCfgDescr0[] = { +/* 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, &_GetCfgDescr, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, UX_CONFIGURATION_DESCRIPTOR_LENGTH - 1, UX_SUCCESS, /* Length error! */ + UX_ERROR, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION length_error_on_GetCfgDescr0[] = { +/* 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, &_GetCfgDescr, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, UX_CONFIGURATION_DESCRIPTOR_LENGTH - 1, UX_SUCCESS, /* Length error! */ + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION length_error_on_GetCfgDescr1[] = { +/* 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, &_GetCfgDescr, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, UX_NULL, + UX_TRUE}, /* bypass */ +{ UX_HCD_TRANSFER_REQUEST, &_GetCfgDescr, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, UX_CONFIGURATION_DESCRIPTOR_LENGTH, UX_SUCCESS, /* Length error! */ + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT break_on_cdc_acm_all_ready(VOID) +{ + if (cdc_acm_host_control && cdc_acm_host_data && cdc_acm_slave) + return 1; + + return 0; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; +} + +static VOID test_ux_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); + } + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_cdc_acm_capabilities_get_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + printf("Running ux_host_class_cdc_acm_capabilities_get 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register CDC ACM class */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_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); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register HCD for test */ + 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(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; + + stepinfo("\n"); + + /* Test connect. */ + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + ux_test_breakable_sleep(100, break_on_cdc_acm_all_ready); + if (!(cdc_acm_host_control && cdc_acm_host_data && cdc_acm_slave)) + { + + printf("ERROR #%d: connect fail\n", __LINE__); + test_control_return(1); + } + + /* Test descriptor length error. */ + stepinfo(">>>>>>>>>>>>>>>> Test capabilities_get (length error)\n"); + + /* Request error on 1st try. */ + ux_test_hcd_sim_host_set_actions(error_on_GetCfgDescr0); + status = _ux_host_class_cdc_acm_capabilities_get(cdc_acm_host_control); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: expect fail\n", __LINE__); + error_counter ++; + } + + /* Request length mismatch on 1st try. */ + ux_test_hcd_sim_host_set_actions(length_error_on_GetCfgDescr0); + status = _ux_host_class_cdc_acm_capabilities_get(cdc_acm_host_control); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: fail\n", __LINE__); + error_counter ++; + } + + /* Request length mismatch on 2nd try. */ + ux_test_hcd_sim_host_set_actions(length_error_on_GetCfgDescr1); + status = _ux_host_class_cdc_acm_capabilities_get(cdc_acm_host_control); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: fail\n", __LINE__); + error_counter ++; + } + + /* Request descriptor corrupt. */ + + /* Modify interface descriptor type, expect error. */ + device_framework_full_speed[18 + 9 + 8 + 1] = 0; + status = _ux_host_class_cdc_acm_capabilities_get(cdc_acm_host_control); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: fail\n", __LINE__); + error_counter ++; + } + + /* Restore configuration descriptor length. */ + device_framework_full_speed[18 + 9 + 8 + 1] = UX_INTERFACE_DESCRIPTOR_ITEM; + + /* Request descriptor subclass is UX_HOST_CLASS_CDC_DLC_SUBCLASS. */ + + /* Modify interface descriptor type, expect no error. */ + device_framework_full_speed[18 + 9 + 8 + 6] = UX_HOST_CLASS_CDC_DLC_SUBCLASS; + status = _ux_host_class_cdc_acm_capabilities_get(cdc_acm_host_control); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: fail\n", __LINE__); + error_counter ++; + } + + /* Restore configuration descriptor length. */ + device_framework_full_speed[18 + 9 + 8 + 6] = UX_HOST_CLASS_CDC_ACM_SUBCLASS; + + /* Request descriptor subclass is not expected. */ + + /* Modify interface descriptor type, expect no error. */ + device_framework_full_speed[18 + 9 + 8 + 6] = 0xEE; + status = _ux_host_class_cdc_acm_capabilities_get(cdc_acm_host_control); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: fail\n", __LINE__); + error_counter ++; + } + + /* Restore configuration descriptor length. */ + device_framework_full_speed[18 + 9 + 8 + 6] = UX_HOST_CLASS_CDC_ACM_SUBCLASS; + + /* Deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + + /* Deinitialize the device side of usbx. */ + _ux_device_stack_uninitialize(); + + /* And finally the usbx system resources. */ + _ux_system_uninitialize(); + + if (error_counter > 0) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + +void tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Sleep so ThreadX on Win32 will delete this thread. */ + ux_utility_delay_ms(100); + } +} diff --git a/test/regression/usbx_ux_host_class_cdc_acm_deactivate_test.c b/test/regression/usbx_ux_host_class_cdc_acm_deactivate_test.c new file mode 100644 index 00000000..e6ff5da2 --- /dev/null +++ b/test/regression/usbx_ux_host_class_cdc_acm_deactivate_test.c @@ -0,0 +1,571 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" + +#include "ux_host_class_cdc_acm.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#include "ux_host_stack.h" + +/* Define constants. */ +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +#define CDC_IFC_DESC_ALL(bIfc, bIntIn, bBulkIn, bBulkOut)\ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (bIfc), 0x02, 0x02, 0x02, 0x00, 0x00,\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (bIfc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06, (bIfc), (bIfc + 1),\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03, (bIfc + 1),\ + /* Endpoint interrupt in descriptor 7 bytes */\ + 0x07, 0x05, (bIntIn), 0x02, 0x40, 0x00, 0x00,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (bIfc + 1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint bulk in descriptor 7 bytes */\ + 0x07, 0x05, (bBulkIn), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint bulk out descriptor 7 bytes */\ + 0x07, 0x05, (bBulkOut), 0x02, 0x40, 0x00, 0x00, +#define CDC_IFC_DESC_ALL_LEN (8+ 9+5+4+5+5+7+ 9+7+7) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +static UCHAR cdc_acm_slave_change; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; + +static ULONG error_counter; + +static ULONG error_callback_counter; +static UCHAR error_callback_ignore; + +/* Define device framework. */ + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Configuration 1 descriptor 9 bytes, total 75 bytes */ + CFG_DESC(CFG_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 1) + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor 9 bytes, total 75 bytes */ + CFG_DESC(CFG_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 1) + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +static UX_TEST_SETUP _GetCfgDescr = UX_TEST_SETUP_GetCfgDescr; + +static UX_TEST_HCD_SIM_ACTION error_on_GetCfgDescr0[] = { +/* 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, &_GetCfgDescr, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, UX_CONFIGURATION_DESCRIPTOR_LENGTH - 1, UX_SUCCESS, /* Length error! */ + UX_ERROR, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION length_error_on_GetCfgDescr0[] = { +/* 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, &_GetCfgDescr, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, UX_CONFIGURATION_DESCRIPTOR_LENGTH - 1, UX_SUCCESS, /* Length error! */ + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION length_error_on_GetCfgDescr1[] = { +/* 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, &_GetCfgDescr, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, UX_NULL, + UX_TRUE}, /* bypass */ +{ UX_HCD_TRANSFER_REQUEST, &_GetCfgDescr, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, UX_CONFIGURATION_DESCRIPTOR_LENGTH, UX_SUCCESS, /* Length error! */ + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT break_on_cdc_acm_all_ready(VOID) +{ + if (cdc_acm_host_control && cdc_acm_host_data && cdc_acm_slave) + return 1; + + return 0; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; +} + +static VOID test_ux_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); + } + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_cdc_acm_deactivate_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + printf("Running ux_host_class_cdc_acm_deactivate 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register CDC ACM class */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_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); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register HCD for test */ + 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(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_COMMAND class_command; +UX_CONFIGURATION *configuration; +UX_DEVICE *device; +UX_INTERFACE *interface; + + stepinfo("\n"); + + /* Test connect. */ + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + ux_test_breakable_sleep(100, break_on_cdc_acm_all_ready); + if (!(cdc_acm_host_control && cdc_acm_host_data && cdc_acm_slave)) + { + + printf("ERROR #%d: connect fail\n", __LINE__); + test_control_return(1); + } + + /* Find device */ + status = _ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Find configuration */ + status = _ux_host_stack_device_configuration_get(device, 0, &configuration); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Prepare a DEACTIVATE command. */ + class_command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_DEACTIVATE; + class_command.ux_host_class_command_instance = (VOID *)cdc_acm_host_control; + + /* Get interface. */ + interface = cdc_acm_host_control -> ux_host_class_cdc_acm_interface; + + error_callback_ignore = UX_TRUE; + + /* Simulate semaphore error. */ + stepinfo(">>>>>>>>>>>>>>>> Test ux_host_class_cdc_acm_deactivate::semaphore_get error\n"); + _ux_utility_semaphore_delete(&cdc_acm_host_control->ux_host_class_cdc_acm_semaphore); + status = interface->ux_interface_class->ux_host_class_entry_function(&class_command); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + error_counter ++; + } + + /* Create semaphore. */ + status = _ux_utility_semaphore_create(&cdc_acm_host_control -> ux_host_class_cdc_acm_semaphore, "ux_host_class_cdc_acm_semaphore", 1); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test ux_host_class_cdc_acm_deactivate: without callback\n"); + _ux_system_host->ux_system_host_change_function = UX_NULL; + ux_test_hcd_sim_host_disconnect(); + ux_test_breakable_sleep(100, break_on_removal); + if (cdc_acm_host_control == UX_NULL || cdc_acm_host_data == UX_NULL) + { + + printf("ERROR #%d\n", __LINE__); + error_counter ++; + } + + error_callback_ignore = UX_FALSE; + + stepinfo(">>>>>>>>>>>>>>>> Deinitialize\n"); + + /* Deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + + /* Deinitialize the device side of usbx. */ + _ux_device_stack_uninitialize(); + + /* And finally the usbx system resources. */ + _ux_system_uninitialize(); + + stepinfo(">>>>>>>>>>>>>>>> Dump results\n"); + + if (error_counter > 0) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + +void tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Sleep so ThreadX on Win32 will delete this thread. */ + ux_utility_delay_ms(100); + } +} diff --git a/test/regression/usbx_ux_host_class_cdc_acm_endpoints_get_test.c b/test/regression/usbx_ux_host_class_cdc_acm_endpoints_get_test.c new file mode 100644 index 00000000..2ad1c223 --- /dev/null +++ b/test/regression/usbx_ux_host_class_cdc_acm_endpoints_get_test.c @@ -0,0 +1,579 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" + +#include "ux_host_class_cdc_acm.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#include "ux_host_stack.h" + +/* Define constants. */ +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +#define CDC_IFC_DESC_ALL(bIfc, bIntIn, bBulkIn, bBulkOut)\ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (bIfc), 0x02, 0x02, 0x02, 0x00, 0x00,\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (bIfc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06, (bIfc), (bIfc + 1),\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03, (bIfc + 1),\ + /* Endpoint interrupt in descriptor 7 bytes */\ + 0x07, 0x05, (bIntIn), 0x03, 0x40, 0x00, 0x10,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (bIfc + 1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint bulk in descriptor 7 bytes */\ + 0x07, 0x05, (bBulkIn), 0x02, 0x40, 0x00, 0x01,\ + /* Endpoint bulk out descriptor 7 bytes */\ + 0x07, 0x05, (bBulkOut), 0x02, 0x40, 0x00, 0x01, +#define CDC_IFC_DESC_ALL_LEN (8+ 9+5+4+5+5+7+ 9+7+7) + +#define CDC_IFC_DESC_ALL_1(bIfc, bIntIn, bIntInType, bBulkIn, bBulkInType, bBulkOut, bBulkOutType)\ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (bIfc), 0x02, 0x02, 0x02, 0x00, 0x00,\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (bIfc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06, (bIfc), (bIfc + 1),\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03, (bIfc + 1),\ + /* Endpoint interrupt in descriptor 7 bytes */\ + 0x07, 0x05, (bIntIn), (bIntInType), 0x40, 0x00, 0x10,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (bIfc + 1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint bulk in descriptor 7 bytes */\ + 0x07, 0x05, (bBulkIn), (bBulkInType), 0x40, 0x00, 0x01,\ + /* Endpoint bulk out descriptor 7 bytes */\ + 0x07, 0x05, (bBulkOut), (bBulkOutType), 0x40, 0x00, 0x01, + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +static UCHAR cdc_acm_slave_change; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; + +static ULONG error_counter; + +static ULONG error_callback_counter; +static UCHAR error_callback_ignore; + +/* Define device framework. */ + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Configuration 1 descriptor 9 bytes, total 75 bytes */ + CFG_DESC(CFG_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 1) + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor 9 bytes, total 75 bytes */ + CFG_DESC(CFG_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 1) + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT break_on_cdc_acm_all_ready(VOID) +{ +UINT status; +UX_HOST_CLASS *class; + + /* Find the main cdc_acm container */ + status = ux_host_stack_class_get(_ux_system_host_class_cdc_acm_name, &class); + if (status != UX_SUCCESS) + /* Do not break. */ + return 0; + + /* Find class instance. */ + status = ux_host_stack_class_instance_get(class, 0, (void **) &cdc_acm_host_control); + if (status != UX_SUCCESS) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + /* Find class instance. */ + status = ux_host_stack_class_instance_get(class, 1, (void **) &cdc_acm_host_data); + if (status != UX_SUCCESS) + /* Do not break. */ + return 0; + + if (cdc_acm_host_data->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_slave == UX_NULL) + /* Do not break. */ + return 0; + + /* All found, break. */ + return 1; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + cdc_acm_host_data = UX_NULL; + cdc_acm_host_control = UX_NULL; + + return 1; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; +} + +static VOID test_ux_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); + } + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_cdc_acm_endpoints_get_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + printf("Running ux_host_class_cdc_acm_endpoints_get 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register CDC ACM class */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_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); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 2,0, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 3,0, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#endif + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register HCD for test */ + 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(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_DEVICE *device; + + stepinfo("\n"); + + /* Test connect. */ + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + ux_test_breakable_sleep(100, break_on_cdc_acm_all_ready); + if (!(cdc_acm_host_control && cdc_acm_host_data && cdc_acm_slave)) + { + + printf("ERROR #%d: connect fail\n", __LINE__); + test_control_return(1); + } + + /* Get device instance. */ + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test one of EP is not bulk\n"); + + error_callback_ignore = UX_TRUE; + + /* Disconnect. */ + ux_test_hcd_sim_host_disconnect(); + ux_test_breakable_sleep(100, break_on_removal); + + /* Modify bulk out endpoint type. */ + device_framework_full_speed[DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 4] = 3; + + /* Connect. */ + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + ux_test_breakable_sleep(100, break_on_cdc_acm_all_ready); + if (cdc_acm_host_data) + { + + printf("ERROR %d: data interface must not ready\n", __LINE__); + error_counter ++; + } + + /* Disconnect. */ + ux_test_hcd_sim_host_disconnect(); + ux_test_breakable_sleep(100, break_on_removal); + + /* Modify bulk out endpoint type. */ + device_framework_full_speed[DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 4] = 2; + + /* Modify bulk in endpoint type. */ + device_framework_full_speed[DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 11] = 3; + + /* Connect. */ + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + ux_test_breakable_sleep(100, break_on_cdc_acm_all_ready); + if (cdc_acm_host_data) + { + + printf("ERROR %d: data interface must not ready\n", __LINE__); + error_counter ++; + } + + /* Modify bulk in endpoint type. */ + device_framework_full_speed[DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 11] = 2; + + error_callback_ignore = UX_FALSE; + + stepinfo(">>>>>>>>>>>>>>>> Deinitialize\n"); + + /* Deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + + /* Deinitialize the device side of usbx. */ + _ux_device_stack_uninitialize(); + + /* And finally the usbx system resources. */ + _ux_system_uninitialize(); + + stepinfo(">>>>>>>>>>>>>>>> Dump results\n"); + + if (error_counter > 0) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + +void tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Sleep so ThreadX on Win32 will delete this thread. */ + ux_utility_delay_ms(100); + } +} diff --git a/test/regression/usbx_ux_host_class_cdc_acm_entry_test.c b/test/regression/usbx_ux_host_class_cdc_acm_entry_test.c new file mode 100644 index 00000000..5cf7eed8 --- /dev/null +++ b/test/regression/usbx_ux_host_class_cdc_acm_entry_test.c @@ -0,0 +1,681 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" + +#include "ux_host_class_cdc_acm.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#include "ux_host_stack.h" + +/* Define constants. */ +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +#define IAD_DESC(bIfc) \ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (bIfc), 0x02, 0x02, 0x02, 0x00, 0x00, +#define IAD_DESC_LEN 8 + +#define CDC_IFC_DESC_ALL(bIfc, bIntIn, bBulkIn, bBulkOut)\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (bIfc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06, (bIfc), (bIfc + 1),\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03, (bIfc + 1),\ + /* Endpoint interrupt in descriptor 7 bytes */\ + 0x07, 0x05, (bIntIn), 0x03, 0x40, 0x00, 0x10,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (bIfc + 1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint bulk in descriptor 7 bytes */\ + 0x07, 0x05, (bBulkIn), 0x02, 0x40, 0x00, 0x01,\ + /* Endpoint bulk out descriptor 7 bytes */\ + 0x07, 0x05, (bBulkOut), 0x02, 0x40, 0x00, 0x01, +#define CDC_IFC_DESC_ALL_LEN (9+5+4+5+5+7+ 9+7+7) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +static UCHAR cdc_acm_slave_change; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; + +static ULONG error_counter; + +static ULONG error_callback_counter; +static UCHAR error_callback_ignore; + +/* Define device framework. */ + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Configuration 1 descriptor 9 bytes, total 75 bytes */ + CFG_DESC(CFG_DESC_LEN + IAD_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 1) + /* IAD 8 bytes */ + IAD_DESC(0) + /* CDC_ACM interfaces */ + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor 10 bytes */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor 9 bytes, total 75-8=67 bytes */ + CFG_DESC(CFG_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 1) + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT break_on_cdc_acm_all_ready(VOID) +{ +UINT status; +UINT i; +UX_HOST_CLASS *class; +UX_HOST_CLASS_CDC_ACM *cdc_acm; + + /* Find the main cdc_acm container */ + status = ux_host_stack_class_get(_ux_system_host_class_cdc_acm_name, &class); + if (status != UX_SUCCESS) + /* Do not break. */ + return 0; + + /* Find class instances. */ + for (i = 0; i < 2; i ++) + { + status = ux_host_stack_class_instance_get(class, i, (void **) &cdc_acm); + if (status != UX_SUCCESS) + /* Do not break. */ + return 0; + + switch(cdc_acm->ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass) + { + + case UX_HOST_CLASS_CDC_CONTROL_CLASS: + cdc_acm_host_control = cdc_acm; + break; + + case UX_HOST_CLASS_CDC_DATA_CLASS: + cdc_acm_host_data = cdc_acm; + break; + + default: + break; + } + } + + if (cdc_acm_host_control == UX_NULL || cdc_acm_host_data == UX_NULL) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_host_data->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_slave == UX_NULL) + /* Do not break. */ + return 0; + + /* All found, break. */ + return 1; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + cdc_acm_host_data = UX_NULL; + cdc_acm_host_control = UX_NULL; + + return 1; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; +} + +static VOID test_ux_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); + } + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_cdc_acm_entry_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + printf("Running ux_host_class_cdc_acm_entry 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register CDC ACM class */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_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); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 2,0, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 3,0, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#endif + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register HCD for test */ + 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(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +INT test_n; +UX_DEVICE *device; +UCHAR *framework; +UCHAR speed; +UINT iad_off; +UINT ifc_off; + + stepinfo("\n"); + + /* Test connect. */ + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + ux_test_breakable_sleep(100, break_on_cdc_acm_all_ready); + if (!(cdc_acm_host_control && cdc_acm_host_data && cdc_acm_slave)) + { + + printf("ERROR #%d: connect fail\n", __LINE__); + test_control_return(1); + } + + /* Get device instance. */ + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + + error_callback_ignore = UX_TRUE; + + for (test_n = 0; test_n < 2; test_n ++) + { + + framework = test_n ? device_framework_high_speed : device_framework_full_speed; + speed = test_n ? UX_HIGH_SPEED_DEVICE : UX_FULL_SPEED_DEVICE; + iad_off = (18+9); + ifc_off = test_n ? (18+10+9) : (18+9+8); + + if (test_n == 0) + { + + stepinfo(">>>>>>>>>>>>>>>> Test %s IAD IAD.bClass error\n", test_n ? "no" : "with"); + + /* Modify IAD.bClass. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + ux_test_breakable_sleep(100, break_on_removal); + framework[iad_off + 4] = 4; + + ux_test_dcd_sim_slave_connect(speed); + ux_test_hcd_sim_host_connect(speed); + ux_test_breakable_sleep(100, break_on_cdc_acm_all_ready); + + if (cdc_acm_host_control || cdc_acm_host_data) + { + + printf("ERROR #%d.%d: expect enum fail\n", __LINE__, test_n); + error_counter ++; + } + framework[iad_off + 4] = 2; + + stepinfo(">>>>>>>>>>>>>>>> Test %s IAD IAD.bSubClass error\n", test_n ? "no" : "width"); + + /* Modify IAD.bSubClass. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + ux_test_breakable_sleep(100, break_on_removal); + framework[iad_off + 5] = 4; + + ux_test_dcd_sim_slave_connect(speed); + ux_test_hcd_sim_host_connect(speed); + ux_test_breakable_sleep(100, break_on_cdc_acm_all_ready); + + if (cdc_acm_host_control || cdc_acm_host_data) + { + + printf("ERROR #%d.%d: expect enum fail\n", __LINE__, test_n); + error_counter ++; + } + framework[iad_off + 5] = 2; + + stepinfo(">>>>>>>>>>>>>>>> Test %s IAD IAD.bClass&bSubClass 0&0\n", test_n ? "no" : "with"); + + /* Modify IAD.bClass&bSubClass. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + ux_test_breakable_sleep(100, break_on_removal); + framework[iad_off + 4] = 0; + framework[iad_off + 5] = 0; + + ux_test_dcd_sim_slave_connect(speed); + ux_test_hcd_sim_host_connect(speed); + ux_test_breakable_sleep(100, break_on_cdc_acm_all_ready); + + if (cdc_acm_host_control == UX_NULL) + { + + printf("ERROR #%d.%d: expect enum OK\n", __LINE__, test_n); + error_counter ++; + } + framework[iad_off + 4] = 2; + framework[iad_off + 5] = 2; + + stepinfo(">>>>>>>>>>>>>>>> Test %s IAD IAD.bClass&bSubClass 0&4\n", test_n ? "no" : "with"); + + /* Modify IAD.bClass&bSubClass. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + ux_test_breakable_sleep(100, break_on_removal); + framework[iad_off + 4] = 0; + framework[iad_off + 5] = 4; + + ux_test_dcd_sim_slave_connect(speed); + ux_test_hcd_sim_host_connect(speed); + ux_test_breakable_sleep(100, break_on_cdc_acm_all_ready); + + if (cdc_acm_host_control != UX_NULL) + { + + printf("ERROR #%d.%d: expect enum fail\n", __LINE__, test_n); + error_counter ++; + } + framework[iad_off + 4] = 2; + framework[iad_off + 5] = 2; + } + + stepinfo(">>>>>>>>>>>>>>>> Test %s IAD interface.bClass error\n", test_n ? "no" : "with"); + + /* Modify Interface.bClass. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + ux_test_breakable_sleep(100, break_on_removal); + framework[ifc_off + 5] = 4; + + ux_test_dcd_sim_slave_connect(speed); + ux_test_hcd_sim_host_connect(speed); + ux_test_breakable_sleep(100, break_on_cdc_acm_all_ready); + + if (cdc_acm_host_control) + { + + printf("ERROR #%d.%d: expect control interface fail\n", __LINE__, test_n); + error_counter ++; + } + framework[ifc_off + 5] = 2; + + stepinfo(">>>>>>>>>>>>>>>> Test %s IAD interface.bSubClass error\n", test_n ? "no" : "with"); + + /* Modify Interface.bSubClass. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + ux_test_breakable_sleep(100, break_on_removal); + framework[ifc_off + 6] = 4; + + ux_test_dcd_sim_slave_connect(speed); + ux_test_hcd_sim_host_connect(speed); + ux_test_breakable_sleep(100, break_on_cdc_acm_all_ready); + + if (cdc_acm_host_control) + { + + printf("ERROR #%d.%d: expect control interface fail\n", __LINE__, test_n); + error_counter ++; + } + framework[ifc_off + 6] = 2; + + } + + error_callback_ignore = UX_FALSE; + + stepinfo(">>>>>>>>>>>>>>>> Deinitialize\n"); + + /* Deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + + /* Deinitialize the device side of usbx. */ + _ux_device_stack_uninitialize(); + + /* And finally the usbx system resources. */ + _ux_system_uninitialize(); + + stepinfo(">>>>>>>>>>>>>>>> Dump results\n"); + + if (error_counter > 0) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + +void tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Sleep so ThreadX on Win32 will delete this thread. */ + ux_utility_delay_ms(100); + } +} diff --git a/test/regression/usbx_ux_host_class_cdc_acm_read_test.c b/test/regression/usbx_ux_host_class_cdc_acm_read_test.c new file mode 100644 index 00000000..7c1a854b --- /dev/null +++ b/test/regression/usbx_ux_host_class_cdc_acm_read_test.c @@ -0,0 +1,583 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" + +#include "ux_host_class_cdc_acm.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#include "ux_host_stack.h" + +/* Define constants. */ +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bmAttributes, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + (bmAttributes), 0x00, +#define CFG_DESC_LEN 9 + +#define IAD_DESC(bIfc) \ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (bIfc), 0x02, 0x02, 0x02, 0x00, 0x00, +#define IAD_DESC_LEN 8 + +#define CDC_IFC_DESC_ALL(bIfc, bIntIn, bBulkIn, bBulkOut)\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (bIfc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06, (bIfc), (bIfc + 1),\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03, (bIfc + 1),\ + /* Endpoint interrupt in descriptor 7 bytes */\ + 0x07, 0x05, (bIntIn), 0x03, 0x40, 0x00, 0x10,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (bIfc + 1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint bulk in descriptor 7 bytes */\ + 0x07, 0x05, (bBulkIn), 0x02, 0x40, 0x00, 0x01,\ + /* Endpoint bulk out descriptor 7 bytes */\ + 0x07, 0x05, (bBulkOut), 0x02, 0x40, 0x00, 0x01, +#define CDC_IFC_DESC_ALL_LEN (9+5+4+5+5+7+ 9+7+7) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_simulation_0; +static TX_THREAD tx_test_thread_simulation_1; +static VOID tx_test_thread_simulation_0_entry(ULONG); +static VOID tx_test_thread_simulation_1_entry(ULONG); +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +static UCHAR cdc_acm_slave_change; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; + +static ULONG error_counter; + +static ULONG error_callback_counter; +static UCHAR error_callback_ignore; + +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG test_thread_action; + +/* Define device framework. */ + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Configuration 1 descriptor 9 bytes, total 75 bytes */ + CFG_DESC(CFG_DESC_LEN + IAD_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 0x40, 1) + /* IAD 8 bytes */ + IAD_DESC(0) + /* CDC_ACM interfaces */ + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor 10 bytes */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor 9 bytes, total 75-8=67 bytes */ + CFG_DESC(CFG_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 0x60, 1) + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +static VOID disconnect_after_mutex_on_action_func(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + _ux_system_slave->ux_system_slave_device.ux_slave_device_state = UX_DEVICE_ADDRESSED; +} + +static UX_TEST_HCD_SIM_ACTION disconnect_after_mutex_on[] = { + { + .do_after = UX_TRUE, + .usbx_function = UX_TEST_OVERRIDE_TX_MUTEX_GET, + .wait_option = TX_WAIT_FOREVER, + .action_func = disconnect_after_mutex_on_action_func, + }, + { 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT break_on_cdc_acm_all_ready(VOID) +{ +UINT status; +UINT i; +UX_HOST_CLASS *class; +UX_HOST_CLASS_CDC_ACM *cdc_acm; + + /* Find the main cdc_acm container */ + status = ux_host_stack_class_get(_ux_system_host_class_cdc_acm_name, &class); + if (status != UX_SUCCESS) + /* Do not break. */ + return 0; + + /* Find class instances. */ + for (i = 0; i < 2; i ++) + { + status = ux_host_stack_class_instance_get(class, i, (void **) &cdc_acm); + if (status != UX_SUCCESS) + /* Do not break. */ + return 0; + + switch(cdc_acm->ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass) + { + + case UX_HOST_CLASS_CDC_CONTROL_CLASS: + cdc_acm_host_control = cdc_acm; + break; + + case UX_HOST_CLASS_CDC_DATA_CLASS: + cdc_acm_host_data = cdc_acm; + break; + + default: + break; + } + } + + if (cdc_acm_host_control == UX_NULL || cdc_acm_host_data == UX_NULL) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_host_data->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (_ux_system_slave->ux_system_slave_class_array[0].ux_slave_class_instance == UX_NULL) + /* Do not break. */ + return 0; + + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *)_ux_system_slave->ux_system_slave_class_array[0].ux_slave_class_instance; + + /* All found, break. */ + return 1; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + if (_ux_system_slave->ux_system_slave_class_array[0].ux_slave_class_instance != UX_NULL) + /* Do not break. */ + return 0; + + cdc_acm_host_data = UX_NULL; + cdc_acm_host_control = UX_NULL; + cdc_acm_slave = UX_NULL; + + return 1; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; +} + +static VOID test_ux_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); + } + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_cdc_acm_read_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + printf("Running ux_host_class_cdc_acm_read Test............................. "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register CDC ACM class */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_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); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = UX_NULL; + parameter.ux_slave_class_cdc_acm_instance_deactivate = UX_NULL; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 2,0, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 3,0, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#endif + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register HCD for test */ + 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(&tx_test_thread_simulation_0, "tx test host simulation", tx_test_thread_simulation_0_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_simulation_1, "tx test slave simulation", tx_test_thread_simulation_1_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_NO_ACTIVATE); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +void tx_test_thread_simulation_0_entry(ULONG arg) +{ + +UINT status; +UX_ENDPOINT *endpoint; +ULONG actual_length; + + /* Test connect. */ + stepinfo(">>>>>>>>>>>>>>>> Test connect (FS)\n"); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + ux_test_breakable_sleep(100, break_on_cdc_acm_all_ready); + if (!(cdc_acm_host_control && cdc_acm_host_data && cdc_acm_slave)) + { + + printf("ERROR #%d: connect fail\n", __LINE__); + test_control_return(1); + } + if (_ux_system_slave->ux_system_slave_device.ux_slave_device_state != UX_DEVICE_CONFIGURED) + { + + printf("ERROR %d: device state fail 0x%lx\n", __LINE__, _ux_system_slave->ux_system_slave_device.ux_slave_device_state); + test_control_return(1); + } + + /* Test read. */ + stepinfo(">>>>>>>>>>>>>>>> Test read semaphore error\n"); + + endpoint = cdc_acm_host_data->ux_host_class_cdc_acm_bulk_in_endpoint; + + /* Delete semaphore so it generates error. */ + _ux_utility_semaphore_delete(&endpoint -> ux_endpoint_transfer_request.ux_transfer_request_semaphore); + + status = ux_host_class_cdc_acm_read(cdc_acm_host_data, buffer, 64, &actual_length); + if (status == UX_SUCCESS) + { + printf("ERROR %d: expect fail\n", __LINE__); + error_counter ++; + } + + + /* Restore semaphore. */ + status = _ux_utility_semaphore_create(&endpoint -> ux_endpoint_transfer_request.ux_transfer_request_semaphore, + "ux_transfer_request_semaphore", 0); + if (status != UX_SUCCESS) + { + printf("ERROR %d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Deinitialize\n"); + + /* Deinitialize the class. */ + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + + /* Deinitialize the device side of usbx. */ + _ux_device_stack_uninitialize(); + + /* And finally the usbx system resources. */ + _ux_system_uninitialize(); + + stepinfo(">>>>>>>>>>>>>>>> Dump results\n"); + + if (error_counter > 0) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + +void tx_test_thread_simulation_1_entry(ULONG arg) +{ + + while(1) + { + tx_thread_suspend(&tx_test_thread_simulation_1); + } +} diff --git a/test/regression/usbx_ux_host_class_cdc_acm_transfer_request_completed_test.c b/test/regression/usbx_ux_host_class_cdc_acm_transfer_request_completed_test.c new file mode 100644 index 00000000..ecd82887 --- /dev/null +++ b/test/regression/usbx_ux_host_class_cdc_acm_transfer_request_completed_test.c @@ -0,0 +1,659 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" + +#include "ux_host_class_cdc_acm.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#include "ux_host_stack.h" + +/* Define constants. */ +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bmAttributes, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + (bmAttributes), 0x00, +#define CFG_DESC_LEN 9 + +#define IAD_DESC(bIfc) \ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (bIfc), 0x02, 0x02, 0x02, 0x00, 0x00, +#define IAD_DESC_LEN 8 + +#define CDC_IFC_DESC_ALL(bIfc, bIntIn, bBulkIn, bBulkOut)\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (bIfc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06, (bIfc), (bIfc + 1),\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03, (bIfc + 1),\ + /* Endpoint interrupt in descriptor 7 bytes */\ + 0x07, 0x05, (bIntIn), 0x03, 0x40, 0x00, 0x10,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (bIfc + 1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint bulk in descriptor 7 bytes */\ + 0x07, 0x05, (bBulkIn), 0x02, 0x40, 0x00, 0x01,\ + /* Endpoint bulk out descriptor 7 bytes */\ + 0x07, 0x05, (bBulkOut), 0x02, 0x40, 0x00, 0x01, +#define CDC_IFC_DESC_ALL_LEN (9+5+4+5+5+7+ 9+7+7) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +static UCHAR cdc_acm_slave_change; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; + +static ULONG error_counter; + +static ULONG error_callback_counter; +static UCHAR error_callback_ignore; + +static ULONG call_counter; + +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +/* Define device framework. */ + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Configuration 1 descriptor 9 bytes, total 75 bytes */ + CFG_DESC(CFG_DESC_LEN + IAD_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 0x40, 1) + /* IAD 8 bytes */ + IAD_DESC(0) + /* CDC_ACM interfaces */ + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor 10 bytes */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor 9 bytes, total 75-8=67 bytes */ + CFG_DESC(CFG_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 0x60, 1) + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +/* DCD simulator. */ + +static VOID UX_DCD_CHANGE_STATE_is_called(UX_TEST_ACTION *action, VOID *_params) +{ + call_counter ++; +} + +static UX_TEST_DCD_SIM_ACTION monitor_UX_DCD_CHANGE_STATE[] = { +/* 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_DCD_CHANGE_STATE, NULL, + UX_FALSE, 0, + 0, 0, UX_NULL, 0, 0, + UX_SUCCESS, UX_DCD_CHANGE_STATE_is_called}, +{ 0 } +}; + +static UINT break_on_cdc_acm_all_ready(VOID) +{ +UINT status; +UINT i; +UX_HOST_CLASS *class; +UX_HOST_CLASS_CDC_ACM *cdc_acm; + + /* Find the main cdc_acm container */ + status = ux_host_stack_class_get(_ux_system_host_class_cdc_acm_name, &class); + if (status != UX_SUCCESS) + /* Do not break. */ + return 0; + + /* Find class instances. */ + for (i = 0; i < 2; i ++) + { + status = ux_host_stack_class_instance_get(class, i, (void **) &cdc_acm); + if (status != UX_SUCCESS) + /* Do not break. */ + return 0; + + switch(cdc_acm->ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass) + { + + case UX_HOST_CLASS_CDC_CONTROL_CLASS: + cdc_acm_host_control = cdc_acm; + break; + + case UX_HOST_CLASS_CDC_DATA_CLASS: + cdc_acm_host_data = cdc_acm; + break; + + default: + break; + } + } + + if (cdc_acm_host_control == UX_NULL || cdc_acm_host_data == UX_NULL) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_host_data->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_slave == UX_NULL) + /* Do not break. */ + return 0; + + /* All found, break. */ + return 1; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + cdc_acm_host_data = UX_NULL; + cdc_acm_host_control = UX_NULL; + + return 1; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; +} + +static VOID test_ux_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 ULONG test_notification_type = 0; +static ULONG test_notification_value = 0; +static VOID test_cdc_acm_device_status_change_callback(struct UX_HOST_CLASS_CDC_ACM_STRUCT *cdc_acm, + ULONG notification_type, ULONG notification_value) +{ + + test_notification_type = notification_type; + test_notification_value = notification_value; +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_cdc_acm_transfer_request_completed_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + printf("Running ux_host_class_cdc_acm_transfer_request_completed 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register CDC ACM class */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_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); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 2,0, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 3,0, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#endif + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register HCD for test */ + 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(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_SLAVE_DEVICE *slave_device; +UX_SLAVE_INTERFACE *slave_interface; +UX_SLAVE_ENDPOINT *slave_endpoint; +UX_SLAVE_ENDPOINT *slave_interrupt_endpoint = UX_NULL; +UX_SLAVE_TRANSFER *slave_transfer; +UCHAR *backup_pointer; + + stepinfo("\n"); + + /* Test connect. */ + stepinfo(">>>>>>>>>>>>>>>> Test connect (FS)\n"); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + ux_test_breakable_sleep(100, break_on_cdc_acm_all_ready); + if (!(cdc_acm_host_control && cdc_acm_host_data && cdc_acm_slave)) + { + + printf("ERROR #%d: connect fail\n", __LINE__); + test_control_return(1); + } + + /* Get slave device. */ + slave_device = &_ux_system_slave->ux_system_slave_device; + + /* Get interrupt endpoint. */ + slave_interface = slave_device->ux_slave_device_first_interface; + while(slave_interface) + { + slave_endpoint = slave_interface->ux_slave_interface_first_endpoint; + while(slave_endpoint) + { + if ((slave_endpoint->ux_slave_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) == UX_INTERRUPT_ENDPOINT) + { + slave_interrupt_endpoint = slave_endpoint; + break; + } + slave_endpoint = slave_endpoint->ux_slave_endpoint_next_endpoint; + } + slave_interface = slave_interface->ux_slave_interface_next_interface; + } + if (!slave_interrupt_endpoint) + { + + printf("ERROR #%d: no interrupt endpoint\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Send notification and check callback\n"); + + test_notification_type = 0; + test_notification_value = 0; + + /* Send interrupt request. */ + buffer[UX_HOST_CLASS_CDC_ACM_NPF_REQUEST_TYPE] = 0xA1; + buffer[UX_HOST_CLASS_CDC_ACM_NPF_NOTIFICATION_TYPE] = 0x40; + buffer[UX_HOST_CLASS_CDC_ACM_NPF_VALUE] = 0x03; + buffer[UX_HOST_CLASS_CDC_ACM_NPF_VALUE + 1] = 0x04; + buffer[UX_HOST_CLASS_CDC_ACM_NPF_INDEX] = 0x00; + buffer[UX_HOST_CLASS_CDC_ACM_NPF_INDEX + 1] = 0x00; + + /* Prepare transfer request. */ + slave_transfer = &slave_interrupt_endpoint->ux_slave_endpoint_transfer_request; + backup_pointer = slave_transfer->ux_slave_transfer_request_data_pointer; + slave_transfer->ux_slave_transfer_request_data_pointer = buffer; + + status = _ux_device_stack_transfer_request(slave_transfer, 8, 8); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: transfer error %x\n", __LINE__, status); + test_control_return(1); + } + + /* Wait a while for transfer to complete. */ + _ux_utility_delay_ms(30); + + if (test_notification_type != 0x00) + { + printf("ERROR #%d: type 0x%lx not correct\n", __LINE__, test_notification_type); + error_counter ++; + } + + if (test_notification_value != 0x0000) + { + printf("ERROR #%d: value 0x%lx not correct\n", __LINE__, test_notification_value); + error_counter ++; + } + + /* Enable callback. */ + ux_host_class_cdc_acm_ioctl(cdc_acm_host_control, UX_HOST_CLASS_CDC_ACM_IOCTL_NOTIFICATION_CALLBACK, (VOID *)test_cdc_acm_device_status_change_callback); + + status = _ux_device_stack_transfer_request(slave_transfer, 8, 8); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: transfer error %x\n", __LINE__, status); + test_control_return(1); + } + + /* Wait a while for transfer to complete. */ + _ux_utility_delay_ms(30); + + if (test_notification_type != 0x40) + { + printf("ERROR #%d: type 0x%lx not correct\n", __LINE__, test_notification_type); + error_counter ++; + } + + if (test_notification_value != 0x0403) + { + printf("ERROR #%d: value 0x%lx not correct\n", __LINE__, test_notification_value); + error_counter ++; + } + + /* Reset transfer request (avoid buffer free error). */ + slave_transfer->ux_slave_transfer_request_data_pointer = backup_pointer; + + stepinfo(">>>>>>>>>>>>>>>> Deinitialize\n"); + + /* Deinitialize the class. */ + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + + /* Deinitialize the device side of usbx. */ + _ux_device_stack_uninitialize(); + + /* And finally the usbx system resources. */ + _ux_system_uninitialize(); + + stepinfo(">>>>>>>>>>>>>>>> Dump results\n"); + + if (error_counter > 0) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + +void tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Sleep so ThreadX on Win32 will delete this thread. */ + ux_utility_delay_ms(100); + } +} diff --git a/test/regression/usbx_ux_host_class_cdc_acm_write_test.c b/test/regression/usbx_ux_host_class_cdc_acm_write_test.c new file mode 100644 index 00000000..0f0c125e --- /dev/null +++ b/test/regression/usbx_ux_host_class_cdc_acm_write_test.c @@ -0,0 +1,664 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" + +#include "ux_host_class_cdc_acm.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#include "ux_host_stack.h" + +/* Define constants. */ +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (32768) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bmAttributes, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + (bmAttributes), 0x00, +#define CFG_DESC_LEN 9 + +#define IAD_DESC(bIfc) \ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (bIfc), 0x02, 0x02, 0x02, 0x00, 0x00, +#define IAD_DESC_LEN 8 + +#define CDC_IFC_DESC_ALL(bIfc, bIntIn, bBulkIn, bBulkOut)\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (bIfc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06, (bIfc), (bIfc + 1),\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03, (bIfc + 1),\ + /* Endpoint interrupt in descriptor 7 bytes */\ + 0x07, 0x05, (bIntIn), 0x03, 0x40, 0x00, 0x10,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (bIfc + 1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint bulk in descriptor 7 bytes */\ + 0x07, 0x05, (bBulkIn), 0x02, 0x40, 0x00, 0x01,\ + /* Endpoint bulk out descriptor 7 bytes */\ + 0x07, 0x05, (bBulkOut), 0x02, 0x40, 0x00, 0x01, +#define CDC_IFC_DESC_ALL_LEN (9+5+4+5+5+7+ 9+7+7) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_simulation_0; +static TX_THREAD tx_test_thread_simulation_1; +static VOID tx_test_thread_simulation_0_entry(ULONG); +static VOID tx_test_thread_simulation_1_entry(ULONG); +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_device; +static UCHAR cdc_acm_device_change; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; + +static ULONG error_counter; + +static ULONG error_callback_counter; +static UCHAR error_callback_ignore; + +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; +static UCHAR *device_buffer = buffer; +static UCHAR *host_buffer = &buffer[UX_DEMO_BUFFER_SIZE/2]; +static ULONG device_run_count; +static UINT device_status; +static ULONG device_actual_length; + +static ULONG test_thread_action; + +/* Define device framework. */ + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Configuration 1 descriptor 9 bytes, total 75 bytes */ + CFG_DESC(CFG_DESC_LEN + IAD_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 0x40, 1) + /* IAD 8 bytes */ + IAD_DESC(0) + /* CDC_ACM interfaces */ + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor 10 bytes */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor 9 bytes, total 75-8=67 bytes */ + CFG_DESC(CFG_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 0x60, 1) + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +static VOID disconnect_after_mutex_on_action_func(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + _ux_system_slave->ux_system_slave_device.ux_slave_device_state = UX_DEVICE_ADDRESSED; +} + +static UX_TEST_HCD_SIM_ACTION disconnect_after_mutex_on[] = { + { + .do_after = UX_TRUE, + .usbx_function = UX_TEST_OVERRIDE_TX_MUTEX_GET, + .wait_option = TX_WAIT_FOREVER, + .action_func = disconnect_after_mutex_on_action_func, + }, + { 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT break_on_cdc_acm_all_ready(VOID) +{ +UINT status; +UINT i; +UX_HOST_CLASS *class; +UX_HOST_CLASS_CDC_ACM *cdc_acm; + + /* Find the main cdc_acm container */ + status = ux_host_stack_class_get(_ux_system_host_class_cdc_acm_name, &class); + if (status != UX_SUCCESS) + /* Do not break. */ + return 0; + + /* Find class instances. */ + for (i = 0; i < 2; i ++) + { + status = ux_host_stack_class_instance_get(class, i, (void **) &cdc_acm); + if (status != UX_SUCCESS) + /* Do not break. */ + return 0; + + switch(cdc_acm->ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass) + { + + case UX_HOST_CLASS_CDC_CONTROL_CLASS: + cdc_acm_host_control = cdc_acm; + break; + + case UX_HOST_CLASS_CDC_DATA_CLASS: + cdc_acm_host_data = cdc_acm; + break; + + default: + break; + } + } + + if (cdc_acm_host_control == UX_NULL || cdc_acm_host_data == UX_NULL) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_host_data->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (_ux_system_slave->ux_system_slave_class_array[0].ux_slave_class_instance == UX_NULL) + /* Do not break. */ + return 0; + + cdc_acm_device = (UX_SLAVE_CLASS_CDC_ACM *)_ux_system_slave->ux_system_slave_class_array[0].ux_slave_class_instance; + + /* All found, break. */ + return 1; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + if (_ux_system_slave->ux_system_slave_class_array[0].ux_slave_class_instance != UX_NULL) + /* Do not break. */ + return 0; + + cdc_acm_host_data = UX_NULL; + cdc_acm_host_control = UX_NULL; + cdc_acm_device = UX_NULL; + + return 1; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_device = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_device = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_device_change = UX_TRUE; +} + +static VOID test_ux_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); + } + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_cdc_acm_read_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + printf("Running ux_host_class_cdc_acm_write Test............................ "); +#if !UX_TEST_MULTI_IFC_ON + printf("Skipped\n"); + test_control_return(0); + return; +#endif + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register CDC ACM class */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_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); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = UX_NULL; + parameter.ux_slave_class_cdc_acm_instance_deactivate = UX_NULL; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 2,0, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 3,0, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#endif + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register HCD for test */ + 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(&tx_test_thread_simulation_0, "tx test host simulation", tx_test_thread_simulation_0_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_simulation_1, "tx test slave simulation", tx_test_thread_simulation_1_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 19, 19, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +void tx_test_thread_simulation_0_entry(ULONG arg) +{ + +UINT status; +UX_ENDPOINT *endpoint; +ULONG actual_length; + + /* Test connect. */ + stepinfo(">>>>>>>>>>>>>>>> Test connect (FS)\n"); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + ux_test_breakable_sleep(100, break_on_cdc_acm_all_ready); + if (!(cdc_acm_host_control && cdc_acm_host_data && cdc_acm_device)) + { + + printf("ERROR #%d: connect fail\n", __LINE__); + test_control_return(1); + } + if (_ux_system_slave->ux_system_slave_device.ux_slave_device_state != UX_DEVICE_CONFIGURED) + { + + printf("ERROR %d: device state fail 0x%lx\n", __LINE__, _ux_system_slave->ux_system_slave_device.ux_slave_device_state); + test_control_return(1); + } + + /* Test write ZLP. */ + stepinfo(">>>>>>>>>>>>>>>> Test write ZLP\n"); + + actual_length = ~0ul; + device_status = ~0u; + device_actual_length = 0ul; + device_run_count = 0; + status = ux_host_class_cdc_acm_write(cdc_acm_host_data, host_buffer, 0, &actual_length); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + error_counter ++; + } + if (actual_length != 0) + { + printf("ERROR #%d: %ld\n", __LINE__, actual_length); + error_counter ++; + } + if (device_status != UX_SUCCESS) + { + printf("ERROR #%d: 0x%x\n", __LINE__, device_status); + error_counter ++; + } + if (device_actual_length != 0) + { + printf("ERROR #%d: %ld\n", __LINE__, device_actual_length); + error_counter ++; + } + tx_thread_resume(&tx_test_thread_simulation_1); + + /* Test write 65B. */ + stepinfo(">>>>>>>>>>>>>>>> Test write 65B\n"); + + actual_length = ~0ul; + device_status = ~0u; + device_actual_length = 0ul; + device_run_count = 0; + status = ux_host_class_cdc_acm_write(cdc_acm_host_data, host_buffer, 65, &actual_length); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + error_counter ++; + } + if (actual_length != 65) + { + printf("ERROR #%d: %ld\n", __LINE__, actual_length); + error_counter ++; + } + if (device_status != UX_SUCCESS) + { + printf("ERROR #%d: 0x%x\n", __LINE__, device_status); + error_counter ++; + } + if (device_actual_length != 65) + { + printf("ERROR #%d: %ld\n", __LINE__, device_actual_length); + error_counter ++; + } + tx_thread_resume(&tx_test_thread_simulation_1); + + /* Test write 512B. */ + stepinfo(">>>>>>>>>>>>>>>> Test write 8192B\n"); + + actual_length = ~0ul; + device_status = ~0u; + device_actual_length = 0ul; + device_run_count = 0; + status = ux_host_class_cdc_acm_write(cdc_acm_host_data, host_buffer, 8192, &actual_length); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + error_counter ++; + } + if (actual_length != 8192) + { + printf("ERROR #%d: %ld\n", __LINE__, actual_length); + error_counter ++; + } + if (device_status != UX_SUCCESS) + { + printf("ERROR #%d: 0x%x\n", __LINE__, device_status); + error_counter ++; + } + if (device_actual_length != 8192) + { + printf("ERROR #%d: %ld\n", __LINE__, device_actual_length); + error_counter ++; + } + tx_thread_resume(&tx_test_thread_simulation_1); + + stepinfo(">>>>>>>>>>>>>>>> Deinitialize\n"); + + /* Deinitialize the class. */ + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + + /* Deinitialize the device side of usbx. */ + _ux_device_stack_uninitialize(); + + /* And finally the usbx system resources. */ + _ux_system_uninitialize(); + + stepinfo(">>>>>>>>>>>>>>>> Dump results\n"); + + if (error_counter > 0) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + +void tx_test_thread_simulation_1_entry(ULONG arg) +{ + while(1) + { + if (!cdc_acm_device) + { + _ux_utility_delay_ms(10); + continue; + } + device_status = ux_device_class_cdc_acm_read(cdc_acm_device, buffer, 8192, &device_actual_length); + device_run_count ++; + tx_thread_suspend(&tx_test_thread_simulation_1); + } +} diff --git a/test/regression/usbx_ux_host_class_cdc_ecm_activate_test.c b/test/regression/usbx_ux_host_class_cdc_ecm_activate_test.c new file mode 100644 index 00000000..94ee3829 --- /dev/null +++ b/test/regression/usbx_ux_host_class_cdc_ecm_activate_test.c @@ -0,0 +1,27 @@ +/* Include necessary system files. */ + +#include "usbx_ux_test_cdc_ecm.h" + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_cdc_ecm_activate_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running ux_host_class_cdc_ecm_activate Test............................ "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static void post_init_host() +{ +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_ux_host_class_cdc_ecm_entry_test.c b/test/regression/usbx_ux_host_class_cdc_ecm_entry_test.c new file mode 100644 index 00000000..2b99d30b --- /dev/null +++ b/test/regression/usbx_ux_host_class_cdc_ecm_entry_test.c @@ -0,0 +1,76 @@ +/* This tests the CDC-ECM entry function. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static UCHAR cdc_ecm_thread_suspended; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_cdc_ecm_entry_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running ux_host_class_cdc_ecm_entry Test............................ "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static void post_init_host() +{ + +UX_HOST_CLASS_COMMAND command = {0}; + + /* Test unknown command. */ + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_FUNCTION_NOT_SUPPORTED)); + command.ux_host_class_command_request = 0xff; + UX_TEST_ASSERT(_ux_host_class_cdc_ecm_entry(&command) != UX_SUCCESS); + + /* Test command class is data, but subclass is non-zero. */ + command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_QUERY; + command.ux_host_class_command_usage = UX_HOST_CLASS_COMMAND_USAGE_CSP; + command.ux_host_class_command_class = UX_HOST_CLASS_CDC_DATA_CLASS; + command.ux_host_class_command_subclass = 1; /* non-zero */ + UX_TEST_ASSERT(_ux_host_class_cdc_ecm_entry(&command) != UX_SUCCESS); + + /* Test command class is control, but subclass is not control subclass. */ + command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_QUERY; + command.ux_host_class_command_usage = UX_HOST_CLASS_COMMAND_USAGE_CSP; + command.ux_host_class_command_class = UX_HOST_CLASS_CDC_CONTROL_CLASS; + command.ux_host_class_command_subclass = UX_HOST_CLASS_CDC_ECM_CONTROL_SUBCLASS - 1; + UX_TEST_ASSERT(_ux_host_class_cdc_ecm_entry(&command) != UX_SUCCESS); + + /* Test IAD with class = zero, but subclass = non-zero. */ + command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_QUERY; + command.ux_host_class_command_usage = UX_HOST_CLASS_COMMAND_USAGE_CSP; + command.ux_host_class_command_class = UX_HOST_CLASS_CDC_CONTROL_CLASS; + command.ux_host_class_command_subclass = UX_HOST_CLASS_CDC_ECM_CONTROL_SUBCLASS; + command.ux_host_class_command_iad_class = 0; + command.ux_host_class_command_iad_subclass = 1; + UX_TEST_ASSERT(_ux_host_class_cdc_ecm_entry(&command) != UX_SUCCESS); + + /* Test IAD wrong class. */ + command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_QUERY; + command.ux_host_class_command_usage = UX_HOST_CLASS_COMMAND_USAGE_CSP; + command.ux_host_class_command_class = UX_HOST_CLASS_CDC_CONTROL_CLASS; + command.ux_host_class_command_subclass = UX_HOST_CLASS_CDC_ECM_CONTROL_SUBCLASS; + command.ux_host_class_command_iad_class = 1; + UX_TEST_ASSERT(_ux_host_class_cdc_ecm_entry(&command) != UX_SUCCESS); + + /* Test IAD wrong subclass. */ + command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_QUERY; + command.ux_host_class_command_usage = UX_HOST_CLASS_COMMAND_USAGE_CSP; + command.ux_host_class_command_class = UX_HOST_CLASS_CDC_CONTROL_CLASS; + command.ux_host_class_command_subclass = UX_HOST_CLASS_CDC_ECM_CONTROL_SUBCLASS; + command.ux_host_class_command_iad_class = UX_HOST_CLASS_CDC_CONTROL_CLASS; + command.ux_host_class_command_iad_subclass = UX_HOST_CLASS_CDC_ECM_CONTROL_SUBCLASS - 1; + UX_TEST_ASSERT(_ux_host_class_cdc_ecm_entry(&command) != UX_SUCCESS); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_ux_host_class_cdc_ecm_interrupt_notification_test.c b/test/regression/usbx_ux_host_class_cdc_ecm_interrupt_notification_test.c new file mode 100644 index 00000000..cb97ee6f --- /dev/null +++ b/test/regression/usbx_ux_host_class_cdc_ecm_interrupt_notification_test.c @@ -0,0 +1,112 @@ +/* This tests the _ux_host_class_cdc_ecm_interrupt_notification function. */ + +#include "usbx_ux_test_cdc_ecm.h" + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_cdc_ecm_interrupt_notification_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running ux_host_class_cdc_ecm_interrupt_notification Test........... "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static void post_init_host() +{ + +UX_HOST_CLASS_CDC_ECM my_cdc_ecm; +UX_TRANSFER transfer_request; +UCHAR transfer_request_data[16]; +UX_ENDPOINT endpoint; +ULONG notification_count; + + /** Test the class in shutdown mode. **/ + + my_cdc_ecm.ux_host_class_cdc_ecm_state = UX_HOST_CLASS_INSTANCE_SHUTDOWN; + transfer_request.ux_transfer_request_class_instance = &my_cdc_ecm; + transfer_request.ux_transfer_request_completion_code = UX_SUCCESS; + _ux_host_class_cdc_ecm_interrupt_notification(&transfer_request); + + /** Test non-network connection message. **/ + + /* Create the action to ignore the transfer request. */ + UX_TEST_ACTION action = {0}; + action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + action.function = UX_HCD_TRANSFER_REQUEST; + action.req_action = UX_TEST_MATCH_EP; + action.req_ep_address = 0xff; + action.no_return = 0; + action.status = UX_SUCCESS; + ux_test_add_action_to_main_list(action); + + my_cdc_ecm.ux_host_class_cdc_ecm_state = UX_HOST_CLASS_INSTANCE_LIVE; + transfer_request_data[UX_HOST_CLASS_CDC_ECM_NPF_NOTIFICATION_TYPE] = (UCHAR)(UX_HOST_CLASS_CDC_ECM_NOTIFICATION_NETWORK_CONNECTION - 1); + endpoint.ux_endpoint_device = cdc_ecm_host->ux_host_class_cdc_ecm_device; + endpoint.ux_endpoint_descriptor.bEndpointAddress = 0xff; + + transfer_request.ux_transfer_request_class_instance = &my_cdc_ecm; + transfer_request.ux_transfer_request_data_pointer = transfer_request_data; + transfer_request.ux_transfer_request_endpoint = &endpoint; + transfer_request.ux_transfer_request_completion_code = UX_SUCCESS; + + _ux_host_class_cdc_ecm_interrupt_notification(&transfer_request); + + /** Test receiving LINK UP while link is already up. **/ + ux_test_device_class_cdc_ecm_set_link_state(cdc_ecm_device, 1); + + /** Test receiving LINK UP while link is pending up. **/ + + cdc_ecm_host->ux_host_class_cdc_ecm_link_state = UX_HOST_CLASS_CDC_ECM_LINK_STATE_PENDING_UP; + + /* Save the interrupt count so we know when the host has received the message. */ + notification_count = cdc_ecm_host->ux_host_class_cdc_ecm_notification_count; + + ux_test_device_class_cdc_ecm_set_link_state(cdc_ecm_device, 1); + + /* Now wait for the host to receive it. Luckly, there's an increment count we can check! */ + ux_test_wait_for_value_ulong(&cdc_ecm_host->ux_host_class_cdc_ecm_notification_count, notification_count + 1); + + cdc_ecm_host->ux_host_class_cdc_ecm_link_state = UX_HOST_CLASS_CDC_ECM_LINK_STATE_UP; + + /** Test receiving LINK DOWN while link is already down. **/ + + /* Send the link down event. */ + ux_test_device_class_cdc_ecm_set_link_state(cdc_ecm_device, 0); + + /* Wait for host to set the link to down. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_ulong(&cdc_ecm_host->ux_host_class_cdc_ecm_link_state, 0)); + + /* Save the interrupt count so we know when the host has received the message. */ + notification_count = cdc_ecm_host->ux_host_class_cdc_ecm_notification_count; + + /* Send the link down event again. */ + ux_test_device_class_cdc_ecm_set_link_state(cdc_ecm_device, 0); + + /* Now wait for the host to receive it. Luckly, there's an increment count we can check! */ + ux_test_wait_for_value_ulong(&cdc_ecm_host->ux_host_class_cdc_ecm_notification_count, notification_count + 1); + + /** Test receiving LINK DOWN while link is pending down. **/ + + cdc_ecm_host->ux_host_class_cdc_ecm_link_state = UX_HOST_CLASS_CDC_ECM_LINK_STATE_PENDING_DOWN; + + /* Save the interrupt count so we know when the host has received the message. */ + notification_count = cdc_ecm_host->ux_host_class_cdc_ecm_notification_count; + + ux_test_device_class_cdc_ecm_set_link_state(cdc_ecm_device, 0); + + /* Now wait for the host to receive it. Luckly, there's an increment count we can check! */ + ux_test_wait_for_value_ulong(&cdc_ecm_host->ux_host_class_cdc_ecm_notification_count, notification_count + 1); + + cdc_ecm_host->ux_host_class_cdc_ecm_link_state = UX_HOST_CLASS_CDC_ECM_LINK_STATE_DOWN; +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_ux_host_class_cdc_ecm_mac_address_get_test.c b/test/regression/usbx_ux_host_class_cdc_ecm_mac_address_get_test.c new file mode 100644 index 00000000..6ba17db5 --- /dev/null +++ b/test/regression/usbx_ux_host_class_cdc_ecm_mac_address_get_test.c @@ -0,0 +1,102 @@ +/* This tests the ux_host_class_cdc_ecm_mac_address_get function. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static UCHAR cdc_ecm_thread_suspended; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_cdc_ecm_mac_address_get_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running ux_host_class_cdc_ecm_mac_address_get Test.................. "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +#define CONFIGURATION_INDEX 0 +static UX_TEST_SETUP get_cfg_desc_setup = { + .ux_test_setup_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE, + .ux_test_setup_request = UX_GET_DESCRIPTOR, + .ux_test_setup_value = (USHORT) CONFIGURATION_INDEX | (UX_CONFIGURATION_DESCRIPTOR_ITEM << 8), + .ux_test_setup_index = 0, +}; + +static void post_init_host() +{ + +int i; + + /* Create the matching one. */ + UX_TEST_ACTION get_cfg_desc_match_action = {0}; + get_cfg_desc_match_action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + get_cfg_desc_match_action.function = UX_HCD_TRANSFER_REQUEST; + get_cfg_desc_match_action.req_action = UX_TEST_SETUP_MATCH_REQUEST | UX_TEST_SETUP_MATCH_VALUE | UX_TEST_SETUP_MATCH_INDEX; + get_cfg_desc_match_action.req_setup = &get_cfg_desc_setup; + get_cfg_desc_match_action.no_return = 1; + + /* Create the action that modifies the length. */ + UX_TEST_ACTION get_cfg_desc_modify_length_action = {0}; + get_cfg_desc_modify_length_action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + get_cfg_desc_modify_length_action.function = UX_HCD_TRANSFER_REQUEST; + get_cfg_desc_modify_length_action.req_action = UX_TEST_SETUP_MATCH_REQUEST | UX_TEST_SETUP_MATCH_VALUE | UX_TEST_SETUP_MATCH_INDEX | UX_TEST_SIM_REQ_ANSWER; + get_cfg_desc_modify_length_action.req_setup = &get_cfg_desc_setup; + get_cfg_desc_modify_length_action.req_actual_len = 0xff; + get_cfg_desc_modify_length_action.no_return = 0; + get_cfg_desc_modify_length_action.status = UX_SUCCESS; + + /** Test configuration descriptor invalid transfer length returned. **/ + + /* Since this happens during enumeration, disconnect. */ + ux_test_disconnect_slave_and_host_wait_for_enum_completion(); + + /* In theory, this should be the third time we get the config desc (the first two + happen during enumeration), so we need two matching, and one breaking. */ + for (i = 0; i < UX_RH_ENUMERATION_RETRY; i++) + { + + ux_test_add_action_to_main_list(get_cfg_desc_match_action); + ux_test_add_action_to_main_list(get_cfg_desc_match_action); + ux_test_add_action_to_main_list(get_cfg_desc_modify_length_action); + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED)); + } + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE)); + + /* Now connect so that mac_address_get runs. */ + ux_test_connect_slave_and_host_wait_for_enum_completion(); + + UX_TEST_ASSERT(ux_test_check_actions_empty()); + + /* Disconnect for next test. */ + ux_test_disconnect_slave_and_host_wait_for_enum_completion(); + + /** Test whole configuration descriptor invalid transfer length returned - note that device should still be disconnected from previous test. **/ + + /* In theory, this should be the fourth time we get the config desc (the first two + happen during enumeration, and the third in mac_address_get), so we need three matching, and one breaking. */ + for (i = 0; i < UX_RH_ENUMERATION_RETRY; i++) + { + + ux_test_add_action_to_main_list(get_cfg_desc_match_action); + ux_test_add_action_to_main_list(get_cfg_desc_match_action); + ux_test_add_action_to_main_list(get_cfg_desc_match_action); + ux_test_add_action_to_main_list(get_cfg_desc_modify_length_action); + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED)); + } + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE)); + + /* Now connect so that mac_address_get runs. */ + ux_test_connect_slave_and_host_wait_for_enum_completion(); + + UX_TEST_ASSERT(ux_test_check_actions_empty()); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_ux_host_class_cdc_ecm_transmission_callback_test.c b/test/regression/usbx_ux_host_class_cdc_ecm_transmission_callback_test.c new file mode 100644 index 00000000..1867df8e --- /dev/null +++ b/test/regression/usbx_ux_host_class_cdc_ecm_transmission_callback_test.c @@ -0,0 +1,112 @@ +/* This functions tests the ux_host_class_cdc_ecm_transmission_callback API. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static UCHAR has_host_write_failed_yet; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_cdc_ecm_transmission_callback_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running _ux_host_class_cdc_ecm_transmission_callback Test........... "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static void post_init_host() +{ + +UX_TRANSFER transfer_request; +UX_HOST_CLASS_CDC_ECM my_cdc_ecm; +UX_ENDPOINT endpoint; +NX_PACKET tmp_packet; + + /** Test packet is null (WHAT ARE YOU, INSANE?). **/ + + my_cdc_ecm.ux_host_class_cdc_ecm_link_state = UX_HOST_CLASS_CDC_ECM_LINK_STATE_UP; + my_cdc_ecm.ux_host_class_cdc_ecm_state = UX_HOST_CLASS_INSTANCE_LIVE; + my_cdc_ecm.ux_host_class_cdc_ecm_xmit_queue_head = UX_NULL; + + transfer_request.ux_transfer_request_completion_code = UX_SUCCESS; + transfer_request.ux_transfer_request_class_instance = &my_cdc_ecm; + + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_FATAL_ERROR)); + _ux_host_class_cdc_ecm_transmission_callback(&transfer_request); + + /** Test completion code failure. **/ + + /* Create the action to ignore the transfer request. */ + UX_TEST_ACTION action = {0}; + action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + action.function = UX_HCD_TRANSFER_REQUEST; + action.req_action = UX_TEST_MATCH_EP; + action.req_ep_address = 0xff; + action.no_return = 0; + action.status = UX_SUCCESS; + ux_test_add_action_to_main_list(action); + + my_cdc_ecm.ux_host_class_cdc_ecm_link_state = UX_HOST_CLASS_CDC_ECM_LINK_STATE_UP; + my_cdc_ecm.ux_host_class_cdc_ecm_state = UX_HOST_CLASS_INSTANCE_LIVE; + my_cdc_ecm.ux_host_class_cdc_ecm_xmit_queue_head = (NX_PACKET *)(ALIGN_TYPE)0xffffffff; /* just needs to be non-null */ + + endpoint.ux_endpoint_device = cdc_ecm_host->ux_host_class_cdc_ecm_device; + endpoint.ux_endpoint_descriptor.bEndpointAddress = 0xff; + + transfer_request.ux_transfer_request_class_instance = &my_cdc_ecm; + transfer_request.ux_transfer_request_endpoint = &endpoint; + transfer_request.ux_transfer_request_completion_code = UX_ERROR; + + _ux_host_class_cdc_ecm_transmission_callback(&transfer_request); + + /** Test transfer_request->ux_transfer_request_requested_length == transfer_request -> ux_transfer_request_packet_length **/ + endpoint.ux_endpoint_device->ux_device_state = UX_DEVICE_SUSPENDED; + endpoint.ux_endpoint_descriptor.bEndpointAddress = 0; + transfer_request.ux_transfer_request_requested_length = 512; + transfer_request.ux_transfer_request_packet_length = 512; + transfer_request.ux_transfer_request_class_instance = &my_cdc_ecm; + transfer_request.ux_transfer_request_completion_code = UX_SUCCESS; + + _ux_host_class_cdc_ecm_transmission_callback(&transfer_request); + + /** Test transfer_request->ux_transfer_request_requested_length != transfer_request -> ux_transfer_request_packet_length **/ + endpoint.ux_endpoint_device->ux_device_state = UX_DEVICE_SUSPENDED; + endpoint.ux_endpoint_descriptor.bEndpointAddress = 0; + my_cdc_ecm.ux_host_class_cdc_ecm_link_state = UX_HOST_CLASS_CDC_ECM_LINK_STATE_UP; + my_cdc_ecm.ux_host_class_cdc_ecm_state = UX_HOST_CLASS_INSTANCE_LIVE; + my_cdc_ecm.ux_host_class_cdc_ecm_xmit_queue_head = &tmp_packet; /* just needs to be non-null */ + tmp_packet.nx_packet_queue_next = (NX_PACKET *)(ALIGN_TYPE)0; + transfer_request.ux_transfer_request_requested_length = 510; + transfer_request.ux_transfer_request_packet_length = 512; + transfer_request.ux_transfer_request_class_instance = &my_cdc_ecm; + transfer_request.ux_transfer_request_completion_code = UX_SUCCESS; + + _ux_host_class_cdc_ecm_transmission_callback(&transfer_request); + + /** Test transfer_request->ux_transfer_request_requested_length == 0 **/ + endpoint.ux_endpoint_device->ux_device_state = UX_DEVICE_SUSPENDED; + endpoint.ux_endpoint_descriptor.bEndpointAddress = 0; + my_cdc_ecm.ux_host_class_cdc_ecm_link_state = UX_HOST_CLASS_CDC_ECM_LINK_STATE_UP; + my_cdc_ecm.ux_host_class_cdc_ecm_state = UX_HOST_CLASS_INSTANCE_LIVE; + my_cdc_ecm.ux_host_class_cdc_ecm_xmit_queue_head = &tmp_packet; /* just needs to be non-null */ + tmp_packet.nx_packet_queue_next = (NX_PACKET *)(ALIGN_TYPE)0; + transfer_request.ux_transfer_request_requested_length = 0; + transfer_request.ux_transfer_request_packet_length = 512; + transfer_request.ux_transfer_request_class_instance = &my_cdc_ecm; + transfer_request.ux_transfer_request_completion_code = UX_SUCCESS; + + _ux_host_class_cdc_ecm_transmission_callback(&transfer_request); + + /* Ensure our action was used. */ + UX_TEST_ASSERT(ux_test_check_actions_empty() == UX_TRUE); +} + +static void post_init_device() +{ +} diff --git a/test/regression/usbx_ux_host_class_cdc_ecm_write_test.c b/test/regression/usbx_ux_host_class_cdc_ecm_write_test.c new file mode 100644 index 00000000..ef2b93c7 --- /dev/null +++ b/test/regression/usbx_ux_host_class_cdc_ecm_write_test.c @@ -0,0 +1,66 @@ +/* This functions tests the ux_host_class_cdc_ecm_write API. */ + +#include "usbx_ux_test_cdc_ecm.h" + +static UCHAR has_host_write_failed_yet; + +/* Define what the initial system looks like. */ +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_cdc_ecm_write_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running _ux_host_class_cdc_ecm_write Test........................... "); + + stepinfo("\n"); + + ux_test_cdc_ecm_initialize(first_unused_memory); +} + +static void post_init_host() +{ + + UX_HOST_CLASS_CDC_ECM local_cdc_ecm = {0}; + NX_PACKET *my_packet; + + /** Test packet size error. */ + local_cdc_ecm.ux_host_class_cdc_ecm_state = UX_HOST_CLASS_INSTANCE_LIVE; + UX_TEST_CHECK_SUCCESS(nx_packet_allocate(&packet_pool_host, &my_packet, NX_TCP_PACKET, NX_WAIT_FOREVER)); + my_packet->nx_packet_length = UX_HOST_CLASS_CDC_ECM_NX_PAYLOAD_SIZE + 1; + UX_TEST_ASSERT(ux_host_class_cdc_ecm_write(&local_cdc_ecm, my_packet) != UX_SUCCESS); + +#ifdef UX_HOST_CLASS_CDC_ECM_PACKET_CHAIN_SUPPORT + + /** Test memory not available. */ + ux_test_utility_sim_mem_allocate_until_flagged(UX_HOST_CLASS_CDC_ECM_NX_PAYLOAD_SIZE, UX_CACHE_SAFE_MEMORY); + my_packet->nx_packet_length = UX_HOST_CLASS_CDC_ECM_NX_PAYLOAD_SIZE; + my_packet->nx_packet_next = my_packet; + local_cdc_ecm.ux_host_class_cdc_ecm_xmit_buffer = UX_NULL; + local_cdc_ecm.ux_host_class_cdc_ecm_xmit_queue_head = UX_NULL; + local_cdc_ecm.ux_host_class_cdc_ecm_link_state = UX_HOST_CLASS_CDC_ECM_LINK_STATE_UP; + UX_TEST_ASSERT(ux_host_class_cdc_ecm_write(&local_cdc_ecm, my_packet) != UX_SUCCESS); + ux_test_utility_sim_mem_free_all_flagged(UX_CACHE_SAFE_MEMORY); + my_packet->nx_packet_next = UX_NULL; +#endif + + /** Test instance not live. **/ + + local_cdc_ecm.ux_host_class_cdc_ecm_state = UX_HOST_CLASS_INSTANCE_SHUTDOWN; + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_INSTANCE_UNKNOWN)); + UX_TEST_ASSERT(ux_host_class_cdc_ecm_write(&local_cdc_ecm, 0) != UX_SUCCESS); + + /** Test link state down. **/ + + local_cdc_ecm.ux_host_class_cdc_ecm_state = UX_HOST_CLASS_INSTANCE_LIVE; + local_cdc_ecm.ux_host_class_cdc_ecm_link_state = UX_HOST_CLASS_CDC_ECM_LINK_STATE_DOWN; + UX_TEST_CHECK_SUCCESS(nx_packet_allocate(&packet_pool_host, &my_packet, NX_TCP_PACKET, NX_WAIT_FOREVER)); + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CLASS_CDC_ECM_LINK_STATE_DOWN_ERROR)); + UX_TEST_ASSERT(ux_host_class_cdc_ecm_write(&local_cdc_ecm, my_packet) != UX_SUCCESS); +} + +static void post_init_device() +{ +} diff --git a/test/regression/usbx_ux_host_class_hid_activate_test.c b/test/regression/usbx_ux_host_class_hid_activate_test.c new file mode 100644 index 00000000..00672624 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_activate_test.c @@ -0,0 +1,430 @@ +/* This file tests ux_host_class_hid_activate(). */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_hid_activate_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_activate 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_COMMAND command; +UX_HOST_CLASS host_class; +UX_DEVICE device; +UX_INTERFACE interface; +UX_CONFIGURATION configuration; +// UX_MEMORY_BLOCK *dummy_memory_block_first = (UX_MEMORY_BLOCK *)dummy_usbx_memory; +// UX_MEMORY_BLOCK *original_memory_block = _ux_system -> ux_system_regular_memory_pool_start; +UX_HOST_CLASS_HID *hid_instance; +TX_SEMAPHORE hid_instance_semaphore_copy; +UX_HOST_CLASS *class; + + + /* 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); + } + + /**************************************************/ + /** Test case: _ux_utility_semaphore_create() fails **/ + /**************************************************/ + + /* Find the main HID container */ + status = ux_host_stack_class_get(_ux_system_host_class_hid_name, &class); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + command.ux_host_class_command_container = hid -> ux_host_class_hid_interface; + command.ux_host_class_command_class_ptr = class; + + /* Allocate a hid instance like hid_activate(). */ + hid_instance = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY,sizeof(UX_HOST_CLASS_HID)); + if (hid_instance == UX_NULL) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Create the semaphore like keyboard_activate(). */ + status = _ux_utility_semaphore_create(&hid_instance -> ux_host_class_hid_semaphore, "ux_host_class_hid_semaphore", 1); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Make a copy of the semaphore. */ + hid_instance_semaphore_copy = hid_instance -> ux_host_class_hid_semaphore; + + /* Free the memory so keyboard_activate() uses the same memory as us, which will cause threadx to detect a semaphore duplicate. */ + ux_utility_memory_free(hid_instance); + + status = _ux_host_class_hid_activate(&command); + if (status != UX_SEMAPHORE_ERROR) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* ux_utility_memory_allocate() zero'd out our hid instance semaphore! Good thing we made a copy! */ + hid_instance -> ux_host_class_hid_semaphore = hid_instance_semaphore_copy; + + /* Restore state for next test. */ + status = ux_utility_semaphore_delete(&hid_instance -> ux_host_class_hid_semaphore); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } +#if 0 /* Tested by basic_memory_test */ + /**************************************************/ + /** Test case: hid = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY,sizeof(UX_HOST_CLASS_HID)) fails. **/ + /**************************************************/ + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + dummy_memory_block_first -> ux_memory_block_size = 0; + _ux_system -> ux_system_regular_memory_pool_start = dummy_memory_block_first; + + status = _ux_host_class_hid_activate(&command); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + _ux_system -> ux_system_regular_memory_pool_start = original_memory_block; +#endif + /**************************************************/ + /** Test case: _ux_host_class_hid_configure() fails. **/ + /** Why direct: When called normally, the device is already configured (via ux_host_stack_class_interface_scan, which always happens before hid_activate()), so _ux_host_class_hid_configure() returns immediately. **/ + /**************************************************/ + + /* Make sure we pass _ux_host_stack_class_instance_create(). */ + host_class.ux_host_class_first_instance = UX_NULL; + + /* Make sure _ux_host_class_hid_configure() fails. */ + device.ux_device_state = ~UX_DEVICE_CONFIGURED; + device.ux_device_handle = 0; + + configuration.ux_configuration_device = &device; + interface.ux_interface_configuration = &configuration; + command.ux_host_class_command_container = &interface; + command.ux_host_class_command_class_ptr = &host_class; + + status = _ux_host_class_hid_activate(&command); + if (status != UX_CONFIGURATION_HANDLE_UNKNOWN) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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_hid_client_register_test.c b/test/regression/usbx_ux_host_class_hid_client_register_test.c new file mode 100644 index 00000000..5a6fd37d --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_client_register_test.c @@ -0,0 +1,609 @@ +/* This test concentrates on the ux_host_class_hid_client_register api. */ + +#include "usbx_test_common_hid.h" + +#include "ux_host_class_hid_mouse.h" +#include "ux_host_class_hid_keyboard.h" +#include "ux_host_class_hid_remote_control.h" + + +static UX_HOST_CLASS_HID_MOUSE *mouse; + + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 52 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00, + 0x00, + + /* HID descriptor */ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH), + MSB(HID_MOUSE_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 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_MOUSE_REPORT_LENGTH), + MSB(HID_MOUSE_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 + }; + + +static UINT dummy_hid_client_handler0 (struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler1 (struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler2 (struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler3 (struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler4 (struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler5 (struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler6 (struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler7 (struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler8 (struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler9 (struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler10(struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler11(struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler12(struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler13(struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler14(struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler15(struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler16(struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler17(struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler18(struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler19(struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler20(struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler21(struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler22(struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler23(struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler24(struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler25(struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler26(struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler27(struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler28(struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler29(struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler30(struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} +static UINT dummy_hid_client_handler31(struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *command) {return 0;} + +#define NUM_DUMMY_HID_CLIENT_HANDLERS 32 +static UINT (*dummy_hid_client_handlers[NUM_DUMMY_HID_CLIENT_HANDLERS])(struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *) = { + dummy_hid_client_handler0, + dummy_hid_client_handler1, + dummy_hid_client_handler2, + dummy_hid_client_handler3, + dummy_hid_client_handler4, + dummy_hid_client_handler5, + dummy_hid_client_handler6, + dummy_hid_client_handler7, + dummy_hid_client_handler8, + dummy_hid_client_handler9, + dummy_hid_client_handler10, + dummy_hid_client_handler11, + dummy_hid_client_handler12, + dummy_hid_client_handler13, + dummy_hid_client_handler14, + dummy_hid_client_handler15, + dummy_hid_client_handler16, + dummy_hid_client_handler17, + dummy_hid_client_handler18, + dummy_hid_client_handler19, + dummy_hid_client_handler20, + dummy_hid_client_handler21, + dummy_hid_client_handler22, + dummy_hid_client_handler23, + dummy_hid_client_handler24, + dummy_hid_client_handler25, + dummy_hid_client_handler26, + dummy_hid_client_handler27, + dummy_hid_client_handler28, + dummy_hid_client_handler29, + dummy_hid_client_handler30, + dummy_hid_client_handler31, +}; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_hid_client_register_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +ULONG dummy_hid_client_handler_idx; + + /* Inform user. */ + printf("Running ux_host_class_hid_client_register 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); + } + + /* Register client before we've registered hid class. */ + status = ux_host_class_hid_client_register(_ux_system_host_class_hid_client_mouse_name, ux_host_class_hid_mouse_entry); + 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 multiple HID clients. */ + + /* Register mouse client. */ + status = ux_host_class_hid_client_register(_ux_system_host_class_hid_client_mouse_name, ux_host_class_hid_mouse_entry); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Register keyboard client. */ + 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\n", __LINE__); + test_control_return(1); + } + + /* Register remote control client. */ + status = ux_host_class_hid_client_register(_ux_system_host_class_hid_client_remote_control_name, ux_host_class_hid_remote_control_entry); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Register remote control client again. */ + status = ux_host_class_hid_client_register(_ux_system_host_class_hid_client_remote_control_name, ux_host_class_hid_remote_control_entry); + if (status != UX_HOST_CLASS_ALREADY_INSTALLED) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Register too many clients. */ + for (dummy_hid_client_handler_idx = 0; dummy_hid_client_handler_idx < NUM_DUMMY_HID_CLIENT_HANDLERS; dummy_hid_client_handler_idx++) + { + status = ux_host_class_hid_client_register("dummy_name", dummy_hid_client_handlers[dummy_hid_client_handler_idx]); + if (status == UX_MEMORY_ARRAY_FULL) + break; + } + + if (status != UX_MEMORY_ARRAY_FULL) + { + + printf("Error on line %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 on line %d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the hid class parameters for a mouse. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_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); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, 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; +UINT max_num_loops; +UINT num_loops; +ULONG num_attempts; +ULONG max_attempts; +SLONG cur_mouse_wheel_movement; +SLONG next_mouse_wheel_movement; +SLONG cur_mouse_x_position; +SLONG cur_mouse_y_position; +SLONG next_mouse_x_position; +SLONG next_mouse_y_position; +ULONG cur_mouse_buttons; +UCHAR next_mouse_buttons; + + /* Initilize max loop value. */ + max_num_loops = 4; + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the mouse instance */ + mouse = (UX_HOST_CLASS_HID_MOUSE *)hid_client -> ux_host_class_hid_client_local_instance; + + /* Set number of successful loops to execute. */ + num_loops = 0; + max_num_loops = 16; + + /* Set number of fails. */ + num_attempts = 0; + max_attempts = 3*max_num_loops; + + /* Set initial mouse button values. */ + next_mouse_buttons = 0x01; + + /* Set initial mouse position values. */ + next_mouse_x_position = -8; + next_mouse_y_position = -8; + + /* Set initial mouse wheel value. */ + next_mouse_wheel_movement = -8; + + while (num_loops++ != max_num_loops) + { + + while (1) + { + + status = ux_host_class_hid_mouse_buttons_get(mouse, &cur_mouse_buttons); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + status = ux_host_class_hid_mouse_position_get(mouse, &cur_mouse_x_position, &cur_mouse_y_position); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + status = ux_host_class_hid_mouse_wheel_get(mouse, &cur_mouse_wheel_movement); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Are these the expected values? */ + if (cur_mouse_buttons == next_mouse_buttons && + cur_mouse_x_position == next_mouse_x_position && + cur_mouse_y_position == next_mouse_y_position && + cur_mouse_wheel_movement == next_mouse_wheel_movement) + break; + + /* Have we hit the max number of attempts? */ + if (num_attempts++ == max_attempts) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Sleep for 1 second. The device sleeps for twice as long. */ + ux_utility_thread_sleep(10); + } + + /* Increment values. */ + next_mouse_buttons = 0x07 & (next_mouse_buttons + 1); + next_mouse_x_position++; + next_mouse_y_position++; + next_mouse_wheel_movement++; + } + + /* 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); +} + +static void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + +UX_SLAVE_DEVICE *device; +UX_SLAVE_INTERFACE *interface; +UX_SLAVE_CLASS_HID *hid; +UX_SLAVE_CLASS_HID_EVENT hid_event; + + /* Get the pointer to the device. */ + device = &_ux_system_slave -> ux_system_slave_device; + + /* reset the HID event structure. */ + ux_utility_memory_set(&hid_event, 0, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + + /* Set length of event. */ + hid_event.ux_device_class_hid_event_length = 4; + + /* Set initial value for buttons. The first three bits are for buttons, the rest are padding. */ + hid_event.ux_device_class_hid_event_buffer[0] = 1; + + /* Set initial value for x and y positions. */ + hid_event.ux_device_class_hid_event_buffer[1] = -8; + hid_event.ux_device_class_hid_event_buffer[2] = -8; + + /* Set initial value for mouse wheel. */ + hid_event.ux_device_class_hid_event_buffer[3] = -8; + + while (1) + { + + /* Is the device configured ? */ + while (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED) + + /* Then wait. */ + tx_thread_sleep(10); + + /* Until the device stays configured. */ + while (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED) + { + + /* Get the interface. We use the first interface, this is a simple device. */ + interface = device -> ux_slave_device_first_interface; + + /* From that interface, derive the HID owner. */ + hid = interface -> ux_slave_interface_class_instance; + + /* Sleep for 2 seconds. The host sleeps half as long. */ + ux_utility_thread_sleep(20); + + /* Set the mouse event. */ + ux_device_class_hid_event_set(hid, &hid_event); + + /* Change the buttons. */ + hid_event.ux_device_class_hid_event_buffer[0] = (0x7 & hid_event.ux_device_class_hid_event_buffer[0] + 1); + + /* Change the x, y, and wheel positions. These are relative values. */ + hid_event.ux_device_class_hid_event_buffer[1] = 1; + hid_event.ux_device_class_hid_event_buffer[2] = 1; + hid_event.ux_device_class_hid_event_buffer[3] = 1; + } + } +} + diff --git a/test/regression/usbx_ux_host_class_hid_client_register_test2.c b/test/regression/usbx_ux_host_class_hid_client_register_test2.c new file mode 100644 index 00000000..397bd842 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_client_register_test2.c @@ -0,0 +1,342 @@ +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_hid_client_register_test2_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_client_register Test2..................... "); + + /* 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_MEMORY_BLOCK *dummy_memory_block_first = (UX_MEMORY_BLOCK *)dummy_usbx_memory; +UX_MEMORY_BLOCK *original_memory_block = (UX_MEMORY_BLOCK*)_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start; +UCHAR invalid_name[UX_HOST_CLASS_HID_MAX_CLIENT_NAME_LENGTH+2]; + + /* 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); + } + + /**************************************************/ + /** Test case: corrupt hid_client_name **/ + /**************************************************/ + _ux_utility_memory_set(invalid_name, ' ', sizeof(invalid_name)); + _ux_utility_memory_copy(invalid_name, _ux_system_host_class_hid_client_keyboard_name, 33); + status = _ux_host_class_hid_client_register(invalid_name, ux_host_class_hid_keyboard_entry); + if (status != UX_ERROR) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + + /**************************************************/ + /** Test case: class -> ux_host_class_client = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, + sizeof(UX_HOST_CLASS_HID_CLIENT)*UX_HOST_CLASS_HID_MAX_CLIENTS); fails **/ + /**************************************************/ + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_byte_pool = UX_NULL; + // dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + // dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + // dummy_memory_block_first -> ux_memory_block_size = 0; + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start = (UCHAR*)dummy_memory_block_first; + + status = _ux_host_class_hid_client_register(_ux_system_host_class_hid_client_keyboard_name, ux_host_class_hid_keyboard_entry); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start = (UCHAR*)original_memory_block; + + /* 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_hid_client_search_test.c b/test/regression/usbx_ux_host_class_hid_client_search_test.c new file mode 100644 index 00000000..043673d7 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_client_search_test.c @@ -0,0 +1,291 @@ +/* This test ensures that USBX continues working when none of the registered HID clients match the device's report descriptor. */ + +#include "usbx_test_common_hid.h" + +#include "ux_host_class_hid_keyboard.h" + +static UINT callback_error_code; + +static UCHAR hid_report_descriptor[] = { + + /* Set usage page and usage to unknown values */ + 0x07, 0xde, 0xad, 0xbe, 0xef, // USAGE_PAGE (???) + 0x0b, 0xde, 0xad, 0xbe, 0xef, // USAGE (???) + 0xa1, 0x01, // COLLECTION (Application) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_HOST_CLASS_HID_UNKNOWN) + { + + /* 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_client_search_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 ux_host_class_hid_client_search.c 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\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 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); + } + + /* 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_hid_configure_test.c b/test/regression/usbx_ux_host_class_hid_configure_test.c new file mode 100644 index 00000000..22eefba6 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_configure_test.c @@ -0,0 +1,427 @@ +/* This file tests ux_host_class_hid_configure() */ + +#include "usbx_test_common_hid.h" + +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR error_callback_expected = UX_FALSE; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (!error_callback_expected) + { + + /* 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_configure_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_configure 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, error code 0x%x\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code 0x%x\n", __LINE__, status); + 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, error code 0x%x\n", __LINE__, status); + 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 0x%x\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, error code 0x%x\n", __LINE__, status); + 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, error code 0x%x\n", __LINE__, status); + 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, error code 0x%x\n", __LINE__, status); + 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, error code 0x%x\n", __LINE__, status); + 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, error code 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_DEVICE parent; +ULONG tmp; + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /**************************************************/ + /** Why direct: Under normal circumstances, the device is already configured by the time this is called, so it exits at the beginning. **/ + /**************************************************/ + /**************************************************/ + + /**************************************************/ + /** Test case: Successful and complete execution. **/ + /** Why direct: See the function-level NOTE. **/ + /**************************************************/ + + /* Make sure we succeed. */ + tmp = hid -> ux_host_class_hid_device -> ux_device_state; + hid -> ux_host_class_hid_device -> ux_device_state = ~UX_DEVICE_CONFIGURED; + + status = _ux_host_class_hid_configure(hid); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + hid -> ux_host_class_hid_device -> ux_device_state = tmp; + + /**************************************************/ + /** Test case: Bus power but no parent. **/ + /** Why direct: See the function-level NOTE. **/ + /**************************************************/ + + /* Set up power source. */ + hid -> ux_host_class_hid_device -> ux_device_power_source = UX_DEVICE_BUS_POWERED; + + /* Set up parent. */ + parent.ux_device_power_source = UX_DEVICE_SELF_POWERED; + + /* Make sure we succeed. */ + tmp = hid -> ux_host_class_hid_device -> ux_device_state; + hid -> ux_host_class_hid_device -> ux_device_state = ~UX_DEVICE_CONFIGURED; + + status = _ux_host_class_hid_configure(hid); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + hid -> ux_host_class_hid_device -> ux_device_state = tmp; + +#if UX_MAX_DEVICES > 1 + /**************************************************/ + /** Test case: Bus power and parent power source OK. **/ + /** Why direct: See the function-level NOTE. **/ + /**************************************************/ + + /* Set up parent. */ + hid -> ux_host_class_hid_device -> ux_device_parent = &parent; + + /* Make sure we succeed. */ + tmp = hid -> ux_host_class_hid_device -> ux_device_state; + hid -> ux_host_class_hid_device -> ux_device_state = ~UX_DEVICE_CONFIGURED; + + status = _ux_host_class_hid_configure(hid); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + hid -> ux_host_class_hid_device -> ux_device_state = tmp; + + /**************************************************/ + /** Test case: Bus power and parent power source NK. **/ + /** Why direct: See the function-level NOTE. **/ + /**************************************************/ + + /* Set up parent. */ + parent.ux_device_power_source = UX_DEVICE_BUS_POWERED; + + /* Make sure we succeed. */ + tmp = hid -> ux_host_class_hid_device -> ux_device_state; + hid -> ux_host_class_hid_device -> ux_device_state = ~UX_DEVICE_CONFIGURED; + + error_callback_expected = UX_TRUE; + + status = _ux_host_class_hid_configure(hid); + if (status == UX_SUCCESS) + { + + printf("Error on line %d, error code 0x%x\n", __LINE__, status); + test_control_return(1); + } +#endif + error_callback_expected = UX_FALSE; + + /* Restore state for next test. */ + hid -> ux_host_class_hid_device -> ux_device_state = tmp; + + /* 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_hid_deactivate_test.c b/test/regression/usbx_ux_host_class_hid_deactivate_test.c new file mode 100644 index 00000000..eaf23c5b --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_deactivate_test.c @@ -0,0 +1,390 @@ +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UINT device_removed; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + + if(a == UX_DEVICE_REMOVAL) + { + device_removed = 1; + } + + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_HOST_CLASS_HID_UNKNOWN) + { + + /* 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_deactivate_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_deactivate 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static UINT ux_hcd_sim_host_entry_filter_device_extraction_test(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; + + switch(function) + { + case UX_HCD_GET_PORT_STATUS: + + /* No device on this port. */ + status = 0; + + /* This is a Full speed device. */ + status |= UX_PS_DS_FS; + + break; + + + default: + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + break; + } + + return status; +} + +static UINT demo_class_hid_check(void) +{ + +UINT status; +UX_HOST_CLASS *class; + + /* Find the main HID container */ + status = ux_host_stack_class_get(_ux_system_host_class_hid_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* We get the first instance of the hid device */ + status = ux_host_stack_class_instance_get(class, 0, (void **) &hid); + if (status != UX_SUCCESS) + return(UX_HOST_CLASS_INSTANCE_UNKNOWN); + + /* We still need to wait for the hid status to be live */ + if (hid -> ux_host_class_hid_state != UX_HOST_CLASS_INSTANCE_LIVE) + return(UX_HOST_CLASS_INSTANCE_UNKNOWN); + + return(UX_SUCCESS); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HCD *hcd; + + /* Find the HID class */ + do { + status = demo_class_hid_get(); + } while(status == UX_HOST_CLASS_INSTANCE_UNKNOWN); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: if (hid -> ux_host_class_hid_client != UX_NULL) failure **/ + /** How: we do this by not registering any hid clients. ** + /**************************************************/ + + hcd = UX_DEVICE_HCD_GET(hid -> ux_host_class_hid_device); + + /* Change the HCD entry function to our filter function. */ + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter_device_extraction_test; + + /* Signal port activity to the enum thread. */ + hcd -> ux_hcd_root_hub_signal[0] = 1; + + /* Signal enum thread. */ + _ux_utility_semaphore_put(&_ux_system_host -> ux_system_host_enum_semaphore); + + /* Wait for device removed signal. */ + while(demo_class_hid_get() == UX_SUCCESS) + tx_thread_sleep(10); + + /* 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_hid_deactivate_test2.c b/test/regression/usbx_ux_host_class_hid_deactivate_test2.c new file mode 100644 index 00000000..2870e4bc --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_deactivate_test2.c @@ -0,0 +1,371 @@ +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UINT device_removed; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + + if(a == UX_DEVICE_REMOVAL) + { + device_removed = 1; + } + + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_hid_deactivate_test2_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_deactivate Test 2......................... "); + + /* 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static UINT ux_hcd_sim_host_entry_filter_device_extraction_test(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; + + switch(function) + { + case UX_HCD_GET_PORT_STATUS: + + /* No device on this port. */ + status = 0; + + /* This is a Full speed device. */ + status |= UX_PS_DS_FS; + + break; + + + default: + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + break; + } + + return status; +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HCD *hcd; + + + /* 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); + } + + /**************************************************/ + /** Test case: if (transfer_request -> ux_transfer_request_data_pointer != UX_NULL) failure **/ + /** Why direct: there doesn't seem to be a way to set ux_transfer_request_data_pointer to null... **/ + /**************************************************/ + + /* Set data pointer to null */ + hid -> ux_host_class_hid_interrupt_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_data_pointer = UX_NULL; + + /* Retrieve hcd */ + hcd = UX_DEVICE_HCD_GET(hid -> ux_host_class_hid_device); + + /* Change the HCD entry function to our filter function. */ + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter_device_extraction_test; + + /* Signal port activity to the enum thread. */ + hcd -> ux_hcd_root_hub_signal[0] = 1; + + /* Signal enum thread. */ + _ux_utility_semaphore_put(&_ux_system_host -> ux_system_host_enum_semaphore); + + /* Wait for device removed signal. */ + while(!device_removed) + tx_thread_sleep(10); + + /* 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_hid_deactivate_test3.c b/test/regression/usbx_ux_host_class_hid_deactivate_test3.c new file mode 100644 index 00000000..54ae5ca2 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_deactivate_test3.c @@ -0,0 +1,339 @@ +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UINT device_removed; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_hid_deactivate_test3_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_deactivate Test 3......................... "); + + /* 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_KEYBOARD *keyboard; +UX_HOST_CLASS_COMMAND command; + + + /* 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); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the keyboard instance */ + keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)hid_client -> ux_host_class_hid_client_local_instance; + + /**************************************************/ + /** Test case: _ux_utility_semaphore_get(&hid -> ux_host_class_hid_semaphore, UX_WAIT_FOREVER); fails **/ + /**************************************************/ + + command.ux_host_class_command_instance = hid; + + /* Make sure it fails. */ + hid -> ux_host_class_hid_semaphore.tx_semaphore_id++; + + status = _ux_host_class_hid_deactivate(&command); + if(status != TX_SEMAPHORE_ERROR) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state. */ + hid -> ux_host_class_hid_semaphore.tx_semaphore_id--; + + /* 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_hid_descriptor_parse_coverage_test.c b/test/regression/usbx_ux_host_class_hid_descriptor_parse_coverage_test.c new file mode 100644 index 00000000..b754b88f --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_descriptor_parse_coverage_test.c @@ -0,0 +1,69 @@ +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" +#include "ux_test.h" +#include "ux_host_class_hid.h" +#include "ux_test_utility_sim.h" + +#define UX_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +static UX_HOST_CLASS_HID hid; +static UX_DEVICE hid_device; +static UX_CONFIGURATION config; +static UCHAR packed_configuration[100]; +// static UX_SYSTEM ux_system; +UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_hid_descriptor_parse_coverage_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status = 0; +UCHAR total_configuration_length = 5; + UINT descriptor_type = 0; +CHAR *stack_pointer; +CHAR *memory_pointer; + + /* Inform user. */ + printf("Running USB host Class HID Descriptor Parse Converge Coverage 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); + if (status != UX_SUCCESS) + { + printf("ux_system_initialize failed! status = %d\n", status); + test_control_return(status); + return; + } + + // _ux_system = &ux_system; + hid.ux_host_class_hid_device = &hid_device; + hid_device.ux_device_current_configuration = &config; + config.ux_configuration_descriptor.wTotalLength = total_configuration_length; + hid_device.ux_device_packed_configuration = packed_configuration; + packed_configuration[0] = total_configuration_length + 1; + packed_configuration[1] = descriptor_type; + _ux_host_class_hid_descriptor_parse(&hid); + + packed_configuration[0] = total_configuration_length; + packed_configuration[1] = descriptor_type; + _ux_host_class_hid_descriptor_parse(&hid); + + + printf("SUCCESS!\n"); + + test_control_return(0); + return; +} diff --git a/test/regression/usbx_ux_host_class_hid_descriptor_parse_test.c b/test/regression/usbx_ux_host_class_hid_descriptor_parse_test.c new file mode 100644 index 00000000..1622d2c2 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_descriptor_parse_test.c @@ -0,0 +1,501 @@ +/* This file tests ux_host_class_hid_descriptor_parse() */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_hid_descriptor_parse_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_descriptor_parse 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static UINT ux_hcd_sim_host_entry_filter(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; + + + switch(function) + { + case UX_HCD_TRANSFER_REQUEST: + + status = UX_ERROR; + + break; + + + default: + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + break; + } + + return status; +} + +static UINT ux_hcd_sim_host_entry_filter_descriptor_too_small_test(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; +UX_TRANSFER *transfer_request; + + + switch(function) + { + case UX_HCD_TRANSFER_REQUEST: + + transfer_request = (UX_TRANSFER *)parameter; + + /* Set the total configuration length to be greater than 0. */ + transfer_request -> ux_transfer_request_data_pointer[2] = 0x01; + + /* Set the first descriptor length to be less than 3. */ + transfer_request -> ux_transfer_request_data_pointer[0] = 0x00; + + transfer_request -> ux_transfer_request_actual_length = transfer_request -> ux_transfer_request_requested_length; + + status = UX_SUCCESS; + + break; + + + default: + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + break; + } + + return status; +} + +static UINT ux_hcd_sim_host_entry_filter_descriptor_too_large_test(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; +UX_TRANSFER *transfer_request; + + + switch(function) + { + case UX_HCD_TRANSFER_REQUEST: + + transfer_request = (UX_TRANSFER *)parameter; + + /* Set the total configuration length to be greater than 0. */ + transfer_request -> ux_transfer_request_data_pointer[2] = 0x01; + + /* Set the first descriptor length to be greater than the total configuration length and at least 3. */ + transfer_request -> ux_transfer_request_data_pointer[0] = 0x03; + + transfer_request -> ux_transfer_request_actual_length = transfer_request -> ux_transfer_request_requested_length; + + status = UX_SUCCESS; + + break; + + + default: + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + break; + } + + return status; +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HCD *hcd; +ALIGN_TYPE tmp; +// UX_MEMORY_BLOCK *dummy_memory_block_first = (UX_MEMORY_BLOCK *)dummy_usbx_memory; +// UX_MEMORY_BLOCK *original_regular_memory_block = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start; +// UX_MEMORY_BLOCK *original_cache_safe_memory_block = _ux_system -> ux_system_cache_safe_memory_pool_start; + + + /* 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); + } +#if 0 /* Covered in basic memory tests. */ + /**************************************************/ + /** Test case: descriptor = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_CONFIGURATION_DESCRIPTOR_LENGTH); fails **/ + /**************************************************/ + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + dummy_memory_block_first -> ux_memory_block_size = 0; + _ux_system -> ux_system_regular_memory_pool_start = dummy_memory_block_first; + _ux_system -> ux_system_cache_safe_memory_pool_start = dummy_memory_block_first; + + status = _ux_host_class_hid_descriptor_parse(hid); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + _ux_system -> ux_system_regular_memory_pool_start = original_regular_memory_block; + _ux_system -> ux_system_cache_safe_memory_pool_start = original_cache_safe_memory_block; +#endif + /**************************************************/ + /** Test case: ux_host_stack_transfer_request() failed. **/ + /** Why direct: To fail normally, I'd have to replace the entry function and somehow distinguish GET_DESCRIPTOR requests. **/ + /**************************************************/ + + /* Replace the entry function. */ + hcd = UX_DEVICE_HCD_GET(hid -> ux_host_class_hid_device); + tmp = (ALIGN_TYPE)hcd -> ux_hcd_entry_function; + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter; + + status = _ux_host_class_hid_descriptor_parse(hid); + if(status != UX_DESCRIPTOR_CORRUPTED) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + hcd -> ux_hcd_entry_function = (UINT (*) (struct UX_HCD_STRUCT *, UINT, VOID *))tmp; + + /**************************************************/ + /** Test case: if (descriptor_length < 3) **/ + /** Why direct: To fail normally, I'd have to replace the entry function and somehow distinguish GET_DESCRIPTOR requests + OR pass a malformed descriptor, but then the device stack would've errored out before. **/ + /**************************************************/ + + /* Replace the entry function. */ + hcd = UX_DEVICE_HCD_GET(hid -> ux_host_class_hid_device); + tmp = (ALIGN_TYPE)hcd -> ux_hcd_entry_function; + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter_descriptor_too_small_test; + + status = _ux_host_class_hid_descriptor_parse(hid); + if(status != UX_DESCRIPTOR_CORRUPTED) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + hcd -> ux_hcd_entry_function = (UINT (*) (struct UX_HCD_STRUCT *, UINT, VOID *))tmp; + + /**************************************************/ + /** Test case: descriptor length larger than total configuration descriptor length. **/ + /** Why direct: To fail normally, I'd have to replace the entry function and somehow distinguish GET_DESCRIPTOR requests + OR pass a malformed descriptor, but then the device stack would've errored out before. **/ + /**************************************************/ + + /* Replace the entry function. */ + hcd = UX_DEVICE_HCD_GET(hid -> ux_host_class_hid_device); + tmp = (ALIGN_TYPE)hcd -> ux_hcd_entry_function; + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter_descriptor_too_large_test; + + status = _ux_host_class_hid_descriptor_parse(hid); + if(status != UX_DESCRIPTOR_CORRUPTED) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + hcd -> ux_hcd_entry_function = (UINT (*) (struct UX_HCD_STRUCT *, UINT, VOID *))tmp; + + /* 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_hid_descriptor_parse_test2.c b/test/regression/usbx_ux_host_class_hid_descriptor_parse_test2.c new file mode 100644 index 00000000..0681da44 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_descriptor_parse_test2.c @@ -0,0 +1,387 @@ +/* This file tests _ux_host_class_hid_descriptor_parse(). */ + +#include "usbx_test_common_hid.h" + +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static UINT ux_hcd_sim_host_entry_filter(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; +UX_TRANSFER *transfer_request; +static UINT get_config_desc_count; + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + + switch(function) + { + case UX_HCD_GET_PORT_STATUS: + + break; + + case UX_HCD_TRANSFER_REQUEST: + + transfer_request = parameter; + + /* Is this the transfer request for GetConfigDescriptor? */ + if (transfer_request -> ux_transfer_request_requested_length == UX_CONFIGURATION_DESCRIPTOR_LENGTH && + transfer_request -> ux_transfer_request_function == UX_GET_DESCRIPTOR && + transfer_request -> ux_transfer_request_type == (UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE) && + transfer_request -> ux_transfer_request_value == UX_CONFIGURATION_DESCRIPTOR_ITEM << 8 && + transfer_request -> ux_transfer_request_index == 0) + { + + /* We're looking for the second time we get the config descriptor (_descriptor_parse is the second time). */ + get_config_desc_count++; + if (get_config_desc_count == 2) + { + transfer_request->ux_transfer_request_actual_length = 0; + } + } + + break; + + default: + + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + } + + return status; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_DESCRIPTOR_CORRUPTED) + { + + /* 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_descriptor_parse_test2_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +UX_HCD *hcd; +ALIGN_TYPE tmp; + + + /* Inform user. */ + printf("Running ux_host_class_hid_descriptor_parse Test 2................... "); + + /* 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: transfer_request -> ux_transfer_request_actual_length == UX_CONFIGURATION_DESCRIPTOR_LENGTH fails in **/ + /** if ((status == UX_SUCCESS) && (transfer_request -> ux_transfer_request_actual_length == UX_CONFIGURATION_DESCRIPTOR_LENGTH)). **/ + /**************************************************/ + + /* Swap the hcd entry function. */ + hcd = &_ux_system_host -> ux_system_host_hcd_array[0]; + tmp = (ALIGN_TYPE)hcd -> ux_hcd_entry_function; + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter; + + /**************************************************/ + /** END TEST **/ + /**************************************************/ + + /* 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, error code: %d\n", __LINE__, status); + 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); + } + + /* 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_hid_descriptor_parse_test3.c b/test/regression/usbx_ux_host_class_hid_descriptor_parse_test3.c new file mode 100644 index 00000000..aa5c94ab --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_descriptor_parse_test3.c @@ -0,0 +1,381 @@ +/* This file tests _ux_host_class_hid_descriptor_parse(). */ + +#include "usbx_test_common_hid.h" + +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static UINT ux_hcd_sim_host_entry_filter(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; +UX_TRANSFER *transfer_request; + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + + switch(function) + { + case UX_HCD_GET_PORT_STATUS: + + break; + + case UX_HCD_TRANSFER_REQUEST: + + transfer_request = parameter; + + /* Is this the second transfer request from descriptor_parse()? */ + if (transfer_request -> ux_transfer_request_requested_length == 34 && + transfer_request -> ux_transfer_request_function == UX_GET_DESCRIPTOR && + transfer_request -> ux_transfer_request_type == (UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE) && + transfer_request -> ux_transfer_request_value == UX_CONFIGURATION_DESCRIPTOR_ITEM << 8 && + transfer_request -> ux_transfer_request_index == 2) + { + + status = UX_ERROR; + } + + break; + + default: + + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + } + + return status; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_DESCRIPTOR_CORRUPTED) + { + + /* 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_descriptor_parse_test3_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +UX_HCD *hcd; +ALIGN_TYPE tmp; + + + /* Inform user. */ + printf("Running ux_host_class_hid_descriptor_parse Test 3................... "); + + /* 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: status == UX_SUCCESS fails in **/ + /** if ((status == UX_SUCCESS) && (transfer_request -> ux_transfer_request_actual_length == configuration_descriptor.wTotalLength)) **/ + /**************************************************/ + + /* Swap the hcd entry function. */ + hcd = &_ux_system_host -> ux_system_host_hcd_array[0]; + tmp = (ALIGN_TYPE)hcd -> ux_hcd_entry_function; + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter; + + /**************************************************/ + /** END TEST **/ + /**************************************************/ + + /* 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, error code: %d\n", __LINE__, status); + 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); + } + + /* 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_hid_descriptor_parse_test4.c b/test/regression/usbx_ux_host_class_hid_descriptor_parse_test4.c new file mode 100644 index 00000000..2bffc152 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_descriptor_parse_test4.c @@ -0,0 +1,387 @@ +/* This file tests _ux_host_class_hid_descriptor_parse(). */ + +#include "usbx_test_common_hid.h" + +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static UINT ux_hcd_sim_host_entry_filter(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; +UX_TRANSFER *transfer_request; +static UINT num_get_config_descs; + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + + switch(function) + { + case UX_HCD_GET_PORT_STATUS: + + break; + + case UX_HCD_TRANSFER_REQUEST: + + transfer_request = parameter; + + /* Is this a GetConfigDescriptor request for the entire descriptor? */ + if (transfer_request -> ux_transfer_request_requested_length == 34 && + transfer_request -> ux_transfer_request_function == UX_GET_DESCRIPTOR && + transfer_request -> ux_transfer_request_type == (UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE) && + transfer_request -> ux_transfer_request_value == UX_CONFIGURATION_DESCRIPTOR_ITEM << 8 && + transfer_request -> ux_transfer_request_index == 0) + { + + /* We want the second one, which happens in _descriptor_parse(). */ + num_get_config_descs++; + if (num_get_config_descs == 2) + { + transfer_request->ux_transfer_request_actual_length = 0; + } + } + + break; + + default: + + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + } + + return status; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_DESCRIPTOR_CORRUPTED) + { + + /* 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_descriptor_parse_test4_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +UX_HCD *hcd; +ALIGN_TYPE tmp; + + + /* Inform user. */ + printf("Running ux_host_class_hid_descriptor_parse Test 4................... "); + + /* 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: transfer_request -> ux_transfer_request_actual_length == configuration_descriptor.wTotalLength fails in **/ + /** if ((status == UX_SUCCESS) && (transfer_request -> ux_transfer_request_actual_length == configuration_descriptor.wTotalLength)) **/ + /**************************************************/ + + /* Swap the hcd entry function */ + hcd = &_ux_system_host -> ux_system_host_hcd_array[0]; + tmp = (ALIGN_TYPE)hcd -> ux_hcd_entry_function; + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter; + + /**************************************************/ + /** END TEST **/ + /**************************************************/ + + /* 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, error code: %d\n", __LINE__, status); + 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); + } + + /* 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_hid_descriptor_parse_test5.c b/test/regression/usbx_ux_host_class_hid_descriptor_parse_test5.c new file mode 100644 index 00000000..a62ecf15 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_descriptor_parse_test5.c @@ -0,0 +1,412 @@ +/* This file tests _ux_host_class_hid_descriptor_parse(). */ + +#include "usbx_test_common_hid.h" + +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +static UCHAR dummy_configuration_descriptor[] = { + + /* Configuration descriptor */ + 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x03, 0x00, 0x01, 0x03, 0x00, 0x00, + 0x00, + + /* HID descriptor */ + 0x09, + 0x20, /* HID descriptors have a 0x21 here. Change it to something RADically different. */ + 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_REPORT_LENGTH), + MSB(HID_REPORT_LENGTH), + + /* Endpoint descriptor (Interrupt) */ + 0x07, 0x05, 0x82, 0x03, 0x08, 0x00, 0x08 + + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static UINT ux_hcd_sim_host_entry_filter(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; +UX_TRANSFER *transfer_request; + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + + switch(function) + { + case UX_HCD_GET_PORT_STATUS: + + break; + + case UX_HCD_TRANSFER_REQUEST: + + transfer_request = parameter; + + /* Is this the second transfer request from descriptor_parse()? */ + if (transfer_request -> ux_transfer_request_requested_length == 34 && + transfer_request -> ux_transfer_request_function == UX_GET_DESCRIPTOR && + transfer_request -> ux_transfer_request_type == (UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE) && + transfer_request -> ux_transfer_request_value == UX_CONFIGURATION_DESCRIPTOR_ITEM << 8 && + transfer_request -> ux_transfer_request_index == 0) + { + + UINT dummy_framework_high_speed_length = ARRAY_COUNT(dummy_configuration_descriptor); + if(dummy_framework_high_speed_length != transfer_request -> ux_transfer_request_requested_length) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + ux_utility_memory_copy(transfer_request -> ux_transfer_request_data_pointer, dummy_configuration_descriptor, ARRAY_COUNT(dummy_configuration_descriptor)); + transfer_request -> ux_transfer_request_actual_length = transfer_request -> ux_transfer_request_requested_length; + } + + break; + + default: + + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + } + + return status; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (!(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_descriptor_parse_test5_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +UX_HCD *hcd; +ALIGN_TYPE tmp; + + + /* Inform user. */ + printf("Running ux_host_class_hid_descriptor_parse Test 5................... "); + + /* 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: while (total_configuration_length) fails **/ + /**************************************************/ + + /* Swap the hcd entry function */ + hcd = &_ux_system_host -> ux_system_host_hcd_array[0]; + tmp = (ALIGN_TYPE)hcd -> ux_hcd_entry_function; + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter; + + /**************************************************/ + /** END TEST **/ + /**************************************************/ + + /* 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, error code: %d\n", __LINE__, status); + 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); + } + + /* 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_hid_descriptor_parse_test6.c b/test/regression/usbx_ux_host_class_hid_descriptor_parse_test6.c new file mode 100644 index 00000000..889434bb --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_descriptor_parse_test6.c @@ -0,0 +1,410 @@ +/* This file tests _ux_host_class_hid_descriptor_parse(). */ + +#include "usbx_test_common_hid.h" + +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +static UCHAR dummy_configuration_descriptor[] = { + + /* Configuration descriptor */ + 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, + 0x03, /* Change the interface number to something different than what the HID instance recorded (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 + + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static UINT ux_hcd_sim_host_entry_filter(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; +UX_TRANSFER *transfer_request; + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + + switch(function) + { + case UX_HCD_GET_PORT_STATUS: + + break; + + case UX_HCD_TRANSFER_REQUEST: + + transfer_request = parameter; + + /* Is this the second transfer request from descriptor_parse()? */ + if (transfer_request -> ux_transfer_request_requested_length == 34 && + transfer_request -> ux_transfer_request_function == UX_GET_DESCRIPTOR && + transfer_request -> ux_transfer_request_type == (UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE) && + transfer_request -> ux_transfer_request_value == UX_CONFIGURATION_DESCRIPTOR_ITEM << 8 && + transfer_request -> ux_transfer_request_index == 2) + { + + UINT dummy_framework_high_speed_length = ARRAY_COUNT(dummy_configuration_descriptor); + if(dummy_framework_high_speed_length != transfer_request -> ux_transfer_request_requested_length) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + ux_utility_memory_copy(transfer_request -> ux_transfer_request_data_pointer, dummy_configuration_descriptor, ARRAY_COUNT(dummy_configuration_descriptor)); + transfer_request -> ux_transfer_request_actual_length = transfer_request -> ux_transfer_request_requested_length; + } + + break; + + default: + + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + } + + return status; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_DESCRIPTOR_CORRUPTED) + { + + /* 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_descriptor_parse_test6_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +UX_HCD *hcd; +ALIGN_TYPE tmp; + + + /* Inform user. */ + printf("Running ux_host_class_hid_descriptor_parse Test 6................... "); + + /* 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: if (current_interface == hid -> ux_host_class_hid_interface -> ux_interface_descriptor.bInterfaceNumber) fails **/ + /**************************************************/ + + /* Swap the hcd entry function */ + hcd = &_ux_system_host -> ux_system_host_hcd_array[0]; + tmp = (ALIGN_TYPE)hcd -> ux_hcd_entry_function; + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter; + + /**************************************************/ + /** END TEST **/ + /**************************************************/ + + /* 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, error code: %d\n", __LINE__, status); + 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); + } + + /* 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_hid_descriptor_parse_test7.c b/test/regression/usbx_ux_host_class_hid_descriptor_parse_test7.c new file mode 100644 index 00000000..891b042e --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_descriptor_parse_test7.c @@ -0,0 +1,387 @@ +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +static UCHAR dummy_configuration_descriptor[] = { + + /* Configuration descriptor */ + 0x09, 0x02, + 0xff, 0xff, /* Set the total length to something really big so memory_allocate fails. */ + 0x01, 0x01, 0x00, 0xc0, + 0x32, + + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static UINT ux_hcd_sim_host_entry_filter(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; +UX_TRANSFER *transfer_request; + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + + switch(function) + { + case UX_HCD_GET_PORT_STATUS: + + break; + + case UX_HCD_TRANSFER_REQUEST: + + transfer_request = parameter; + + if (transfer_request -> ux_transfer_request_requested_length == UX_CONFIGURATION_DESCRIPTOR_LENGTH && + transfer_request -> ux_transfer_request_function == UX_GET_DESCRIPTOR && + transfer_request -> ux_transfer_request_type == (UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE) && + transfer_request -> ux_transfer_request_value == UX_CONFIGURATION_DESCRIPTOR_ITEM << 8 && + transfer_request -> ux_transfer_request_index == 2) + { + + ux_utility_memory_copy(transfer_request -> ux_transfer_request_data_pointer, dummy_configuration_descriptor, ARRAY_COUNT(dummy_configuration_descriptor)); + transfer_request -> ux_transfer_request_actual_length = transfer_request -> ux_transfer_request_requested_length; + } + + break; + + default: + + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + } + + return status; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_MEMORY_INSUFFICIENT) + { + + /* 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_descriptor_parse_test7_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +UX_HCD *hcd; +ALIGN_TYPE tmp; + + + /* Inform user. */ + printf("Running ux_host_class_hid_descriptor_parse Test 7................... "); + + /* 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: descriptor = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, total_configuration_length); fails **/ + /**************************************************/ + + /* Swap the hcd entry function */ + hcd = &_ux_system_host -> ux_system_host_hcd_array[0]; + tmp = (ALIGN_TYPE)hcd -> ux_hcd_entry_function; + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter; + + /**************************************************/ + /** END TEST **/ + /**************************************************/ + + /* 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, error code: %d\n", __LINE__, status); + 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); + } + + /* 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_hid_entry_test.c b/test/regression/usbx_ux_host_class_hid_entry_test.c new file mode 100644 index 00000000..087eaeb7 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_entry_test.c @@ -0,0 +1,336 @@ +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_hid_entry_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_entry 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} +static UX_HOST_CLASS host_class; +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_COMMAND command; + + /* 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); + } + + /**************************************************/ + /** Test case: no match in switch (command -> ux_host_class_command_request). **/ + /**************************************************/ + + /* Set an unknown command request. */ + command.ux_host_class_command_request = 0xff; + + status = _ux_host_class_hid_entry(&command); + if (status != UX_FUNCTION_NOT_SUPPORTED) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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"); + + + /* Cover line 151 */ + command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_DESTROY; + command.ux_host_class_command_class_ptr = &host_class; + host_class.ux_host_class_client = UX_NULL; + _ux_host_class_hid_entry(&command); + + + + 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_hid_idle_get_test.c b/test/regression/usbx_ux_host_class_hid_idle_get_test.c new file mode 100644 index 00000000..0ccab4dd --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_idle_get_test.c @@ -0,0 +1,480 @@ +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + +#include "ux_test_hcd_sim_host.h" + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + +static UX_TEST_HCD_SIM_ACTION error_on_transfer_0[] = { +/* 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_SIM_REQ_ANSWER, 0, UX_NULL, 0, UX_ERROR, + UX_ERROR}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION zlp_on_transfer_0[] = { +/* 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_SIM_REQ_ANSWER, 0, UX_NULL, 0, UX_SUCCESS, + UX_SUCCESS}, +{ 0 } +}; + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_hid_idle_get_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_idle_get 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_KEYBOARD *keyboard; +USHORT idle_time; +UX_MEMORY_BLOCK *dummy_memory_block_first = (UX_MEMORY_BLOCK *)dummy_usbx_memory; +UX_MEMORY_BLOCK *original_regular_memory_block = (UX_MEMORY_BLOCK *)_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start; +UX_MEMORY_BLOCK *original_cache_safe_memory_block = (UX_MEMORY_BLOCK *)_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_start; + + + /* 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); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the keyboard instance */ + keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)hid_client -> ux_host_class_hid_client_local_instance; + + /**************************************************/ + /** Test case: Basic, successful test. **/ + /**************************************************/ + + status = ux_host_class_hid_idle_get(hid, &idle_time, 0); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: status = _ux_utility_semaphore_get(&hid -> ux_host_class_hid_semaphore, UX_WAIT_FOREVER); fails **/ + /**************************************************/ + + /* Make sure it fails. */ + hid -> ux_host_class_hid_semaphore.tx_semaphore_id++; + + status = _ux_host_class_hid_idle_get(hid, &idle_time, 0); + if(status != TX_SEMAPHORE_ERROR) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state. */ + hid -> ux_host_class_hid_semaphore.tx_semaphore_id--; + + /**************************************************/ + /** Test case: idle_byte = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, 1); fails **/ + /**************************************************/ + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_byte_pool = UX_NULL; + // dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + // dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + // dummy_memory_block_first -> ux_memory_block_size = 0; + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start = (UCHAR*)dummy_memory_block_first; + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_start = (UCHAR*)dummy_memory_block_first; + + status = _ux_host_class_hid_idle_get(hid, &idle_time, 0); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start = (UCHAR*)original_regular_memory_block; + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_start = (UCHAR*)original_cache_safe_memory_block; + + /**************************************************/ + /** Test case: status = _ux_utility_semaphore_get(&hid -> ux_host_class_hid_device -> ux_device_protection_semaphore, UX_WAIT_FOREVER); fails **/ + /**************************************************/ + + /* Make sure it fails. */ + hid -> ux_host_class_hid_device -> ux_device_protection_semaphore.tx_semaphore_id++; + + status = _ux_host_class_hid_idle_get(hid, &idle_time, 0); + if(status != TX_SEMAPHORE_ERROR) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state. */ + hid -> ux_host_class_hid_device -> ux_device_protection_semaphore.tx_semaphore_id--; + + /**************************************************/ + /** Test case: _ux_host_stack_class_instance_verify(_ux_system_host_class_hid_name, (VOID *) hid) fails. **/ + /**************************************************/ + + status = ux_host_class_hid_idle_get(UX_NULL, UX_NULL, 0); + if (status == UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: (status == UX_SUCCESS) fails in **/ + /** if ((status == UX_SUCCESS) && (transfer_request -> ux_transfer_request_actual_length == 1)) **/ + /**************************************************/ + + /* Swap the hcd entry function. */ + ux_test_hcd_sim_host_set_actions(error_on_transfer_0); + + status = ux_host_class_hid_idle_get(hid, &idle_time, 0); + if (status == UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /** Restore state for next test. **/ + + /* ux_host_stack_transfer_request() doesn't release the device protection semaphore when it fails, so do it manually. */ + _ux_utility_semaphore_put(&hid -> ux_host_class_hid_device -> ux_device_protection_semaphore); + + /**************************************************/ + /** Test case: (transfer_request -> ux_transfer_request_actual_length == 1) fails in **/ + /** if ((status == UX_SUCCESS) && (transfer_request -> ux_transfer_request_actual_length == 1)) **/ + /**************************************************/ + + ux_test_hcd_sim_host_set_actions(zlp_on_transfer_0); + + status = ux_host_class_hid_idle_get(hid, &idle_time, 0); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /** Restore state for next test. **/ + + + /* ux_host_stack_transfer_request() doesn't release the device protection semaphore when it fails, so do it manually. */ + _ux_utility_semaphore_put(&hid -> ux_host_class_hid_device -> ux_device_protection_semaphore); + + /* 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_hid_idle_set_test.c b/test/regression/usbx_ux_host_class_hid_idle_set_test.c new file mode 100644 index 00000000..a990b1c4 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_idle_set_test.c @@ -0,0 +1,361 @@ +/* This file tests ux_host_class_hid_idle_set() */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_hid_idle_set_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_idle_set 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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); + } + + /**************************************************/ + /** Test case: status = _ux_utility_semaphore_get(&hid -> ux_host_class_hid_semaphore, UX_WAIT_FOREVER); fails **/ + /**************************************************/ + + /* Make sure it fails. */ + hid -> ux_host_class_hid_semaphore.tx_semaphore_id++; + + status = _ux_host_class_hid_idle_set(hid, 0, 0); + if(status != TX_SEMAPHORE_ERROR) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state. */ + hid -> ux_host_class_hid_semaphore.tx_semaphore_id--; + + /**************************************************/ + /** Test case: status = _ux_utility_semaphore_get(&hid -> ux_host_class_hid_device -> ux_device_protection_semaphore, UX_WAIT_FOREVER); fails **/ + /**************************************************/ + + /* Make sure it fails. */ + hid -> ux_host_class_hid_device -> ux_device_protection_semaphore.tx_semaphore_id++; + + status = _ux_host_class_hid_idle_set(hid, 0, 0); + if(status != TX_SEMAPHORE_ERROR) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state. */ + hid -> ux_host_class_hid_device -> ux_device_protection_semaphore.tx_semaphore_id--; + + /**************************************************/ + /** Test case: _ux_host_stack_class_instance_verify() fails. **/ + /**************************************************/ + + status = _ux_host_class_hid_idle_set(UX_NULL, 0, 0); + if (status != UX_HOST_CLASS_INSTANCE_UNKNOWN) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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_hid_interrupt_endpoint_search_int_out_test.c b/test/regression/usbx_ux_host_class_hid_interrupt_endpoint_search_int_out_test.c new file mode 100644 index 00000000..3d6cde39 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_interrupt_endpoint_search_int_out_test.c @@ -0,0 +1,337 @@ +/* This file tests ux_host_class_hid_interrupt_endpoint_search for interrupt OUT endpoint. */ + + +#include "usbx_test_common_hid.h" + +#include "ux_host_class_hid_mouse.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#define HID_REPORT_LENGTH sizeof(hid_report_descriptor)/sizeof(hid_report_descriptor[0]) + + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 59 +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, 0x29, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x02, 0x00, 0x02, 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, 0x81, 0x03, 0x08, 0x00, 0x08, + + /* Endpoint descriptor (Interrupt OUT) */ + 0x07, 0x05, 0x02, 0x03, 0x01, 0x00, 0x08 + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 69 +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, 0x29, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x02, 0x00, 0x02, 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, 0x81, 0x03, 0x08, 0x00, 0x08, + + /* Endpoint descriptor (Interrupt OUT) */ + 0x07, 0x05, 0x02, 0x03, 0x01, 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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + +#if 0 + if (error_code != ) + { + + /* Something went wrong. */ + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } +#endif +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_hid_interrupt_endpoint_search_int_out_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_interrupt_endpoint_search Interrupt OUT 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Register the HID client(s). */ + status = ux_host_class_hid_client_register(_ux_system_host_class_hid_client_mouse_name, ux_host_class_hid_mouse_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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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); + } +#if defined(UX_HOST_CLASS_HID_INTERRUPT_OUT_SUPPORT) + /* Check if we have found the interrupt OUT endpoint. */ + if (hid -> ux_host_class_hid_interrupt_out_endpoint == UX_NULL) + { + + printf("Error on line %d, error code: %d\n", __LINE__, UX_ENDPOINT_HANDLE_UNKNOWN); + test_control_return(2); + } +#endif + /* 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_hid_interrupt_endpoint_search_test.c b/test/regression/usbx_ux_host_class_hid_interrupt_endpoint_search_test.c new file mode 100644 index 00000000..9d1aa00b --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_interrupt_endpoint_search_test.c @@ -0,0 +1,383 @@ +/* This file tests ux_host_class_hid_interrupt_endpoint_search() */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_hid_interrupt_endpoint_search_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_interrupt_endpoint_search 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ALIGN_TYPE tmp; +UX_MEMORY_BLOCK *dummy_memory_block_first = (UX_MEMORY_BLOCK *)dummy_usbx_memory; +UX_MEMORY_BLOCK *original_regular_memory_block = (UX_MEMORY_BLOCK *)_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start; +UX_MEMORY_BLOCK *original_cache_safe_memory_block = (UX_MEMORY_BLOCK *)_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_start; + + /* 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); + } + + /**************************************************/ + /** Test case: ux_utility_memory_allocate() fails **/ + /**************************************************/ + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_byte_pool = UX_NULL; + // dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + // dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + // dummy_memory_block_first -> ux_memory_block_size = 0; + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start = (UCHAR*)dummy_memory_block_first; + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_start = (UCHAR*)dummy_memory_block_first; + + status = _ux_host_class_hid_interrupt_endpoint_search(hid); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start = (UCHAR*)original_regular_memory_block; + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_start = (UCHAR*)original_cache_safe_memory_block; + + /**************************************************/ + /** Test case: _ux_host_stack_interface_endpoint_get() fails. **/ + /** NOTE: only reasonable way for _ux_host_stack_interface_endpoint_get() to fail is if there are no endpoints, which is unreasonable. **/ + /**************************************************/ + + /* Set the endpoint to null so we don't find it. */ + tmp = (ALIGN_TYPE)hid -> ux_host_class_hid_interface -> ux_interface_first_endpoint; + hid -> ux_host_class_hid_interface -> ux_interface_first_endpoint = UX_NULL; + + status = _ux_host_class_hid_interrupt_endpoint_search(hid); + if (status != UX_ENDPOINT_HANDLE_UNKNOWN) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + hid -> ux_host_class_hid_interface -> ux_interface_first_endpoint = (VOID *)tmp; + + /**************************************************/ + /** Test case: **/ + /** if (!(((hid -> ux_host_class_hid_interrupt_endpoint -> ux_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) == UX_ENDPOINT_IN) && **/ + /** ((hid -> ux_host_class_hid_interrupt_endpoint -> ux_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) == UX_INTERRUPT_ENDPOINT))) **/ + /** NOTE: USBX requires the first endpoint to be INTERRUPT and IN. **/ + /**************************************************/ + + /* Clear the IN bit. */ + tmp = hid -> ux_host_class_hid_interrupt_endpoint -> ux_endpoint_descriptor.bEndpointAddress; + hid -> ux_host_class_hid_interrupt_endpoint -> ux_endpoint_descriptor.bEndpointAddress &= (~UX_ENDPOINT_IN); + + status = _ux_host_class_hid_interrupt_endpoint_search(hid); + if (status != UX_ENDPOINT_HANDLE_UNKNOWN) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + hid -> ux_host_class_hid_interrupt_endpoint -> ux_endpoint_descriptor.bEndpointAddress = (ULONG)tmp; + + /* 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_hid_interrupt_endpoint_search_test2.c b/test/regression/usbx_ux_host_class_hid_interrupt_endpoint_search_test2.c new file mode 100644 index 00000000..ed7631aa --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_interrupt_endpoint_search_test2.c @@ -0,0 +1,330 @@ +/* This file tests ux_host_class_hid_interrupt_endpoint_search. */ + +/**************************************************/ +/** Test case: hid -> ux_host_class_hid_interrupt_endpoint -> ux_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) == UX_INTERRUPT_ENDPOINT fails in **/ +/** if (((hid -> ux_host_class_hid_interrupt_endpoint -> ux_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) == UX_ENDPOINT_IN) && **/ +/** ((hid -> ux_host_class_hid_interrupt_endpoint -> ux_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) == UX_INTERRUPT_ENDPOINT)) **/ +/**************************************************/ + +#include "usbx_test_common_hid.h" + +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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. Make it non-interrupt for the test (in this case, bulk). */ + 0x07, 0x05, 0x82, 0x02, 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. Make it non-interrupt for the test (in this case, bulk). */ + 0x07, 0x05, 0x82, 0x02, 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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + +#if 0 + if (error_code != ) + { + + /* Something went wrong. */ + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } +#endif +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_hid_interrupt_endpoint_search_test2_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_interrupt_endpoint_search Test 2....................... "); + + /* 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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); + } + + /* 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_hid_keyboard_activate_test.c b/test/regression/usbx_ux_host_class_hid_keyboard_activate_test.c new file mode 100644 index 00000000..5f8e192f --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_keyboard_activate_test.c @@ -0,0 +1,610 @@ +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" +#include "tx_thread.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); +UINT _ux_host_class_hid_keyboard_activate(UX_HOST_CLASS_HID_CLIENT_COMMAND *); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_hid_keyboard_activate_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_keyboard_activate 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, error code: 0x%x\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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: 0x%x\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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_CLIENT_COMMAND client_command; +UX_MEMORY_BLOCK *dummy_memory_block_first = (UX_MEMORY_BLOCK *)dummy_usbx_memory; +UX_MEMORY_BLOCK *original_memory_block = (UX_MEMORY_BLOCK *)_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start; +UX_HOST_CLASS_HID_KEYBOARD *keyboard_instance; +TX_SEMAPHORE keyboard_instance_semaphore_copy; +ALIGN_TYPE tmp; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /**************************************************/ + /** Test case: status = _ux_host_class_hid_report_id_get(hid, &report_id); fails **/ + /** NOTE: PAIN IN THE ASS **/ + /**************************************************/ + +#if 0 /* @BUG_FIX_PENDING */ + /**************************************************/ + /** Test case: status = _ux_utility_thread_create(&keyboard_instance -> ux_host_class_hid_keyboard_thread, "ux_host_stack_keyboard_thread",_ux_host_class_hid_keyboard_thread, + (ULONG)keyboard_instance, keyboard_instance -> ux_host_class_hid_keyboard_thread_stack, + UX_THREAD_STACK_SIZE, UX_THREAD_PRIORITY_KEYBOARD, + UX_THREAD_PRIORITY_KEYBOARD, UX_NO_TIME_SLICE, TX_AUTO_START); fails **/ + /**************************************************/ + + client_command.ux_host_class_hid_client_command_instance = hid; + + /* Allocate a keyboard instance like keyboard_activate(). */ + keyboard_instance = (UX_HOST_CLASS_HID_KEYBOARD *) _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_HOST_CLASS_HID_KEYBOARD)); + if (keyboard_instance == UX_NULL) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + keyboard_instance -> ux_host_class_hid_keyboard_thread_stack = keyboard_thread_stack; + + /* Create the thread like keyboard_activate(). NOTE: in order to prevent ux_host_class_hid_keyboard_thread from running infinitely and not letting us run, we change TX_AUTO_START to TX_DONT_START. */ + status = _ux_utility_thread_create(&keyboard_instance -> ux_host_class_hid_keyboard_thread, "ux_host_stack_keyboard_thread",_ux_host_class_hid_keyboard_thread, + (ULONG)keyboard_instance, keyboard_instance -> ux_host_class_hid_keyboard_thread_stack, + UX_THREAD_STACK_SIZE, UX_THREAD_PRIORITY_KEYBOARD, + UX_THREAD_PRIORITY_KEYBOARD, UX_NO_TIME_SLICE, TX_DONT_START); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Make a copy of the thread. */ + keyboard_instance_thread_copy = keyboard_instance -> ux_host_class_hid_keyboard_thread; + + /* Free the memory so keyboard_activate() uses the same memory as us, which will cause threadx to detect a thread duplicate. */ + ux_utility_memory_free(keyboard_instance); + + status = _ux_host_class_hid_keyboard_activate(&client_command); + if (status != UX_THREAD_ERROR) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* ux_utility_memory_allocate() zero'd out our keyboard instance semaphore! Good thing we made a copy! */ + keyboard_instance -> ux_host_class_hid_keyboard_thread = keyboard_instance_thread_copy; + + /* Restore state for next test. */ + status = ux_utility_thread_delete(&keyboard_instance -> ux_host_class_hid_keyboard_thread); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } +#endif + + /**************************************************/ + /** Test case: status = _ux_utility_semaphore_create(&keyboard_instance -> ux_host_class_hid_keyboard_semaphore, "ux_host_class_hid_keyboard_semaphore", 0); fails **/ + /**************************************************/ + + client_command.ux_host_class_hid_client_command_instance = hid; + + /* Allocate a keyboard instance like keyboard_activate(). */ + keyboard_instance = (UX_HOST_CLASS_HID_KEYBOARD *) _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_HOST_CLASS_HID_KEYBOARD)); + if (keyboard_instance == UX_NULL) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Create the semaphore like keyboard_activate(). */ + status = _ux_utility_semaphore_create(&keyboard_instance -> ux_host_class_hid_keyboard_semaphore, "ux_host_class_hid_keyboard_semaphore", 0); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Make a copy of the semaphore. */ + keyboard_instance_semaphore_copy = keyboard_instance -> ux_host_class_hid_keyboard_semaphore; + + /* Free the memory so keyboard_activate() uses the same memory as us, which will cause threadx to detect a semaphore duplicate. */ + ux_utility_memory_free(keyboard_instance); + + status = _ux_host_class_hid_keyboard_activate(&client_command); + if (status != UX_SEMAPHORE_ERROR) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* ux_utility_memory_allocate() zero'd out our keyboard instance semaphore! Good thing we made a copy! */ + keyboard_instance -> ux_host_class_hid_keyboard_semaphore = keyboard_instance_semaphore_copy; + + /* Restore state for next test. */ + status = ux_utility_semaphore_delete(&keyboard_instance -> ux_host_class_hid_keyboard_semaphore); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } +#if 0 /* Tested by HID basic memory tests. */ + /**************************************************/ + /** Test case: keyboard_instance = (UX_HOST_CLASS_HID_KEYBOARD *) _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, + sizeof(UX_HOST_CLASS_HID_KEYBOARD)); fails. **/ + /**************************************************/ + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + dummy_memory_block_first -> ux_memory_block_size = 0; + _ux_system -> ux_system_regular_memory_pool_start = dummy_memory_block_first; + + /* Set the command. */ + client_command.ux_host_class_hid_client_command_instance = hid; + + status = _ux_host_class_hid_keyboard_activate(&client_command); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + _ux_system -> ux_system_regular_memory_pool_start = original_memory_block; + + /**************************************************/ + /** Test case: keyboard_instance -> ux_host_class_hid_keyboard_usage_array = (ULONG *) + _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, UX_HOST_CLASS_HID_KEYBOARD_USAGE_ARRAY_LENGTH*4); fails. **/ + /**************************************************/ + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + dummy_memory_block_first -> ux_memory_block_size = 0x132; + _ux_system -> ux_system_regular_memory_pool_start = dummy_memory_block_first; + + /* Set the command. */ + client_command.ux_host_class_hid_client_command_instance = hid; + + status = _ux_host_class_hid_keyboard_activate(&client_command); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + _ux_system -> ux_system_regular_memory_pool_start = original_memory_block; +#endif + /**************************************************/ + /** Test case: _ux_host_class_hid_report_id_get() fails. **/ + /** Why direct: This is the first time _ux_host_class_hid_report_id_get() is called, and it only fails normally after being called more than once. **/ + /**************************************************/ + + /* Cause UX_HOST_CLASS_HID_REPORT_TYPE_INPUT in _ux_host_class_hid_report_id_get() to fail. */ + tmp = (ALIGN_TYPE)hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_input_report; + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_input_report = UX_NULL; + + /* Set the command. */ + client_command.ux_host_class_hid_client_command_instance = hid; + + status = _ux_host_class_hid_keyboard_activate(&client_command); + if (status != UX_HOST_CLASS_HID_REPORT_ERROR) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_input_report = (UX_HOST_CLASS_HID_REPORT *)tmp; + + /* Cause UX_HOST_CLASS_HID_REPORT_TYPE_OUTPUT in _ux_host_class_hid_report_id_get() to fail. */ + tmp = (ALIGN_TYPE)hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_output_report; + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_output_report = UX_NULL; + + /* Set the command. */ + client_command.ux_host_class_hid_client_command_instance = hid; + + status = _ux_host_class_hid_keyboard_activate(&client_command); + if (status != UX_HOST_CLASS_HID_REPORT_ERROR) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_output_report = (UX_HOST_CLASS_HID_REPORT *)tmp; + + +#if 0 /* @BUG_FIX_PENDING: Right now, this test fails due to a bug in _ux_host_class_hid_idle_set.c where the status is lost. */ + /**************************************************/ + /** Test case: _ux_host_class_hid_idle_set() fails. **/ + /**************************************************/ + + /* Set device state to an unknown state, thus causing the transfer request to fail. */ + tmp = hid -> ux_host_class_hid_interrupt_endpoint -> ux_endpoint_device -> ux_device_state; + hid -> ux_host_class_hid_interrupt_endpoint -> ux_endpoint_device -> ux_device_state = 0xdeadbeef; + + /* Set the command. */ + client_command.ux_host_class_hid_client_command_instance = hid; + + status = _ux_host_class_hid_keyboard_activate(&client_command); + if (status == UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + hid -> ux_host_class_hid_interrupt_endpoint -> ux_endpoint_device -> ux_device_state = tmp; +#endif + + /**************************************************/ + /** Test case: _ux_host_class_hid_report_callback_register() fails. **/ + /** Why direct: one reasonable way _ux_host_class_hid_report_callback_register() can fail is if it can't find the specified report; **/ + /** however, _ux_host_class_hid_keyboard_activate() calls it with a known-to-exist report. the other way is that the hid **/ + /** parser doesn't have any input reports, which would be a user error since it makes no sense to have no input reports. **/ + /**************************************************/ + + /* Make sure it can't find . */ + tmp = (ALIGN_TYPE)hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_input_report; + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_input_report = UX_NULL; + + /* Set the command. */ + client_command.ux_host_class_hid_client_command_instance = hid; + + status = _ux_host_class_hid_keyboard_activate(&client_command); + if (status == UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_input_report = (UX_HOST_CLASS_HID_REPORT *)tmp; + + /**************************************************/ + /** Test case: insufficient memory for keyboard thread stack. **/ + /**************************************************/ + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_byte_pool = UX_NULL; + // dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + // dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + // dummy_memory_block_first -> ux_memory_block_size = 0x300; + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start = (CHAR*)dummy_memory_block_first; + + /* Set the command. */ + client_command.ux_host_class_hid_client_command_instance = hid; + + status = _ux_host_class_hid_keyboard_activate(&client_command); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start = (CHAR*)original_memory_block; + + /* 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_hid_keyboard_callback_test.c b/test/regression/usbx_ux_host_class_hid_keyboard_callback_test.c new file mode 100644 index 00000000..ab0465f3 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_keyboard_callback_test.c @@ -0,0 +1,534 @@ +/* This tests focuses on code coverage of ux_host_class_hid_keyboard_callback. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_host_class_hid.h" +#include "ux_host_class_hid_keyboard.h" +#include "ux_device_class_hid.h" +#include "ux_device_stack.h" +#include "usbx_test_common_hid.h" + +/* Define constants. */ +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE 2048 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 + +/* Define local/extern function prototypes. */ +static void demo_thread_entry(ULONG); +static UINT demo_thread_hid_callback(UX_SLAVE_CLASS_HID *, UX_SLAVE_CLASS_HID_EVENT *); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); +static void tx_demo_thread_slave_simulation_entry(ULONG); + + +/* Define global data structures. */ +static ULONG error_counter; +static TX_THREAD demo_thread; +static UX_HOST_CLASS *class_driver; +static ULONG class_driver_index; +static UX_HOST_CLASS_HID *hid; +static UX_HOST_CLASS_HID_CLIENT *hid_client; +static UX_HOST_CLASS_HID_KEYBOARD *keyboard; +static UINT status; +static UINT transfer_completed; +static ULONG requested_length; +static TX_SEMAPHORE demo_semaphore; + +static ULONG keyboard_char; +static ULONG keyboard_state; +static UCHAR keyboard_queue[1024]; +static ULONG keyboard_queue_index; + +static UX_SLAVE_CLASS_HID_PARAMETER hid_parameter; + +static UCHAR hid_keyboard_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x09, 0x39, // USAGE (Caps Lock) + 0x09, 0x53, // USAGE (Num Lock) + 0x09, 0x47, // USAGE (Scroll Lock) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#define HID_KEYBOARD_REPORT_LENGTH (sizeof(hid_keyboard_report)/sizeof(hid_keyboard_report)[0]) + + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 52 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00, + 0x00, + + /* HID descriptor */ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_KEYBOARD_REPORT_LENGTH), + MSB(HID_KEYBOARD_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 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_KEYBOARD_REPORT_LENGTH), + MSB(HID_KEYBOARD_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 + }; + + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* @BUG_FIX_PENDING: ux_dcd_sim_slave_function.c doesn't support transfer aborts, which happen during device unregistration of a class. */ + if (error_code != UX_FUNCTION_NOT_SUPPORTED) + { + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_hid_keyboard_callback_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +UINT descriptor_size = HID_KEYBOARD_REPORT_LENGTH; + + /* Inform user. */ + printf("Running HID Keyboard Callback 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Initialize the hid class parameters for a keyboard. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_keyboard_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_KEYBOARD_REPORT_LENGTH; + hid_parameter.ux_device_class_hid_parameter_callback = 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UINT max_hid_loop; + + /* Initialize max loop value. */ + max_hid_loop = 2*UX_HOST_CLASS_HID_KEYBOARD_USAGE_ARRAY_LENGTH; + + /* 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); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the keyboard instance */ + keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)hid_client -> ux_host_class_hid_client_local_instance; + + /* Init the keyboard queue index. */ + keyboard_queue_index = 0; + + while (max_hid_loop--) + { + /* Get a key/state from the keyboard. */ + status = ux_host_class_hid_keyboard_key_get(keyboard, &keyboard_char, &keyboard_state); + + /* Check if there is something. */ + if (status == UX_SUCCESS) + { + /* We have a character in the queue. */ + keyboard_queue[keyboard_queue_index] = (UCHAR) keyboard_char; + + /* Can we accept more ? */ + if(keyboard_queue_index < 1024) + keyboard_queue_index++; + + } + + tx_thread_sleep(10); + } + + /* 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); +} + +static void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + +UX_SLAVE_DEVICE *device; +UX_SLAVE_INTERFACE *interface; +UX_SLAVE_CLASS_HID *hid; +UX_SLAVE_CLASS_HID_EVENT hid_event; +UCHAR key1; +UCHAR key2; + + /* Get the pointer to the device. */ + device = &_ux_system_slave -> ux_system_slave_device; + + /* Set the first key to 'a' which is 04. */ + key1 = 0x04; + + /* Set the second key to the first keypad key. */ + key2 = 0x54; + + /* reset the HID event structure. */ + ux_utility_memory_set(&hid_event, 0, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + + /* First byte is a modifier byte. */ + hid_event.ux_device_class_hid_event_buffer[0] = 0xff; + + /* Second byte is part modifier and part padding. */ + hid_event.ux_device_class_hid_event_buffer[1] = 0xff; + + while(1) + { + + /* Is the device configured ? */ + while (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED) + + /* Then wait. */ + tx_thread_sleep(10); + + /* Until the device stays configured. */ + while (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED) + { + + /* Get the interface. We use the first interface, this is a simple device. */ + interface = device -> ux_slave_device_first_interface; + + /* Form that interface, derive the HID owner. */ + hid = interface -> ux_slave_interface_class_instance; + + /* Wait for 2 seconds. */ + ux_utility_thread_sleep(20); + + /* Then insert a key into the keyboard event. Length is fixed to 8. */ + hid_event.ux_device_class_hid_event_length = 8; + + /* Toggle first and second byte. */ + hid_event.ux_device_class_hid_event_buffer[0] ^= 0xff; + hid_event.ux_device_class_hid_event_buffer[1] ^= 0xff; + + /* The 6 next bytes are keys. We only have two keys here. */ + hid_event.ux_device_class_hid_event_buffer[2] = key1; + hid_event.ux_device_class_hid_event_buffer[3] = key2; + + /* Set the keyboard event. */ + ux_device_class_hid_event_set(hid, &hid_event); + + /* Next event has the key depressed. */ + hid_event.ux_device_class_hid_event_buffer[2] = 0; + + /* Length is fixed to 8. */ + hid_event.ux_device_class_hid_event_length = 8; + + /* Set the keyboard event. */ + ux_device_class_hid_event_set(hid, &hid_event); + + /* Are we at the end of alphabet? */ + if (key1 != (0x04 + 26)) + + /* Next key. */ + key1++; + + else + + /* Start over again. */ + key1 = 0x04; + + /* Are we at the end of keypad keys? */ + if (key2 != 0x67) + + /* Next key. */ + key2++; + + else + + /* Start over again. */ + key2 = 0x54; + + } + } +} + diff --git a/test/regression/usbx_ux_host_class_hid_keyboard_callback_test2.c b/test/regression/usbx_ux_host_class_hid_keyboard_callback_test2.c new file mode 100644 index 00000000..084b10d6 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_keyboard_callback_test2.c @@ -0,0 +1,410 @@ +/**************************************************/ +/** Test case: if (callback -> ux_host_class_hid_report_callback_value < UX_HID_KEYBOARD_KEYS_UPPER_RANGE) fails **/ +/**************************************************/ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + /* Set to something over the maximum amount. */ + 0x25, UX_HID_KEYBOARD_KEYS_UPPER_RANGE, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + /* Set to something over the maximum amount. */ + 0x29, UX_HID_KEYBOARD_KEYS_UPPER_RANGE, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* @BUG_FIX_PENDING: ux_dcd_sim_slave_function.c doesn't support transfer aborts, which happen during device unregistration of a class. */ + if (error_code != UX_FUNCTION_NOT_SUPPORTED) + { + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + 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_keyboard_callback_test2_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_keyboard_callback Test 2.................. "); + + /* 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_KEYBOARD *keyboard; + + /* 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); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the keyboard instance */ + keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)hid_client -> ux_host_class_hid_client_local_instance; + + /* Wait for keyboard_callback() */ + tx_thread_sleep(50); + + /* 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 void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + +UX_SLAVE_DEVICE *device; +UX_SLAVE_INTERFACE *interface; +UX_SLAVE_CLASS_HID *hid; +UX_SLAVE_CLASS_HID_EVENT hid_event; +UCHAR key; + + /* Get the pointer to the device. */ + device = &_ux_system_slave -> ux_system_slave_device; + + /* Set the first key to 'a' which is 04. */ + key = 0x04; + + /* reset the HID event structure. */ + ux_utility_memory_set(&hid_event, 0, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + + while(1) + { + + /* Is the device configured ? */ + while (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED) + + /* Then wait. */ + tx_thread_sleep(10); + + /* Until the device stays configured. */ + while (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED) + { + + /* Get the interface. We use the first interface, this is a simple device. */ + interface = device -> ux_slave_device_first_interface; + + /* Form that interface, derive the HID owner. */ + hid = interface -> ux_slave_interface_class_instance; + + /* Wait for 2 seconds. */ + ux_utility_thread_sleep(20); + + /* Then insert a key into the keyboard event. Length is fixed to 8. */ + hid_event.ux_device_class_hid_event_length = 8; + + /* First byte is a modifier byte. */ + hid_event.ux_device_class_hid_event_buffer[0] = 0; + + /* Second byte is reserved. */ + hid_event.ux_device_class_hid_event_buffer[1] = 0; + + /* The 6 next bytes are keys. We only have one key here. */ + hid_event.ux_device_class_hid_event_buffer[2] = UX_HID_KEYBOARD_KEYS_UPPER_RANGE; + + /* Set the keyboard event. */ + ux_device_class_hid_event_set(hid, &hid_event); + } + } +} + +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_hid_keyboard_entry_test.c b/test/regression/usbx_ux_host_class_hid_keyboard_entry_test.c new file mode 100644 index 00000000..f8d57739 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_keyboard_entry_test.c @@ -0,0 +1,354 @@ +/* This file tests the ux_host_class_hid_keyboard_entry API. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + //if (error_code != ) + printf("hello"); + { + + /* 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_keyboard_entry_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_keyboard_entry 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, error code: 0x%x\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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: 0x%x\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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_CLIENT_COMMAND client_command; + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: no match in switch (command -> ux_host_class_hid_client_command_request). **/ + /**************************************************/ + + /* Set to unknown command request. */ + client_command.ux_host_class_hid_client_command_request = 0xdeadbeef; + + status = _ux_host_class_hid_keyboard_entry(&client_command); + if (status != UX_ERROR) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: ux_host_class_hid_client_command_page/ux_host_class_hid_client_command_usage error. **/ + /**************************************************/ + + /* Set to unknown command request. */ + client_command.ux_host_class_hid_client_command_request = UX_HOST_CLASS_COMMAND_QUERY; + client_command.ux_host_class_hid_client_command_page = UX_HOST_CLASS_HID_PAGE_GENERIC_DESKTOP_CONTROLS; + client_command.ux_host_class_hid_client_command_usage = UX_HOST_CLASS_HID_GENERIC_DESKTOP_KEYBOARD + 1; + + status = _ux_host_class_hid_keyboard_entry(&client_command); + if (status != UX_NO_CLASS_MATCH) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + 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_hid_keyboard_ioctl_test.c b/test/regression/usbx_ux_host_class_hid_keyboard_ioctl_test.c new file mode 100644 index 00000000..96b237f9 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_keyboard_ioctl_test.c @@ -0,0 +1,570 @@ +/* This file tests that the host correctly receives the keys the device sends to it. */ + +#include "usbx_test_common_hid.h" + +#include "ux_host_class_hid_keyboard.h" + +#define HOST_WAIT_TIME 1 +#define SLAVE_WAIT_TIME (3*HOST_WAIT_TIME) + +static UCHAR ux_host_class_hid_keyboard_regular_array[] = +{ + 0,0,0,0, + 'a','b','c','d','e','f','g','h','i','j', 'k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z', + '1','2','3','4','5','6','7','8','9','0', + 0x0d,0x1b,0x08,0x07,0x20,'-','=','[',']', + '\\','#',';',0x27,'`',',','.','/',0xf0, + 0xbb,0xbc,0xbd,0xbe,0xbf,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6, + 0x00,0xf1,0x00,0xd2,0xc7,0xc9,0xd3,0xcf,0xd1,0xcd,0xcd,0xd0,0xc8,0xf2, + '/','*','-','+', + 0x0d,'1','2','3','4','5','6','7','8','9','0','.','\\',0x00,0x00,'=', + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +static UCHAR ux_host_class_hid_keyboard_shift_array[] = +{ + 0,0,0,0, + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z', + '!','@','#','$','%','^','&','*','(',')', + 0x0d,0x1b,0x08,0x07,0x20,'_','+','{','}', + '|','~',':','"','~','<','>','?',0xf0, + 0xbb,0xbc,0xbd,0xbe,0xbf,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6, + 0x00,0xf1,0x00,0xd2,0xc7,0xc9,0xd3,0xcf,0xd1,0xcd,0xcd,0xd0,0xc8,0xf2, + '/','*','-','+', + 0x0d,'1','2','3','4','5','6','7','8','9','0','.','\\',0x00,0x00,'=', + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +static UCHAR ux_host_class_hid_keyboard_numlock_on_array[] = +{ + '/','*','-','+', + 0x0d,'1','2','3','4','5','6','7','8','9','0','.','\\',0x00,0x00,'=', +}; + +static UCHAR ux_host_class_hid_keyboard_numlock_off_array[] = +{ + '/','*','-','+', + 0x0d,0xcf,0xd0,0xd1,0xcb,'5',0xcd,0xc7,0xc8,0xc9,0xd2,0xd3,'\\',0x00,0x00,'=', +}; + +static UX_HOST_CLASS_HID_KEYBOARD_LAYOUT test_layout_swap_regular_shift = +{ + .ux_host_class_hid_keyboard_layout_regular_array = ux_host_class_hid_keyboard_shift_array, + .ux_host_class_hid_keyboard_layout_shift_array = ux_host_class_hid_keyboard_regular_array, + .ux_host_class_hid_keyboard_layout_numlock_on_array = ux_host_class_hid_keyboard_numlock_on_array, + .ux_host_class_hid_keyboard_layout_numlock_off_array = ux_host_class_hid_keyboard_numlock_off_array, + .ux_host_class_hid_keyboard_layout_keys_upper_range = UX_HID_KEYBOARD_KEYS_UPPER_RANGE, + .ux_host_class_hid_keyboard_layout_letters_lower_range = UX_HID_KEYBOARD_KEY_LETTER_A, + .ux_host_class_hid_keyboard_layout_letters_upper_range = UX_HID_KEYBOARD_KEY_LETTER_Z, + .ux_host_class_hid_keyboard_layout_keypad_lower_range = UX_HID_KEYBOARD_KEYS_KEYPAD_LOWER_RANGE, + .ux_host_class_hid_keyboard_layout_keypad_upper_range = UX_HID_KEYBOARD_KEYS_KEYPAD_UPPER_RANGE, +}; + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, ARRAY_COUNT(ux_host_class_hid_keyboard_regular_array) + 1, // LOGICAL_MAXIMUM () + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, ARRAY_COUNT(ux_host_class_hid_keyboard_regular_array) + 1, // USAGE_MAXIMUM () + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* @BUG_FIX_PENDING: ux_dcd_sim_slave_function.c doesn't support transfer aborts, which happen during device unregistration of a class. */ + if (error_code != UX_FUNCTION_NOT_SUPPORTED) + { + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: 0x%x\n", __LINE__, system_level, system_context, error_code); + 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_keyboard_ioctl_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_keyboard_ioctl 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, error code: 0x%x\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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: 0x%x\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, error code: 0x%x\n", __LINE__, status); + 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; + + /* Initialize 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running HID Keyboard Basic Functionality Test....................... ERROR #10\n"); + test_control_return(1); + } + +} + +static UINT _wait_key(UX_HOST_CLASS_HID_KEYBOARD *keyboard, ULONG *keyboard_key, ULONG *keyboard_state) +{ + +UINT status; +UINT i; + + + for(i = 0; i < 200; i ++) + { + status = ux_host_class_hid_keyboard_key_get(keyboard, keyboard_key, keyboard_state); + if (status == UX_SUCCESS) + { + +#if defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE_REPORT_LOCK_KEYS) || defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE_REPORT_MODIFIER_KEYS) + if (*keyboard_state & UX_HID_KEYBOARD_STATE_FUNCTION) + continue; +#endif + +#if !defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE_REPORT_KEY_DOWN_ONLY) + if (*keyboard_state & UX_HID_KEYBOARD_STATE_KEY_UP) + continue; +#endif + return UX_SUCCESS; + } + _ux_utility_delay_ms(2); + } + return UX_ERROR; +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_KEYBOARD *keyboard; +ULONG keyboard_key; +ULONG keyboard_state; + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the keyboard instance */ + keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)hid_client -> ux_host_class_hid_client_local_instance; + + /**************************************************************************/ + /* Case: normal layout */ + + /* Wait a regular key. */ + status = _wait_key(keyboard, &keyboard_key, &keyboard_state); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (keyboard_key != 'a') + { + printf("ERROR #%d: key 0x%x (%c)\n", __LINE__, status, (UCHAR)keyboard_key); + test_control_return(1); + } + + /**************************************************************************/ + /* Case: swap layout */ + + status = ux_host_class_hid_keyboard_ioctl(keyboard, UX_HID_KEYBOARD_IOCTL_SET_LAYOUT, (VOID *)&test_layout_swap_regular_shift); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Resume slave to send a key. */ + _ux_utility_thread_resume(&tx_demo_thread_slave_simulation); + + /* Wait a regular key. */ + status = _wait_key(keyboard, &keyboard_key, &keyboard_state); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (keyboard_key != 'A') + { + printf("ERROR #%d: key 0x%x (%c)\n", __LINE__, status, (UCHAR)keyboard_key); + test_control_return(1); + } + + /**************************************************************************/ + /* Case: normal layout */ + + status = ux_host_class_hid_keyboard_ioctl(keyboard, UX_HID_KEYBOARD_IOCTL_SET_LAYOUT, UX_NULL); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Resume slave to send a key. */ + _ux_utility_thread_resume(&tx_demo_thread_slave_simulation); + + /* Wait a regular key. */ + status = _wait_key(keyboard, &keyboard_key, &keyboard_state); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (keyboard_key != 'a') + { + printf("ERROR #%d: key 0x%x (%c)\n", __LINE__, status, (UCHAR)keyboard_key); + test_control_return(1); + } + + /**************************************************************************/ + /* Case: invalid IOCTL */ + + status = ux_host_class_hid_keyboard_ioctl(keyboard, ~0, UX_NULL); + if (status == UX_SUCCESS) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + 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); +} + +static void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + +UINT status; +UX_SLAVE_DEVICE *device; +UX_SLAVE_INTERFACE *interface; +UX_SLAVE_CLASS_HID *hid; +UX_SLAVE_CLASS_HID_EVENT hid_event; +UCHAR state_modifier[2] = {0, (0x01 << 1)}; + + /* Get the pointer to the device. */ + device = &_ux_system_slave -> ux_system_slave_device; + + /* reset the HID event structure. */ + ux_utility_memory_set(&hid_event, 0, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + + /* Is the device configured ? */ + while (device->ux_slave_device_state != UX_DEVICE_CONFIGURED) + + /* Then wait. */ + tx_thread_sleep(10); + + /* Get the interface. We use the first interface, this is a simple device. */ + interface = device->ux_slave_device_first_interface; + + /* Form that interface, derive the HID owner. */ + hid = interface->ux_slave_interface_class_instance; + + /* Wait resume to continue. */ + while(1) { + + /* Send a key! */ + hid_event.ux_device_class_hid_event_length = 8; + hid_event.ux_device_class_hid_event_buffer[0] = 0; + hid_event.ux_device_class_hid_event_buffer[1] = 0; + hid_event.ux_device_class_hid_event_buffer[2] = UX_HID_KEYBOARD_KEY_LETTER_A; + status = ux_device_class_hid_event_set(hid, &hid_event); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Release it. */ + hid_event.ux_device_class_hid_event_buffer[2] = 0; + status = ux_device_class_hid_event_set(hid, &hid_event); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + ux_utility_thread_suspend(&tx_demo_thread_slave_simulation); + } +} diff --git a/test/regression/usbx_ux_host_class_hid_keyboard_thread_test.c b/test/regression/usbx_ux_host_class_hid_keyboard_thread_test.c new file mode 100644 index 00000000..84b84dbd --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_keyboard_thread_test.c @@ -0,0 +1,399 @@ +/* This test ux_host_class_hid_keyboard_thread(). */ + +#include "usbx_test_common_hid.h" + +#include "ux_host_class_hid_keyboard.h" + +#include "tx_api.h" +#include "tx_thread.h" + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + //if (error_code != ) + printf("hello"); + { + + /* 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_keyboard_thread_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 ux_host_class_hid_keyboard_thread 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_system_host_change_function); + 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\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 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, + 19, 19, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } +} + +static UINT ux_hcd_sim_host_entry_filter_device_extraction_test(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; + + switch(function) + { + case UX_HCD_GET_PORT_STATUS: + + /* No device on this port. */ + status = 0; + + /* This is a Full speed device. */ + status |= UX_PS_DS_FS; + + break; + + + default: + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + break; + } + + return status; +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_KEYBOARD *keyboard; +UX_HCD *hcd; +ULONG old_time_slice; + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d; status code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the keyboard instance */ + keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)hid_client -> ux_host_class_hid_client_local_instance; + + hcd = UX_DEVICE_HCD_GET(hid -> ux_host_class_hid_device); + + /**************************************************/ + /** Test case: _ux_utility_semaphore_get(&keyboard_instance -> ux_host_class_hid_keyboard_semaphore, UX_WAIT_FOREVER) fails **/ + /**************************************************/ + + /* Give it a time slice; otherwise, this thread will never continue. */ + status = tx_thread_time_slice_change(&keyboard -> ux_host_class_hid_keyboard_thread, 1, &old_time_slice); + if (status != UX_SUCCESS) + { + + printf("Error on line %d; status code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Make sure keyboard_deactivate() won't terminate the thread, that way it'll be around long enough to call semaphore_get() and fail. */ + keyboard -> ux_host_class_hid_keyboard_thread.tx_thread_id = TX_THREAD_ID + 1; + + /* Change the HCD entry function to our filter function. */ + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter_device_extraction_test; + + /* Signal port activity to the enum thread. */ + hcd -> ux_hcd_root_hub_signal[0] = 1; + + /* Signal enum thread. */ + _ux_utility_semaphore_put(&_ux_system_host -> ux_system_host_enum_semaphore); + + /* Wait for hid class to shut down. */ + while(hid -> ux_host_class_hid_state == UX_HOST_CLASS_INSTANCE_LIVE) + tx_thread_sleep(10); + + /* Restore thread_id to allow thread_delete() to succeed. */ + keyboard -> ux_host_class_hid_keyboard_thread.tx_thread_id = TX_THREAD_ID; + + /* Terminate the thread. */ + _ux_utility_thread_delete(&keyboard -> ux_host_class_hid_keyboard_thread); + + /* 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_hid_keyboard_thread_test2.c b/test/regression/usbx_ux_host_class_hid_keyboard_thread_test2.c new file mode 100644 index 00000000..ff1550ad --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_keyboard_thread_test2.c @@ -0,0 +1,379 @@ +/**************************************************/ +/** Test case: _ux_host_class_hid_report_id_get(hid, &report_id) fails **/ +/** Why direct: In order to make _ux_host_class_hid_report_id_get() fail, we must either make _ux_host_stack_class_instance_verify fail, or **/ +/** _ux_utility_semaphore_get() fail. Either way, something else in USBX is going to break... **/ +/** How: we run the call in a separate thread since the ux_host_class_hid_keyboard_thread never returns. **/ +/**************************************************/ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + +#include "tx_api.h" +#include "tx_thread.h" + +static TX_THREAD test_thread; +static UX_HOST_CLASS_HID_KEYBOARD keyboard; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static void test_thread_entry(ULONG arg); + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_HOST_CLASS_INSTANCE_UNKNOWN) + { + + /* 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_keyboard_thread_test2_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 ux_host_class_hid_keyboard_thread Test 2.................... "); + + /* 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_system_host_change_function); + 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\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 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); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&test_thread, "test thread", test_thread_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, 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 test_thread_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID keyboard_hid; + + + /* Since keyboard_hid isn't located in a USBX class container, instance_veryify() will fail. */ + keyboard.ux_host_class_hid_keyboard_hid = &keyboard_hid; + + /* Create the semaphore used in _ux_host_class_hid_keyboard_thread(). */ + status = ux_utility_semaphore_create(&keyboard.ux_host_class_hid_keyboard_semaphore, "dummy", 1); + if (status != UX_SUCCESS) + { + + printf("Error on line %d; status code: %d\n", __LINE__, status); + test_control_return(1); + } + + UX_THREAD_EXTENSION_PTR_SET(tx_thread_identify(), &keyboard) + _ux_host_class_hid_keyboard_thread((ULONG)(ALIGN_TYPE)&keyboard); +} + +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; status code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Give test thread time to make call. */ + tx_thread_sleep(20); + + tx_thread_terminate(&test_thread); + + /* 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_hid_local_item_parse_test.c b/test/regression/usbx_ux_host_class_hid_local_item_parse_test.c new file mode 100644 index 00000000..f76bfaf9 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_local_item_parse_test.c @@ -0,0 +1,538 @@ +/* This test ensures that the parser generates an error upon encountering an invalid close delimiter tag. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + +#include "ux_test.h" +#include "ux_test_hcd_sim_host.h" + +#define TEST_SLAVE_REQUEST_CONTROL_MAX_LENGTH 8192 + +#define REP2_0(v0,v1) +#define REP2_1(v0,v1) v0,v1, +#define REP2_2(v0,v1) REP2_1(v0,v1) v0,v1, +#define REP2_3(v0,v1) REP2_2(v0,v1) v0,v1, +#define REP2_4(v0,v1) REP2_3(v0,v1) v0,v1, +#define REP2_5(v0,v1) REP2_4(v0,v1) v0,v1, +#define REP2_6(v0,v1) REP2_5(v0,v1) v0,v1, +#define REP2_7(v0,v1) REP2_6(v0,v1) v0,v1, +#define REP2_8(v0,v1) REP2_7(v0,v1) v0,v1, +#define REP2_9(v0,v1) REP2_8(v0,v1) v0,v1, +#define REP2_10(v0,v1) REP2_9(v0,v1) v0,v1, +#define REP2_20(v0,v1) REP2_10(v0,v1) REP2_10(v0,v1) +#define REP2_50(v0,v1) REP2_10(v0,v1) REP2_10(v0,v1) REP2_10(v0,v1) REP2_10(v0,v1) REP2_10(v0,v1) +#define REP2_100(v0,v1) REP2_50(v0,v1) REP2_50(v0,v1) +#define REP2_200(v0,v1) REP2_100(v0,v1) REP2_100(v0,v1) +#define REP2_500(v0,v1) REP2_100(v0,v1) REP2_100(v0,v1) REP2_100(v0,v1) REP2_100(v0,v1) REP2_100(v0,v1) +#define REP2_1000(v0,v1) REP2_500(v0,v1) REP2_500(v0,v1) + +#define REP4_0(v0,v1,v2,v3) +#define REP4_1(v0,v1,v2,v3) v0,v1,v2,v3, +#define REP4_2(v0,v1,v2,v3) REP4_1(v0,v1,v2,v3) v0,v1,v2,v3, +#define REP4_3(v0,v1,v2,v3) REP4_2(v0,v1,v2,v3) v0,v1,v2,v3, +#define REP4_4(v0,v1,v2,v3) REP4_3(v0,v1,v2,v3) v0,v1,v2,v3, +#define REP4_5(v0,v1,v2,v3) REP4_4(v0,v1,v2,v3) v0,v1,v2,v3, +#define REP4_6(v0,v1,v2,v3) REP4_5(v0,v1,v2,v3) v0,v1,v2,v3, +#define REP4_7(v0,v1,v2,v3) REP4_6(v0,v1,v2,v3) v0,v1,v2,v3, +#define REP4_8(v0,v1,v2,v3) REP4_7(v0,v1,v2,v3) v0,v1,v2,v3, +#define REP4_9(v0,v1,v2,v3) REP4_8(v0,v1,v2,v3) v0,v1,v2,v3, +#define REP4_10(v0,v1,v2,v3) REP4_9(v0,v1,v2,v3) v0,v1,v2,v3, +#define REP4_20(v0,v1,v2,v3) REP4_10(v0,v1,v2,v3) REP4_10(v0,v1,v2,v3) +#define REP4_50(v0,v1,v2,v3) REP4_10(v0,v1,v2,v3) REP4_10(v0,v1,v2,v3) REP4_10(v0,v1,v2,v3) REP4_10(v0,v1,v2,v3) REP4_10(v0,v1,v2,v3) +#define REP4_100(v0,v1,v2,v3) REP4_50(v0,v1,v2,v3) REP4_50(v0,v1,v2,v3) +#define REP4_200(v0,v1,v2,v3) REP4_100(v0,v1,v2,v3) REP4_100(v0,v1,v2,v3) +#define REP4_500(v0,v1,v2,v3) REP4_100(v0,v1,v2,v3) REP4_100(v0,v1,v2,v3) REP4_100(v0,v1,v2,v3) REP4_100(v0,v1,v2,v3) REP4_100(v0,v1,v2,v3) +#define REP4_1000(v0,v1,v2,v3) REP4_500(v0,v1,v2,v3) REP4_500(v0,v1,v2,v3) + +static UINT callback_error_code; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0xa9, 0x01, // DELIMITER (Open) + 0x0b, 0x20, 0x00, 0x05, 0x00, // USAGE (Gaming Controls:Point of View) + 0x0b, 0x39, 0x00, 0x01, 0x00, // USAGE (Generic Desktop:Hat switch) + 0x0b, 0x20, 0x00, 0x05, 0x00, // USAGE (Gaming Controls:Point of View) + 0xa9, 0x00, // DELIMITER (Close) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x03, // LOGICAL_MAXIMUM (3) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x46, 0x0e, 0x01, // PHYSICAL_MAXIMUM (270) + 0x65, 0x14, // UNIT (Eng Rot:Angular Pos) + 0x55, 0x00, // UNIT_EXPONENT (0) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; +#define HID_REPORT_LENGTH sizeof(hid_report_descriptor)/sizeof(hid_report_descriptor[0]) + +#if UX_HOST_CLASS_HID_USAGES == 1024 +static UCHAR hid_report_descriptor1[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0xa9, 0x01, // DELIMITER (Open) + REP4_5(0x19, 1, 0x29, 200) + REP4_1(0x19, 1, 0x29, 23) + REP2_5(0x09, 0x30) + 0x0b, 0x20, 0x00, 0x05, 0x00, // USAGE (Gaming Controls:Point of View) + 0x0b, 0x39, 0x00, 0x01, 0x00, // USAGE (Generic Desktop:Hat switch) + 0x0b, 0x20, 0x00, 0x05, 0x00, // USAGE (Gaming Controls:Point of View) + 0xa9, 0x00, // DELIMITER (Close) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x03, // LOGICAL_MAXIMUM (3) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x46, 0x0e, 0x01, // PHYSICAL_MAXIMUM (270) + 0x65, 0x14, // UNIT (Eng Rot:Angular Pos) + 0x55, 0x00, // UNIT_EXPONENT (0) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; +#define HID_REPORT_LENGTH1 sizeof(hid_report_descriptor1)/sizeof(hid_report_descriptor1[0]) + +static UCHAR hid_report_descriptor2[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0xa9, 0x01, // DELIMITER (Open) + REP4_5(0x19, 1, 0x29, 200) + REP4_1(0x19, 1, 0x29, 30) + 0x0b, 0x20, 0x00, 0x05, 0x00, // USAGE (Gaming Controls:Point of View) + 0x0b, 0x39, 0x00, 0x01, 0x00, // USAGE (Generic Desktop:Hat switch) + 0x0b, 0x20, 0x00, 0x05, 0x00, // USAGE (Gaming Controls:Point of View) + 0xa9, 0x00, // DELIMITER (Close) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x03, // LOGICAL_MAXIMUM (3) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x46, 0x0e, 0x01, // PHYSICAL_MAXIMUM (270) + 0x65, 0x14, // UNIT (Eng Rot:Angular Pos) + 0x55, 0x00, // UNIT_EXPONENT (0) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; +#define HID_REPORT_LENGTH2 sizeof(hid_report_descriptor2)/sizeof(hid_report_descriptor2[0]) +#else /* UX_HOST_CLASS_HID_USAGES == 1024 */ +static inline void hid_usage_min_max_add(UCHAR *ptr, UCHAR min, UCHAR max) +{ + ptr[0] = 0x19; + ptr[1] = min; + ptr[2] = 0x29; + ptr[3] = max; +} + +static inline void hid_usage_add(UCHAR *ptr, UCHAR usage) +{ + ptr[0] = 0x09; + ptr[1] = usage; +} + +/* usage : 200 x N + M */ +#define _DIV200(V) ((V)/200) +#define _MOD200(V) ((V)%200) +#define _P1_START (0) +#define _P1_SIZE (8) +#define _P2_START (_P1_SIZE) +#define _P2_SIZE (HID_REPORT_LENGTH - _P1_SIZE) +static UCHAR hid_report_descriptor_mem[HID_REPORT_LENGTH + _DIV200(UX_HOST_CLASS_HID_USAGES + 10) * 4 + 10 * 4]; +static UCHAR *hid_report_descriptor1 = hid_report_descriptor_mem; +static UCHAR *hid_report_descriptor2 = hid_report_descriptor_mem; +#define HID_REPORT_LENGTH1 (HID_REPORT_LENGTH+_DIV200(UX_HOST_CLASS_HID_USAGES-1)*4+1*4+5*2) +#define HID_REPORT_LENGTH2 (HID_REPORT_LENGTH+_DIV200(UX_HOST_CLASS_HID_USAGES+5)*4+2*4) +static void hid_report_descriptor_generate(ULONG length) +{ + +UINT i; +UCHAR *ptr = hid_report_descriptor_mem; +UINT nb_min_max0, nb_min_max1, nb_usage; + + + _ux_utility_memory_copy(ptr, hid_report_descriptor + _P1_START, _P1_SIZE); + ptr += _P1_SIZE; + + /* Build descriptor. */ + switch(length) + { + case HID_REPORT_LENGTH1: + nb_min_max0 = _DIV200(UX_HOST_CLASS_HID_USAGES-1); + nb_min_max1 = 1; + nb_usage = 5; + break; + + case HID_REPORT_LENGTH2: + nb_min_max0 = _DIV200(UX_HOST_CLASS_HID_USAGES+5); + nb_min_max1 = 2; + nb_usage = 0; + break; + + default: + nb_min_max0 = 0; + nb_min_max1 = 0; + nb_usage = 0; + } + for (i = 0; i < nb_min_max0; i ++) + { + hid_usage_min_max_add(ptr, 1, 200); + ptr += 4; + } + for (i = 0; i < nb_min_max1; i ++) + { + hid_usage_min_max_add(ptr, 1, _MOD200(UX_HOST_CLASS_HID_USAGES)); + ptr += 4; + } + for (i = 0; i < nb_usage; i ++) + { + hid_usage_add(ptr, 0x30); + ptr += 2; + } + + _ux_utility_memory_copy(ptr, hid_report_descriptor + _P2_START, _P2_SIZE); + #if 0 + printf("N usage max: %d\n", UX_HOST_CLASS_HID_USAGES); + printf("Len %ld or (%d, %d) - %d, %d, %d\n", length, HID_REPORT_LENGTH1, HID_REPORT_LENGTH2, nb_min_max0, nb_min_max1, nb_usage); + printf("hid_report_descriptor:"); + for (i = 0; i < HID_REPORT_LENGTH; i ++) + { + if ((i & 3) == 0) printf("\n"); + printf(" %2x", hid_report_descriptor[i]); + } + printf("\n"); + printf("hid_report_descriptor_mem:"); + for (i = 0; i < length; i ++) + { + if ((i & 3) == 0) printf("\n"); + printf(" %2x", hid_report_descriptor_mem[i]); + } + printf("\n"); + #endif +} +#endif + +#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 + }; + + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (error_code != UX_HOST_CLASS_HID_USAGE_OVERFLOW && + error_code != UX_DEVICE_ENUMERATION_FAILURE && + error_code != UX_HOST_CLASS_INSTANCE_UNKNOWN && + error_code != UX_DESCRIPTOR_CORRUPTED) + { + + /* Something went wrong. */ + printf("Error on line %d: code 0x%x\n", __LINE__, error_code); + test_control_return(1); + } +} + +static VOID set_hid_descriptor(UCHAR *descriptor, ULONG length) +{ + +UX_SLAVE_CLASS *class; +UX_SLAVE_CLASS_HID *hid_class; + + + device_framework_full_speed[DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 9] = LSB(length); + device_framework_full_speed[DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 8] = MSB(length); + device_framework_high_speed[DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 9] = LSB(length); + device_framework_high_speed[DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 8] = MSB(length); + + /* Modify class settings. */ + class = &_ux_system_slave->ux_system_slave_class_array[0]; + hid_class = (UX_SLAVE_CLASS_HID*)class->ux_slave_class_instance; + + hid_class->ux_device_class_hid_report_address = descriptor; + hid_class->ux_device_class_hid_report_length = length; + +#if UX_HOST_CLASS_HID_USAGES != 1024 + hid_report_descriptor_generate(length); +#endif +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_hid_local_item_parse_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 ux_host_class_hid_local_item_parse Test..................... "); + stepinfo("\n"); + + /* 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: 0x%x\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; + + stepinfo(">>>>>>>>>>> Test normal connect\n"); + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>> Test USAGE overflow\n"); + ux_test_hcd_sim_host_disconnect(); + set_hid_descriptor(hid_report_descriptor1, HID_REPORT_LENGTH1); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + status = demo_class_hid_get(); + if (status == UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>> Test USAGE_MAXIMUM overflow\n"); + ux_test_hcd_sim_host_disconnect(); + set_hid_descriptor(hid_report_descriptor2, HID_REPORT_LENGTH2); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + status = demo_class_hid_get(); + if (status == UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + 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); +} \ No newline at end of file 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 new file mode 100644 index 00000000..b7b6dc6c --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_logitech_pro_x_superlight_test.c @@ -0,0 +1,463 @@ +/**************************************************/ +/** Test case: The default case of switch (item -> ux_host_class_hid_item_report_tag). **/ +/**************************************************/ + +#include "usbx_test_common_hid.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xA1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xA1, 0x00, // COLLECTION (Physical) + + 0x95, 0x10, // REPORT_COUNT (16) + 0x75, 0x01, // REPORT_SIZE (1) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x10, // USAGE_MAXIMUM (Button 16) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + 0x95, 0x02, // REPORT_COUNT (2) + 0x75, 0x10, // REPORT_SIZE (16) + 0x16, 0x01, 0x80, // LOGICAL_MINIMUM (-32767) + 0x26, 0xff, 0x7f, // LOGICAL_MAXIMUM (32767) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x81, 0x06, // INPUT (Data,Var,Rel) + + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x09, 0x38, // USAGE (Wheel) + 0x81, 0x06, // INPUT (Data,Var,Rel) + + 0x95, 0x01, // REPORT_COUNT (1) + 0x05, 0x0C, // USAGE_PAGE (Consumer Devices) + 0x0a, 0x38, 0x02, // USAGE (AC Pan) + 0x81, 0x06, // INPUT (Data,Var,Rel) +#if 1 /* Additional keyboard for test */ + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) +#endif + 0xC0, // END_COLLECTION + + 0x06, 0x00, 0xFF, // USAGE_PAGE (Vendor Defined Page 1) + 0x09, 0xF1, // USAGE (Vendor Usage 1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x05, // REPORT_COUNT (5) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xFF, 0x00, // LOGICAL_MAXIMUM (255) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + + 0xc0 // END_COLLECTION +}; +#define HID_REPORT_LENGTH sizeof(hid_report_descriptor)/sizeof(hid_report_descriptor[0]) +typedef struct DEMO_HID_REPORT_STRUCT { + USHORT input_buttons; + SHORT input_x; + SHORT input_y; + CHAR input_wheel; + UCHAR input_ac_pan; + UCHAR input_vendor[5]; +} DEMO_HID_REPORT; + + +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (!(error_code == UX_DESCRIPTOR_CORRUPTED || + error_code == UX_DEVICE_ENUMERATION_FAILURE)) + { + + /* Error callback should have been invoked. */ + 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_logitech_pro_x_superlight_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_logitech_pro_x_superlight 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Register the HID client(s). */ + status = ux_host_class_hid_client_register(_ux_system_host_class_hid_client_mouse_name, ux_host_class_hid_mouse_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, error code: %d\n", __LINE__, status); + 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; + + hid_parameter.ux_slave_class_hid_instance_activate = demo_device_hid_instance_activate; + hid_parameter.ux_slave_class_hid_instance_deactivate = demo_device_hid_instance_deactivate; + + /* 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Create the main device simulation thread. */ + status = tx_thread_create(&tx_demo_thread_device_simulation, "tx demo device simulation", tx_demo_thread_device_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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + stack_pointer += UX_DEMO_STACK_SIZE; + + /* 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, error code: %d\n", __LINE__, status); + 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); + } + + /* Dump input reports. */ + UX_HOST_CLASS_HID_REPORT_GET_ID get_id; + 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; + 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) + { +ULONG calc_n_bytes = 0; +ULONG calc_n_bits = 0; +ULONG calc_n_item = 0; + printf("Input report %p, ID: %ld\n", (void*)hid_report, hid_report -> ux_host_class_hid_report_id); + printf(" report n_item %ld, n_bytes %ld, n_bits %ld\n", hid_report -> ux_host_class_hid_report_number_item, hid_report -> ux_host_class_hid_report_byte_length, hid_report -> ux_host_class_hid_report_bit_length); + hid_field = hid_report -> ux_host_class_hid_report_field; + while(hid_field) + { + calc_n_item += hid_field -> ux_host_class_hid_field_report_count; + calc_n_bits += hid_field -> ux_host_class_hid_field_report_count * hid_field -> ux_host_class_hid_field_report_size; + printf(" Field %p, report count %ld size %ld\n", + (void*)hid_field, hid_field ->ux_host_class_hid_field_report_count, hid_field->ux_host_class_hid_field_report_size); + printf(" Offset %ld, value %ld\n", hid_field -> ux_host_class_hid_field_report_offset, hid_field -> ux_host_class_hid_field_value); + printf(" Usage page %ld (%lx), min %ld, max %ld\n", + hid_field -> ux_host_class_hid_field_usage_page, hid_field -> ux_host_class_hid_field_usage_page, + hid_field -> ux_host_class_hid_field_usage_min, hid_field -> ux_host_class_hid_field_usage_max); + printf(" Usage logical min %ld, max %ld\n", + hid_field -> ux_host_class_hid_field_logical_min, hid_field -> ux_host_class_hid_field_logical_max); + printf(" Usage n %ld(%ld) @ %p\n", + hid_field -> ux_host_class_hid_field_number_usage, + hid_field -> ux_host_class_hid_field_number_usage, + hid_field -> ux_host_class_hid_field_usages); + if (hid_field -> ux_host_class_hid_field_usages) + { + printf(" Usage [%lx (%ld<<16)]+", + *hid_field -> ux_host_class_hid_field_usages & 0xFFFF0000, + *hid_field -> ux_host_class_hid_field_usages >> 16); + for (int i = 0; i < hid_field -> ux_host_class_hid_field_number_usage; i++) + { + printf(" %ld", hid_field -> ux_host_class_hid_field_usages[i] & 0xFFFF); + } + printf("\n"); + } + hid_field = hid_field -> ux_host_class_hid_field_next_field; + } + hid_report = hid_report -> ux_host_class_hid_report_next_report; + + calc_n_bytes = (calc_n_bits + 7) / 8; + printf(" Calc n_item %ld, n_bytes %ld, n_bits %ld\n", calc_n_item, calc_n_bytes, calc_n_bits); + } + + /* 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); +} + +static void tx_demo_thread_device_simulation_entry(ULONG arg) +{ +UX_SLAVE_CLASS_HID_EVENT hid_event; +DEMO_HID_REPORT *device_report = (DEMO_HID_REPORT*)hid_event.ux_device_class_hid_event_buffer; + + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); +#endif + + if (device_hid) + { + /* Wait for 2s. */ + tx_thread_sleep(2 * TX_TIMER_TICKS_PER_SECOND); + + /* Report ID set to 0. */ + hid_event.ux_device_class_hid_event_report_id = 0; + + /* Report type set to OUTPUT. */ + hid_event.ux_device_class_hid_event_report_type = UX_DEVICE_CLASS_HID_REPORT_TYPE_INPUT; + + /* Length is fixed to 1. */ + hid_event.ux_device_class_hid_event_length = sizeof(DEMO_HID_REPORT); + + /* Set the event. */ + ux_device_class_hid_event_set(device_hid, &hid_event); + } + } +} + +static void demo_device_hid_instance_activate(VOID *inst) +{ + if (device_hid == UX_NULL) + device_hid = (UX_SLAVE_CLASS_HID *)inst; +} +static void demo_device_hid_instance_deactivate(VOID *inst) +{ + if (inst == (VOID *)device_hid) + device_hid = UX_NULL; +} diff --git a/test/regression/usbx_ux_host_class_hid_main_item_parse_test.c b/test/regression/usbx_ux_host_class_hid_main_item_parse_test.c new file mode 100644 index 00000000..6310a203 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_main_item_parse_test.c @@ -0,0 +1,325 @@ +/**************************************************/ +/** Test case: The default case of switch (item -> ux_host_class_hid_item_report_tag). **/ +/**************************************************/ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + /* Set the tag to an unknown value (examples of tags are INPUT, OUTPUT, and FEATURE) */ + 0x71, 0x00, // ??? + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (!(error_code == UX_DESCRIPTOR_CORRUPTED || + error_code == UX_DEVICE_ENUMERATION_FAILURE)) + { + + /* Error callback should have been invoked. */ + 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_main_item_parse_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_main_item_parse 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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); + } + + /* 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_hid_main_item_parse_test2.c b/test/regression/usbx_ux_host_class_hid_main_item_parse_test2.c new file mode 100644 index 00000000..86bcf187 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_main_item_parse_test2.c @@ -0,0 +1,358 @@ +/**************************************************/ +/** Test case: hid_parser -> ux_host_class_hid_parser_main_usage == 0) fails in **/ +/** if ((hid_parser -> ux_host_class_hid_parser_main_page == 0) && (hid_parser -> ux_host_class_hid_parser_main_usage == 0)) **/ +/** How: Two application collections, the first one having a zero usage page, and a non-zero usage. **/ +/** Note: Since USBX doesn't support any devices with a usage page of 0, it generates an error and will call our error callback. **/ +/**************************************************/ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + /* Make sure the usage page is 0 */ + 0x05, 0x00, // USAGE_PAGE () + /* Make sure the usage is not 0 */ + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0, // END_COLLECTION + /* Second Application Collection. */ + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_HOST_CLASS_HID_UNKNOWN) + { + + /* Error callback should have been invoked. */ + 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_main_item_parse_test2_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_main_item_parse Test 2.................... "); + + /* 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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); + } + + /* 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_hid_mouse_activate_test.c b/test/regression/usbx_ux_host_class_hid_mouse_activate_test.c new file mode 100644 index 00000000..ac6ffd20 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_mouse_activate_test.c @@ -0,0 +1,458 @@ +/* This file tests the ux_host_class_hid_mouse_activate API. */ + +#include "usbx_test_common_hid.h" + +#include "ux_host_class_hid_keyboard.h" +#include "ux_host_class_hid_mouse.h" + +#include "ux_test_hcd_sim_host.h" + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + +static UX_TEST_HCD_SIM_ACTION stall_on_transfer_0[] = { +/* 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_SIM_REQ_ANSWER, 0, UX_NULL, 0, UX_TRANSFER_STALLED, + UX_TRANSFER_STALLED}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION error_on_transfer_0[] = { +/* 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_SIM_REQ_ANSWER, 0, UX_NULL, 0, UX_ERROR, + UX_ERROR}, +{ 0 } +}; + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_hid_mouse_activate_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_mouse_activate 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, error code: 0x%x\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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: 0x%x\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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID fake_hid; +UX_HOST_CLASS_HID_CLIENT fake_hid_client; +UX_HOST_CLASS_HID_CLIENT_COMMAND client_command; +ALIGN_TYPE tmp; +// UX_MEMORY_BLOCK *dummy_memory_block_first = (UX_MEMORY_BLOCK *)dummy_usbx_memory; +// UX_MEMORY_BLOCK *original_regular_memory_block = _ux_system -> ux_system_regular_memory_pool_start; +// UX_MEMORY_BLOCK *original_cache_safe_memory_block = _ux_system -> ux_system_cache_safe_memory_pool_start; + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); +#if 0 /* Tested in basic memory tests. */ + /**************************************************/ + /** Test case: Template for making ux_utility_memory_allocate() fail **/ + /**************************************************/ + + client_command.ux_host_class_hid_client_command_instance = hid; + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + dummy_memory_block_first -> ux_memory_block_size = 0; + _ux_system -> ux_system_regular_memory_pool_start = dummy_memory_block_first; + _ux_system -> ux_system_cache_safe_memory_pool_start = dummy_memory_block_first; + + status = _ux_host_class_hid_mouse_activate(&client_command); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + _ux_system -> ux_system_regular_memory_pool_start = original_regular_memory_block; + _ux_system -> ux_system_cache_safe_memory_pool_start = original_cache_safe_memory_block; +#endif + /**************************************************/ + /** Test case: _ux_host_class_hid_report_id_get() fails. **/ + /** Why direct: _ux_host_class_hid_mouse_activate() is the first one to call _ux_host_class_hid_report_id_get(), **/ + /** and it only fails normally after being called more than once (by trying to get a report when you pass **/ + /** it the last one in the list). **/ + /**************************************************/ + + /* Set up command. */ + fake_hid.ux_host_class_hid_client = &fake_hid_client; + client_command.ux_host_class_hid_client_command_instance = &fake_hid; + + /* Make sure _ux_host_stack_class_instance_verify() in _ux_host_class_hid_report_id_get() doesn't find any classes. */ + // tmp = _ux_system_host -> ux_system_host_max_class; + // _ux_system_host -> ux_system_host_max_class = 0; + tmp = _ux_system_host->ux_system_host_class_array->ux_host_class_status; + _ux_system_host->ux_system_host_class_array->ux_host_class_status = UX_UNUSED; + + status = _ux_host_class_hid_mouse_activate(&client_command); + if (status != UX_HOST_CLASS_INSTANCE_UNKNOWN) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + // _ux_system_host -> ux_system_host_max_class = (UINT)tmp; + _ux_system_host->ux_system_host_class_array->ux_host_class_status = (UINT)tmp; + + /**************************************************/ + /** Test case: _ux_host_class_hid_report_callback_register() fails. **/ + /** Why direct: _ux_host_class_hid_report_callback_register() loops through each input report until it finds the one passed to it; + /** the problem is that the one passed to it is always the first input report, so it always finds it. **/ + /**************************************************/ + + /* Set up. */ + tmp = (ALIGN_TYPE)hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_input_report; + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_input_report = UX_NULL; + client_command.ux_host_class_hid_client_command_instance = hid; + + status = _ux_host_class_hid_mouse_activate(&client_command); + if (status != UX_HOST_CLASS_HID_REPORT_ERROR) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_input_report = (UX_HOST_CLASS_HID_REPORT *)tmp; + + /**************************************************/ + /** Test case: _ux_host_class_hid_idle_set() stalled. **/ + /** activate continues, and there may be periodic report start error. **/ + /**************************************************/ + + ux_test_hcd_sim_host_set_actions(stall_on_transfer_0); + status = _ux_host_class_hid_mouse_activate(&client_command); + if (status != UX_HOST_CLASS_HID_PERIODIC_REPORT_ERROR && status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: _ux_host_class_hid_idle_set() failed. **/ + /**************************************************/ + + ux_test_hcd_sim_host_set_actions(error_on_transfer_0); + status = _ux_host_class_hid_mouse_activate(&client_command); + if (status != UX_ERROR) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + 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_hid_mouse_buttons_get_test.c b/test/regression/usbx_ux_host_class_hid_mouse_buttons_get_test.c new file mode 100644 index 00000000..aa994063 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_mouse_buttons_get_test.c @@ -0,0 +1,332 @@ +/* This file tests the ux_host_class_hid_mouse_buttons_get API. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + +#include "ux_host_class_hid_mouse.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_hid_mouse_buttons_get_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_mouse_buttons_get 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID fake_hid; +UX_HOST_CLASS_HID_MOUSE fake_mouse; +ULONG mouse_buttons; + + /* 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); + } + + /**************************************************/ + /** Test case: _ux_host_stack_class_instance_verify() fails. **/ + /**************************************************/ + + /* Make sure _ux_host_stack_class_instance_verify() doesn't our class. */ + fake_mouse.ux_host_class_hid_mouse_hid = &fake_hid; + + status = _ux_host_class_hid_mouse_buttons_get(&fake_mouse, &mouse_buttons); + if (status != UX_HOST_CLASS_INSTANCE_UNKNOWN) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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_hid_mouse_entry_test.c b/test/regression/usbx_ux_host_class_hid_mouse_entry_test.c new file mode 100644 index 00000000..317155cc --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_mouse_entry_test.c @@ -0,0 +1,339 @@ +/* This file tests the ux_host_class_hid_mouse_entry API. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + +#include "ux_host_class_hid_mouse.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + //if (error_code != ) + printf("hello"); + { + + /* 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_mouse_entry_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_mouse_entry 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_CLIENT_COMMAND client_command; + + /* 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); + } + + /**************************************************/ + /** Test case: no match in switch (command -> ux_host_class_hid_client_command_request). **/ + /**************************************************/ + + /* Set to unknown command. */ + client_command.ux_host_class_hid_client_command_request = 0xdeadbeef; + + status = _ux_host_class_hid_mouse_entry(&client_command); + if (status != UX_ERROR) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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_hid_mouse_entry_test2.c b/test/regression/usbx_ux_host_class_hid_mouse_entry_test2.c new file mode 100644 index 00000000..1e5f1a76 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_mouse_entry_test2.c @@ -0,0 +1,300 @@ +/**************************************************/ +/** Test case: command -> ux_host_class_hid_client_command_usage == UX_HOST_CLASS_HID_GENERIC_DESKTOP_MOUSE fails in +/** if ((command -> ux_host_class_hid_client_command_page == UX_HOST_CLASS_HID_PAGE_GENERIC_DESKTOP_CONTROLS) && + (command -> ux_host_class_hid_client_command_usage == UX_HOST_CLASS_HID_GENERIC_DESKTOP_MOUSE)) **/ +/** How: Register the mouse class but use a non-mouse report descriptor. */ +/**************************************************/ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_mouse.h" + + +static UX_HOST_CLASS_HID_MOUSE *mouse; +static UINT callback_error_code; + +/* We use a non-mouse report descriptor. */ +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 52 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00, + 0x00, + + /* HID descriptor */ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH), + MSB(HID_MOUSE_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 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_MOUSE_REPORT_LENGTH), + MSB(HID_MOUSE_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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_HOST_CLASS_HID_UNKNOWN) + { + + /* 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_mouse_entry_test2_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + /* Inform user. */ + printf("Running ux_host_class_hid_mouse_entry Test 2........................ "); + + /* 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_mouse_name, ux_host_class_hid_mouse_entry); + if (status != UX_SUCCESS) + { + + printf("Error on line %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 on line %d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the hid class parameters for a mouse. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_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) + { + + /* Error callback should have been invoked. */ + printf("Error on line %d\n", __LINE__); + 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_hid_mouse_entry_test3.c b/test/regression/usbx_ux_host_class_hid_mouse_entry_test3.c new file mode 100644 index 00000000..afc6ecdc --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_mouse_entry_test3.c @@ -0,0 +1,299 @@ +/**************************************************/ +/** Test case: command -> ux_host_class_hid_client_command_page == UX_HOST_CLASS_HID_PAGE_GENERIC_DESKTOP_CONTROLS fails in +/** if ((command -> ux_host_class_hid_client_command_page == UX_HOST_CLASS_HID_PAGE_GENERIC_DESKTOP_CONTROLS) && + (command -> ux_host_class_hid_client_command_usage == UX_HOST_CLASS_HID_GENERIC_DESKTOP_MOUSE)) **/ +/** How: Register the mouse class but make the USAGE_PAGE not GENERIC_DESKTOP_CONTROLS. */ +/**************************************************/ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_mouse.h" + + +static UX_HOST_CLASS_HID_MOUSE *mouse; + +/* We use a non-mouse report descriptor. */ +static UCHAR hid_mouse_report[] = { + + /* Make the usage page not GENERIC DESKTOP CONTROLS */ + 0x05, 0x02, // USAGE_PAGE () + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 52 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00, + 0x00, + + /* HID descriptor */ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH), + MSB(HID_MOUSE_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 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_MOUSE_REPORT_LENGTH), + MSB(HID_MOUSE_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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_HOST_CLASS_HID_UNKNOWN) + { + + /* 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_mouse_entry_test3_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + /* Inform user. */ + printf("Running ux_host_class_hid_mouse_entry Test 3........................ "); + + /* 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_mouse_name, ux_host_class_hid_mouse_entry); + if (status != UX_SUCCESS) + { + + printf("Error on line %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 on line %d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the hid class parameters for a mouse. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_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); + } + + /* 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_hid_mouse_positions_get_test.c b/test/regression/usbx_ux_host_class_hid_mouse_positions_get_test.c new file mode 100644 index 00000000..b8ecb9f6 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_mouse_positions_get_test.c @@ -0,0 +1,333 @@ +/* This file tests the ux_host_class_hid_mouse_positions_get API. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + +#include "ux_host_class_hid_mouse.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_hid_mouse_positions_get_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_mouse_positions_get 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID fake_hid; +UX_HOST_CLASS_HID_MOUSE fake_mouse; +SLONG mouse_x_position; +SLONG mouse_y_position; + + /* 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); + } + + /**************************************************/ + /** Test case: _ux_host_stack_class_instance_verify() fails. **/ + /**************************************************/ + + /* Make sure _ux_host_stack_class_instance_verify() doesn't our class. */ + fake_mouse.ux_host_class_hid_mouse_hid = &fake_hid; + + status = _ux_host_class_hid_mouse_position_get(&fake_mouse, &mouse_x_position, &mouse_y_position); + if (status != UX_HOST_CLASS_INSTANCE_UNKNOWN) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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_hid_mouse_wheel_get_test.c b/test/regression/usbx_ux_host_class_hid_mouse_wheel_get_test.c new file mode 100644 index 00000000..c931a3da --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_mouse_wheel_get_test.c @@ -0,0 +1,332 @@ +/* This file tests the ux_host_class_hid_mouse_wheel_get API. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + +#include "ux_host_class_hid_mouse.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_hid_mouse_wheel_get_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_mouse_wheel_get 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_MOUSE fake_mouse; +UX_HOST_CLASS_HID fake_hid; +SLONG mouse_wheel_movement; + + /* 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); + } + + /**************************************************/ + /** Test case: _ux_host_stack_class_instance_verify() fails. **/ + /**************************************************/ + + /* Make sure _ux_host_stack_class_instance_verify() doesn't our class. */ + fake_mouse.ux_host_class_hid_mouse_hid = &fake_hid; + + status = _ux_host_class_hid_mouse_wheel_get(&fake_mouse, &mouse_wheel_movement); + if (status != UX_HOST_CLASS_INSTANCE_UNKNOWN) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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_hid_periodic_report_start_test.c b/test/regression/usbx_ux_host_class_hid_periodic_report_start_test.c new file mode 100644 index 00000000..7c775bf1 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_periodic_report_start_test.c @@ -0,0 +1,363 @@ +/* This file tests ux_host_class_hid_periodic_report_start() */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_hid_periodic_report_start_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_periodic_report_start 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG tmp; + + /* 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); + } + + /**************************************************/ + /** Test case: _ux_utility_semaphore_get(&hid -> ux_host_class_hid_semaphore, UX_WAIT_FOREVER); fails **/ + /**************************************************/ + + /* Make sure it fails. */ + hid -> ux_host_class_hid_semaphore.tx_semaphore_id++; + + status = _ux_host_class_hid_periodic_report_start(hid); + if(status != TX_SEMAPHORE_ERROR) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state. */ + hid -> ux_host_class_hid_semaphore.tx_semaphore_id--; + + /**************************************************/ + /** Test case: _ux_host_stack_class_instance_verify() fails. **/ + /**************************************************/ + + status = _ux_host_class_hid_periodic_report_start(UX_NULL); + if(status != UX_HOST_CLASS_INSTANCE_UNKNOWN) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: if (hid -> ux_host_class_hid_interrupt_endpoint_status != UX_HOST_CLASS_HID_INTERRUPT_ENDPOINT_READY) **/ + /** Why direct: this will always fail if there is an interrupt endpoint. if there is none, it's a user error. **/ + /**************************************************/ + + /* Set endpoint to non-ready state. */ + tmp = hid -> ux_host_class_hid_interrupt_endpoint_status; + hid -> ux_host_class_hid_interrupt_endpoint_status = ~UX_HOST_CLASS_HID_INTERRUPT_ENDPOINT_READY; + + status = _ux_host_class_hid_periodic_report_start(hid); + if(status != UX_HOST_CLASS_HID_PERIODIC_REPORT_ERROR) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + hid -> ux_host_class_hid_interrupt_endpoint_status = tmp; + + /* 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_hid_periodic_report_start_test2.c b/test/regression/usbx_ux_host_class_hid_periodic_report_start_test2.c new file mode 100644 index 00000000..f1db8a86 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_periodic_report_start_test2.c @@ -0,0 +1,371 @@ +/* This file tests ux_host_class_hid_periodic_report_start() */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static UINT ux_hcd_sim_host_entry_filter(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; +UX_TRANSFER *transfer_request; + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + + /* Let get port status requests don't return UX_SUCCESS. */ + if (status != UX_SUCCESS && function != UX_HCD_GET_PORT_STATUS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + if (function == UX_HCD_TRANSFER_REQUEST) + { + + transfer_request = parameter; + + /* Is this the second transfer request from descriptor_parse()? */ + if (transfer_request -> ux_transfer_request_requested_length == 8 && + transfer_request -> ux_transfer_request_function == 0 && + transfer_request -> ux_transfer_request_type == 0x80 && + transfer_request -> ux_transfer_request_value == 0 && + transfer_request -> ux_transfer_request_index == 0) + { + + status = UX_ERROR; + } + } + + return status; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_TRANSFER_ERROR) + { + + printf("Error on line %d, error code: %d\n", __LINE__, error_code); + 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_periodic_report_start_test2_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +UX_HCD *hcd; +ALIGN_TYPE tmp; + + + /* Inform user. */ + printf("Running ux_host_class_hid_periodic_report_start Test 2.............. "); + + /* 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: ux_host_stack_transfer_request(transfer_request) fails. **/ + /**************************************************/ + + /* Swap the hcd entry function */ + hcd = &_ux_system_host -> ux_system_host_hcd_array[0]; + tmp = (ALIGN_TYPE)hcd -> ux_hcd_entry_function; + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter; + + /**************************************************/ + /** END TEST SETUP **/ + /**************************************************/ + + /* 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; + + + /* Wait for test case to execute in enum thread. */ + tx_thread_sleep(100); + + /* 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); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* 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_hid_periodic_report_stop_test.c b/test/regression/usbx_ux_host_class_hid_periodic_report_stop_test.c new file mode 100644 index 00000000..2b6d2ff4 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_periodic_report_stop_test.c @@ -0,0 +1,356 @@ +/* This file tests the ux_host_class_hid_periodic_report_stop API. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_hid_periodic_report_stop_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_periodic_report_stop 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG tmp; + + /* 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); + } + + /**************************************************/ + /** Test case: _ux_host_stack_class_instance_verify() fails. **/ + /**************************************************/ + + /* Make sure verify() doesn't find any classes. */ + // tmp = _ux_system_host -> ux_system_host_max_class; + // _ux_system_host -> ux_system_host_max_class = 0; + tmp = _ux_system_host->ux_system_host_class_array->ux_host_class_status; + _ux_system_host->ux_system_host_class_array->ux_host_class_status = UX_UNUSED; + + status = _ux_host_class_hid_periodic_report_stop(hid); + if (status != UX_HOST_CLASS_INSTANCE_UNKNOWN) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + // _ux_system_host -> ux_system_host_max_class = tmp; + _ux_system_host->ux_system_host_class_array->ux_host_class_status = (UINT)tmp; + + /**************************************************/ + /** Test case: if (hid -> ux_host_class_hid_interrupt_endpoint_status != UX_HOST_CLASS_HID_INTERRUPT_ENDPOINT_ACTIVE) **/ + /** Why direct: Endpoint status only changes via _ux_host_class_hid_periodic_report_start and _ux_host_class_hid_periodic_report_stop; **/ + /** changing it would require unreasonable hack. **/ + /**************************************************/ + + /* Set status to inactive. */ + tmp = hid -> ux_host_class_hid_interrupt_endpoint_status; + hid -> ux_host_class_hid_interrupt_endpoint_status = ~UX_HOST_CLASS_HID_INTERRUPT_ENDPOINT_ACTIVE; + + status = _ux_host_class_hid_periodic_report_stop(hid); + if (status != UX_HOST_CLASS_HID_PERIODIC_REPORT_ERROR) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + hid -> ux_host_class_hid_interrupt_endpoint_status = tmp; + + /* 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_hid_remote_control_activate_test.c b/test/regression/usbx_ux_host_class_hid_remote_control_activate_test.c new file mode 100644 index 00000000..5da82a3f --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_remote_control_activate_test.c @@ -0,0 +1,339 @@ +/**************************************************/ +/** Test case: _ux_host_class_hid_report_callback_register(hid, &call_back); fails AND it's status is checked **/ +/** HOW: Have no input reports in the report descriptor. **/ +/**************************************************/ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_remote_control.h" + + +static UX_HOST_CLASS_HID_REMOTE_CONTROL *remote_control; + + +/* In order for callback_register() to fail, there are no input reports. */ +static UCHAR hid_remote_control_report[] = { + + 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) + 0x09, 0x01, // USAGE (Consumer Control) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x02, // USAGE (Numeric Key Pad) + 0xa1, 0x02, // COLLECTION (Logical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x0a, // USAGE_MAXIMUM (Button 10) + 0x15, 0x01, // LOGICAL_MINIMUM (1) + 0x25, 0x0a, // LOGICAL_MAXIMUM (10) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0, // END_COLLECTION + 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) + 0x09, 0x86, // USAGE (Channel) + 0x09, 0xe0, // USAGE (Volume) + 0x15, 0xff, // LOGICAL_MINIMUM (-1) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x02, // REPORT_SIZE (2) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x46, // INPUT (Data,Var,Rel,Null) + 0xc0 // END_COLLECTION +}; +#define HID_REMOTE_CONTROL_REPORT_LENGTH (sizeof(hid_remote_control_report)/sizeof(hid_remote_control_report[0])) + + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 52 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00, + 0x00, + + /* HID descriptor */ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_REMOTE_CONTROL_REPORT_LENGTH), + MSB(HID_REMOTE_CONTROL_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 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_REMOTE_CONTROL_REPORT_LENGTH), + MSB(HID_REMOTE_CONTROL_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 + }; + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_HOST_CLASS_HID_PERIODIC_REPORT_ERROR) + { + + /* Something went wrong. */ + printf("Error on line %d, code 0x%x\n", __LINE__, error_code); + 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_remote_control_activate_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + /* Inform user. */ + printf("Running ux_host_class_hid_remote_control_activate 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_remote_control_name, ux_host_class_hid_remote_control_entry); + if (status != UX_SUCCESS) + { + + printf("Error on line %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 on line %d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the hid class parameters for a mouse. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_remote_control_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_REMOTE_CONTROL_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; +UX_HOST_CLASS_HID_CLIENT_COMMAND command; +UX_HOST_CLASS_HID_REMOTE_CONTROL *remote_control; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the remote control is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + remote_control = (UX_HOST_CLASS_HID_REMOTE_CONTROL *)hid_client -> ux_host_class_hid_client_local_instance; + + /**************************************************/ + /** Test case: status = _ux_host_class_hid_periodic_report_start(hid); fails **/ + /**************************************************/ + + /* Fails endpoint status. */ + hid -> ux_host_class_hid_interrupt_endpoint_status = 0; + + command.ux_host_class_hid_client_command_instance = hid; + status = _ux_host_class_hid_remote_control_activate(&command); + if (status != UX_HOST_CLASS_HID_PERIODIC_REPORT_ERROR) + { + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Restore. */ + hid -> ux_host_class_hid_interrupt_endpoint_status = UX_HOST_CLASS_HID_INTERRUPT_ENDPOINT_READY; + + /* 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); +} \ No newline at end of file diff --git a/test/regression/usbx_ux_host_class_hid_remote_control_activate_test2.c b/test/regression/usbx_ux_host_class_hid_remote_control_activate_test2.c new file mode 100644 index 00000000..1aea4a9b --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_remote_control_activate_test2.c @@ -0,0 +1,377 @@ +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_remote_control.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) + 0x09, 0x01, // USAGE (Consumer Control) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x02, // USAGE (Numeric Key Pad) + 0xa1, 0x02, // COLLECTION (Logical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x0a, // USAGE_MAXIMUM (Button 10) + 0x15, 0x01, // LOGICAL_MINIMUM (1) + 0x25, 0x0a, // LOGICAL_MAXIMUM (10) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0, // END_COLLECTION + 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) + 0x09, 0x86, // USAGE (Channel) + 0x09, 0xe0, // USAGE (Volume) + 0x15, 0xff, // LOGICAL_MINIMUM (-1) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x02, // REPORT_SIZE (2) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x46, // INPUT (Data,Var,Rel,Null) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_MEMORY_INSUFFICIENT) + { + + /* 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_remote_control_activate_test2_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_remote_control_activate Test 2............ "); + + /* 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Register the HID client(s). */ + status = ux_host_class_hid_client_register(_ux_system_host_class_hid_client_remote_control_name, ux_host_class_hid_remote_control_entry); + if (status != UX_SUCCESS) + { + + printf("Error on line %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 on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_REMOTE_CONTROL *remote_control; +UX_MEMORY_BLOCK *dummy_memory_block_first = (UX_MEMORY_BLOCK *)dummy_usbx_memory; +UX_MEMORY_BLOCK *original_memory_block = (UX_MEMORY_BLOCK *)_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start; +UX_HOST_CLASS_HID_CLIENT_COMMAND command; + + + /* 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); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the remote control is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the keyboard instance */ + remote_control = (UX_HOST_CLASS_HID_REMOTE_CONTROL *)hid_client -> ux_host_class_hid_client_local_instance; + + /**************************************************/ + /** Test case: remote_control_instance -> ux_host_class_hid_remote_control_usage_array = (ULONG *) + _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, + UX_HOST_CLASS_HID_REMOTE_CONTROL_USAGE_ARRAY_LENGTH*4); fails **/ + /**************************************************/ + + command.ux_host_class_hid_client_command_instance = hid; + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_byte_pool = UX_NULL; + // dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + // dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + // dummy_memory_block_first -> ux_memory_block_size = calculate_final_memory_request_size(1, sizeof(UX_HOST_CLASS_HID_REMOTE_CONTROL)); + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start = (UCHAR*)dummy_memory_block_first; + + status = _ux_host_class_hid_remote_control_activate(&command); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start = (UCHAR*)original_memory_block; + + /**************************************************/ + /** Test case: remote_control_instance = (UX_HOST_CLASS_HID_REMOTE_CONTROL *) _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, + sizeof(UX_HOST_CLASS_HID_REMOTE_CONTROL)); fails **/ + /**************************************************/ + + command.ux_host_class_hid_client_command_instance = hid; + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_byte_pool = UX_NULL; + // dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + // dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + // dummy_memory_block_first -> ux_memory_block_size = 0; + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start = (UCHAR*)dummy_memory_block_first; + + status = _ux_host_class_hid_remote_control_activate(&command); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start = (UCHAR*)original_memory_block; + + /* 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_hid_remote_control_callback_test.c b/test/regression/usbx_ux_host_class_hid_remote_control_callback_test.c new file mode 100644 index 00000000..2e09e40b --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_remote_control_callback_test.c @@ -0,0 +1,415 @@ +/* This tests _ux_host_class_hid_remote_control_callback. */ + +/**************************************************/ +/** Test case: if (array_head != array_tail) fails **/ +/**************************************************/ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + +#include "ux_host_class_hid_remote_control.h" + + +static UX_HOST_CLASS_HID_REMOTE_CONTROL *remote_control; + + +static UCHAR hid_remote_control_report[] = { + + 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) + 0x09, 0x01, // USAGE (Consumer Control) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x02, // USAGE (Numeric Key Pad) + 0xa1, 0x02, // COLLECTION (Logical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x0a, // USAGE_MAXIMUM (Button 10) + 0x15, 0x01, // LOGICAL_MINIMUM (1) + 0x25, 0x0a, // LOGICAL_MAXIMUM (10) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0, // END_COLLECTION + 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) + 0x09, 0x86, // USAGE (Channel) + 0x09, 0xe0, // USAGE (Volume) + 0x15, 0xff, // LOGICAL_MINIMUM (-1) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x02, // REPORT_SIZE (2) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x46, // INPUT (Data,Var,Rel,Null) + 0xc0 // END_COLLECTION +}; +#define HID_REMOTE_CONTROL_REPORT_LENGTH (sizeof(hid_remote_control_report)/sizeof(hid_remote_control_report[0])) + + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 52 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00, + 0x00, + + /* HID descriptor */ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_REMOTE_CONTROL_REPORT_LENGTH), + MSB(HID_REMOTE_CONTROL_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 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_REMOTE_CONTROL_REPORT_LENGTH), + MSB(HID_REMOTE_CONTROL_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 + }; + + +static UINT ux_system_host_change_function(ULONG event, UX_HOST_CLASS *class, VOID *instance) +{ + return 0; +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* @BUG_FIX_PENDING: ux_dcd_sim_slave_function.c doesn't support transfer aborts, which happen during device unregistration of a class. */ + if (error_code != UX_FUNCTION_NOT_SUPPORTED) + { + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + 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_remote_control_callback_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_remote_control_callback 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_system_host_change_function); + 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_remote_control_name, ux_host_class_hid_remote_control_entry); + if (status != UX_SUCCESS) + { + + printf("Error on line %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 on line %d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the hid class parameters for a mouse. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_remote_control_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_REMOTE_CONTROL_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); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, 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; +UINT max_num_loops; + + /* Initilize max loop value. */ + max_num_loops = 16; + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the remote control is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the remote control instance */ + remote_control = (UX_HOST_CLASS_HID_REMOTE_CONTROL *)hid_client -> ux_host_class_hid_client_local_instance; + + /* Wait for device to send events, and 'remote_control_instance -> ux_host_class_hid_remote_control_usage_array' to overflow */ + tx_thread_sleep(200); + + /* 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); +} + +static void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + +UINT status; +UX_SLAVE_DEVICE *device; +UX_SLAVE_INTERFACE *interface; +UX_SLAVE_CLASS_HID *hid; +UX_SLAVE_CLASS_HID_EVENT hid_event; +UINT i; + + /* Get the pointer to the device. */ + device = &_ux_system_slave -> ux_system_slave_device; + + /* reset the HID event structure. */ + ux_utility_memory_set(&hid_event, 0, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + + /* Set length of event. */ + hid_event.ux_device_class_hid_event_length = 1; + + /* Set initial keypad value. */ + hid_event.ux_device_class_hid_event_buffer[0] = 0x01; + + /* Set initial channel value. */ + hid_event.ux_device_class_hid_event_buffer[0] |= (0x03 << 4); + + /* Set initial volume value. */ + hid_event.ux_device_class_hid_event_buffer[0] |= (0x01 << 6); + + while (1) + { + + /* Is the device configured ? */ + while (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED) + + /* Then wait. */ + tx_thread_sleep(10); + + /* Until the device stays configured. */ + while (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED) + { + + for (i = 0; i < UX_HOST_CLASS_HID_REMOTE_CONTROL_USAGE_ARRAY_LENGTH + 1; i++) + { + + /* Get the interface. We use the first interface, this is a simple device. */ + interface = device->ux_slave_device_first_interface; + + /* From that interface, derive the HID owner. */ + hid = interface -> ux_slave_interface_class_instance; + + while (1) + { + + status = ux_device_class_hid_event_set(hid, &hid_event); + if (status == UX_SUCCESS) + break; + + /* Wait for events to be sent to host. */ + tx_thread_sleep(10); + } + } + } + } +} + diff --git a/test/regression/usbx_ux_host_class_hid_remote_control_entry_test.c b/test/regression/usbx_ux_host_class_hid_remote_control_entry_test.c new file mode 100644 index 00000000..5b12e8ee --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_remote_control_entry_test.c @@ -0,0 +1,339 @@ +/* This file tests the ux_host_class_hid_remote_control_entry API. */ + +#include "usbx_test_common_hid.h" + +#include "ux_host_class_hid_keyboard.h" +#include "ux_host_class_hid_remote_control.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + //if (error_code != ) + printf("hello"); + { + + /* 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_remote_control_entry_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_remote_control_entry 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_CLIENT_COMMAND client_command; + + /* 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); + } + + /**************************************************/ + /** Test case: no match in switch (command -> ux_host_class_hid_client_command_request). **/ + /**************************************************/ + + /* Set to unknown command. */ + client_command.ux_host_class_hid_client_command_request = 0xdeadbeef; + + status = _ux_host_class_hid_remote_control_entry(&client_command); + if (status != UX_ERROR) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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_hid_remote_control_entry_test2.c b/test/regression/usbx_ux_host_class_hid_remote_control_entry_test2.c new file mode 100644 index 00000000..3a3a4459 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_remote_control_entry_test2.c @@ -0,0 +1,304 @@ +/**************************************************/ +/** Test case: command -> ux_host_class_hid_client_command_page == UX_HOST_CLASS_HID_PAGE_CONSUMER fails in +/** if ((command -> ux_host_class_hid_client_command_page == UX_HOST_CLASS_HID_PAGE_CONSUMER) && + (command -> ux_host_class_hid_client_command_usage == UX_HOST_CLASS_HID_CONSUMER_REMOTE_CONTROL)) **/ +/**************************************************/ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_remote_control.h" + + +static UX_HOST_CLASS_HID_REMOTE_CONTROL *remote_control; + + +/* We use a non-remote control report descriptor. */ +static UCHAR hid_remote_control_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; +#define HID_REMOTE_CONTROL_REPORT_LENGTH (sizeof(hid_remote_control_report)/sizeof(hid_remote_control_report[0])) + + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 52 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00, + 0x00, + + /* HID descriptor */ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_REMOTE_CONTROL_REPORT_LENGTH), + MSB(HID_REMOTE_CONTROL_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 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_REMOTE_CONTROL_REPORT_LENGTH), + MSB(HID_REMOTE_CONTROL_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 + }; + + +static UINT ux_system_host_change_function(ULONG event, UX_HOST_CLASS *class, VOID *instance) +{ + return 0; +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_HOST_CLASS_HID_UNKNOWN) + { + + /* 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_remote_control_entry_test2_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + /* Inform user. */ + printf("Running ux_host_class_hid_remote_control_entry Test 2............... "); + + /* 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_system_host_change_function); + 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_remote_control_name, ux_host_class_hid_remote_control_entry); + if (status != UX_SUCCESS) + { + + printf("Error on line %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 on line %d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the hid class parameters for a mouse. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_remote_control_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_REMOTE_CONTROL_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); + } + + /* 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 *a, UX_SLAVE_CLASS_HID_EVENT *b) +{ + return 0; +} \ No newline at end of file diff --git a/test/regression/usbx_ux_host_class_hid_remote_control_entry_test3.c b/test/regression/usbx_ux_host_class_hid_remote_control_entry_test3.c new file mode 100644 index 00000000..9c4bca8a --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_remote_control_entry_test3.c @@ -0,0 +1,316 @@ +/**************************************************/ +/** Test case: command -> ux_host_class_hid_client_command_usage == UX_HOST_CLASS_HID_CONSUMER_REMOTE_CONTROL fails in +/** if ((command -> ux_host_class_hid_client_command_page == UX_HOST_CLASS_HID_PAGE_CONSUMER) && + (command -> ux_host_class_hid_client_command_usage == UX_HOST_CLASS_HID_CONSUMER_REMOTE_CONTROL)) **/ +/** How: Set the usage to something other than UX_HOST_CLASS_HID_CONSUMER_REMOTE_CONTROL **/ +/**************************************************/ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_remote_control.h" + + +static UX_HOST_CLASS_HID_REMOTE_CONTROL *remote_control; + + +/* We use a non-remote control report descriptor. */ +static UCHAR hid_remote_control_report[] = { + + 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) + 0x09, 0x00, // USAGE () + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x02, // USAGE (Numeric Key Pad) + 0xa1, 0x02, // COLLECTION (Logical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x0a, // USAGE_MAXIMUM (Button 10) + 0x15, 0x01, // LOGICAL_MINIMUM (1) + 0x25, 0x0a, // LOGICAL_MAXIMUM (10) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0, // END_COLLECTION + 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) + 0x09, 0x86, // USAGE (Channel) + 0x09, 0xe0, // USAGE (Volume) + 0x15, 0xff, // LOGICAL_MINIMUM (-1) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x02, // REPORT_SIZE (2) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x46, // INPUT (Data,Var,Rel,Null) + 0xc0 // END_COLLECTION +}; +#define HID_REMOTE_CONTROL_REPORT_LENGTH (sizeof(hid_remote_control_report)/sizeof(hid_remote_control_report[0])) + + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 52 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00, + 0x00, + + /* HID descriptor */ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_REMOTE_CONTROL_REPORT_LENGTH), + MSB(HID_REMOTE_CONTROL_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 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_REMOTE_CONTROL_REPORT_LENGTH), + MSB(HID_REMOTE_CONTROL_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 + }; + + +static UINT ux_system_host_change_function(ULONG event, UX_HOST_CLASS *class, VOID *instance) +{ + return 0; +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_HOST_CLASS_HID_UNKNOWN) + { + + /* 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_remote_control_entry_test3_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + /* Inform user. */ + printf("Running ux_host_class_hid_remote_control_entry Test 3............... "); + + /* 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_system_host_change_function); + 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_remote_control_name, ux_host_class_hid_remote_control_entry); + if (status != UX_SUCCESS) + { + + printf("Error on line %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 on line %d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the hid class parameters for a mouse. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_remote_control_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_REMOTE_CONTROL_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); + } + + /* 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 *a, UX_SLAVE_CLASS_HID_EVENT *b) +{ + return 0; +} \ No newline at end of file diff --git a/test/regression/usbx_ux_host_class_hid_remote_control_usage_get_test.c b/test/regression/usbx_ux_host_class_hid_remote_control_usage_get_test.c new file mode 100644 index 00000000..910f3888 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_remote_control_usage_get_test.c @@ -0,0 +1,333 @@ +/* This file tests the ux_host_class_hid_remote_control_usage_get API. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + +#include "ux_host_class_hid_remote_control.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_hid_remote_control_usage_get_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_remote_control_usage_get_test 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID fake_hid; +UX_HOST_CLASS_HID_REMOTE_CONTROL fake_remote_control; +ULONG usage; +ULONG value; + + /* 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); + } + + /**************************************************/ + /** Test case: _ux_host_stack_class_instance_verify() fails. **/ + /**************************************************/ + + /* Make sure _ux_host_stack_class_instance_verify() doesn't our class. */ + fake_remote_control.ux_host_class_hid_remote_control_hid = &fake_hid; + + status = _ux_host_class_hid_remote_control_usage_get(&fake_remote_control, &usage, &value); + if (status != UX_HOST_CLASS_INSTANCE_UNKNOWN) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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_hid_report_add_test.c b/test/regression/usbx_ux_host_class_hid_report_add_test.c new file mode 100644 index 00000000..f5b626c1 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_report_add_test.c @@ -0,0 +1,549 @@ +/* This file tests ux_host_class_hid_report_add() */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0, // END_COLLECTION + + 0xa1, 0x01, // COLLECTION (Application) + 0x95, 0x00, // REPORT_COUNT (0) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION + +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* 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_add_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_report_add 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_ITEM hid_item; +UINT report_id = 0xabcdef; +UX_MEMORY_BLOCK *dummy_memory_block_first = (UX_MEMORY_BLOCK *)dummy_usbx_memory; +UX_MEMORY_BLOCK *original_regular_memory_block = (UX_MEMORY_BLOCK*)_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start; +UX_MEMORY_BLOCK *original_cache_safe_memory_block = (UX_MEMORY_BLOCK*)_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_start; +UX_HOST_CLASS_HID_ITEM item; +ALIGN_TYPE tmp; +ALIGN_TYPE tmp2; +ALIGN_TYPE tmp3; +UX_HOST_CLASS_HID_PARSER *hid_parser; + + + /* 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); + } + + hid_parser = &hid -> ux_host_class_hid_parser; + + /**************************************************/ + /** Test case: new_hid_field -> ux_host_class_hid_field_usages = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, hid_field_count*4); fails **/ + /**************************************************/ + + tmp2 = hid_parser->ux_host_class_hid_parser_global.ux_host_class_hid_global_item_report_count; + hid_parser->ux_host_class_hid_parser_global.ux_host_class_hid_global_item_report_count = 1; + + tmp3 = hid_parser->ux_host_class_hid_parser_local.ux_host_class_hid_local_item_number_usage; + hid_parser->ux_host_class_hid_parser_local.ux_host_class_hid_local_item_number_usage = 1; + + /* Ensure report_add() doesn't free the allocated memory for the new hid report. */ + tmp = (ALIGN_TYPE)hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_input_report; + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_input_report = UX_NULL; + + item.ux_host_class_hid_item_report_tag = UX_HOST_CLASS_HID_MAIN_TAG_INPUT; + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_byte_pool = UX_NULL; + // dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + // dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + // dummy_memory_block_first -> ux_memory_block_size = calculate_final_memory_request_size(3, + // sizeof(UX_HOST_CLASS_HID_REPORT), sizeof(UX_HOST_CLASS_HID_FIELD), hid_parser -> ux_host_class_hid_parser_global.ux_host_class_hid_global_item_report_count*4); + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start = (UCHAR *)dummy_memory_block_first; + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_start = (UCHAR *)dummy_memory_block_first; + + /* The array is only allocated if the item is variable. */ + UCHAR descriptor = UX_HOST_CLASS_HID_ITEM_VARIABLE; + item.ux_host_class_hid_item_report_length = 1; + + status = _ux_host_class_hid_report_add(hid, &descriptor, &item); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start = (UCHAR *)original_regular_memory_block; + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_start = (UCHAR *)original_cache_safe_memory_block; + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_input_report = (UX_HOST_CLASS_HID_REPORT *)tmp; + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_global.ux_host_class_hid_global_item_report_count = (ULONG)tmp2; + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_local.ux_host_class_hid_local_item_number_usage = (ULONG)tmp3; + + /**************************************************/ + /** Test case: new_hid_field -> ux_host_class_hid_field_values = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, + new_hid_field -> ux_host_class_hid_field_report_count*4); fails **/ + /**************************************************/ + + tmp2 = hid_parser->ux_host_class_hid_parser_global.ux_host_class_hid_global_item_report_count; + hid_parser->ux_host_class_hid_parser_global.ux_host_class_hid_global_item_report_count = 1; + + tmp3 = hid_parser->ux_host_class_hid_parser_local.ux_host_class_hid_local_item_number_usage; + hid_parser->ux_host_class_hid_parser_local.ux_host_class_hid_local_item_number_usage = 1; + + /* Ensure report_add() doesn't free the allocated memory for the new hid report. */ + tmp = (ALIGN_TYPE)hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_input_report; + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_input_report = UX_NULL; + + item.ux_host_class_hid_item_report_tag = UX_HOST_CLASS_HID_MAIN_TAG_INPUT; + item.ux_host_class_hid_item_report_length = 1; + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_byte_pool = UX_NULL; + // dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + // dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + // dummy_memory_block_first -> ux_memory_block_size = calculate_final_memory_request_size(2, sizeof(UX_HOST_CLASS_HID_REPORT), sizeof(UX_HOST_CLASS_HID_FIELD)); + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start = (UCHAR *)dummy_memory_block_first; + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_start = (UCHAR *)dummy_memory_block_first; + + status = _ux_host_class_hid_report_add(hid, "doesn't matter what this is", &item); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start = (UCHAR *)original_regular_memory_block; + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_start = (UCHAR *)original_cache_safe_memory_block; + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_input_report = (UX_HOST_CLASS_HID_REPORT *)tmp; + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_global.ux_host_class_hid_global_item_report_count = (ULONG)tmp2; + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_local.ux_host_class_hid_local_item_number_usage = (ULONG)tmp3; + + /**************************************************/ + /** Test case: switch (item -> ux_host_class_hid_item_report_tag) default case. **/ + /** Why direct: _ux_host_class_hid_report_add() only gets called with INPUT, OUTPUT, or FEATURE tags. **/ + /**************************************************/ + + /* Set to value to trigger default case. */ + hid_item.ux_host_class_hid_item_report_tag = 0x00; + + status = _ux_host_class_hid_report_add(hid, "dummy", &hid_item); + if (status != UX_HOST_CLASS_HID_REPORT_ERROR) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + +#if 0 + /**************************************************/ + /** Test case: insufficient memory to allocate a new report (ux_utility_memory_allocate fails). **/ + /**************************************************/ + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + dummy_memory_block_first -> ux_memory_block_size = 0; + _ux_system -> ux_system_regular_memory_pool_start = dummy_memory_block_first; + + status = _ux_host_class_hid_report_add(hid, "dummy", &hid_item); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + _ux_system -> ux_system_regular_memory_pool_start = original_regular_memory_block; + + /**************************************************/ + /** Test case: insufficient memory to allocate a new field. **/ + /**************************************************/ + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + dummy_memory_block_first -> ux_memory_block_size = 0x50 + 0x01; // These values are taken from trial and error. + _ux_system -> ux_system_regular_memory_pool_start = dummy_memory_block_first; + + /* Set the necessary values to ensure we hit the case. */ + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_global.ux_host_class_hid_global_item_report_id = report_id++; // Don't free the newly allocated report. + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_global.ux_host_class_hid_global_item_report_count = 1; // Make sure we allocate a field. + hid_item.ux_host_class_hid_item_report_tag = UX_HOST_CLASS_HID_MAIN_TAG_INPUT; // Make sure we pass a valid tag. + hid_item.ux_host_class_hid_item_report_length = 1; // Make sure we read in the INPUT's data. + buffer[0] = 0x02; // Set the input's data (Data,Var,Abs) + + status = _ux_host_class_hid_report_add(hid, buffer, &hid_item); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + _ux_system -> ux_system_regular_memory_pool_start = original_regular_memory_block; + + /**************************************************/ + /** Test case: insufficient memory to allocate a new values for field. **/ + /**************************************************/ + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + dummy_memory_block_first -> ux_memory_block_size = 0x50 + 0x80 + 0x01; + _ux_system -> ux_system_regular_memory_pool_start = dummy_memory_block_first; + + /* Set the necessary values to ensure we hit the case. */ + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_global.ux_host_class_hid_global_item_report_id = report_id++; + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_global.ux_host_class_hid_global_item_report_count = 1; + hid_item.ux_host_class_hid_item_report_tag = UX_HOST_CLASS_HID_MAIN_TAG_INPUT; + hid_item.ux_host_class_hid_item_report_length = 1; + buffer[0] = 0x02; + + status = _ux_host_class_hid_report_add(hid, buffer, &hid_item); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + _ux_system -> ux_system_regular_memory_pool_start = original_regular_memory_block; + + /**************************************************/ + /** Test case: insufficient memory to allocate a new usages for the field. **/ + /**************************************************/ + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + dummy_memory_block_first -> ux_memory_block_size = 0x50 + 0x80 + 0x20 + 0x01; + _ux_system -> ux_system_regular_memory_pool_start = dummy_memory_block_first; + + /* Set the necessary values to ensure we hit the case. */ + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_global.ux_host_class_hid_global_item_report_id = report_id++; + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_global.ux_host_class_hid_global_item_report_count = 1; + hid_item.ux_host_class_hid_item_report_tag = UX_HOST_CLASS_HID_MAIN_TAG_INPUT; + hid_item.ux_host_class_hid_item_report_length = 1; + buffer[0] = 0x02; + + status = _ux_host_class_hid_report_add(hid, buffer, &hid_item); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + _ux_system -> ux_system_regular_memory_pool_start = original_regular_memory_block; +#endif + + /* 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_hid_report_callback_register_test.c b/test/regression/usbx_ux_host_class_hid_report_callback_register_test.c new file mode 100644 index 00000000..05704fcf --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_report_callback_register_test.c @@ -0,0 +1,370 @@ +/* This file tests ux_host_class_hid_report_callback_register(). */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* 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_callback_register_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_report_callback_register 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, error code: 0x%x\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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: 0x%x\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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_REPORT_CALLBACK hid_report_callback; +ULONG tmp; + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: _ux_host_stack_class_instance_verify() fails. **/ + /**************************************************/ + + /* Make sure verify() doesn't find any classes. */ + // tmp = _ux_system_host -> ux_system_host_max_class; + // _ux_system_host -> ux_system_host_max_class = 0; + tmp = _ux_system_host->ux_system_host_class_array->ux_host_class_status; + _ux_system_host->ux_system_host_class_array->ux_host_class_status = UX_UNUSED; + + status = _ux_host_class_hid_report_callback_register(hid, UX_NULL); + if (status != UX_HOST_CLASS_INSTANCE_UNKNOWN) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + // _ux_system_host -> ux_system_host_max_class = tmp; + _ux_system_host->ux_system_host_class_array->ux_host_class_status = (UINT)tmp; + + /**************************************************/ + /** Test case: _ux_utility_semaphore_get() fails. **/ + /**************************************************/ + + /* Change semaphore ID to generate error. */ + hid->ux_host_class_hid_semaphore.tx_semaphore_id ++; + + status = _ux_host_class_hid_report_callback_register(hid, UX_NULL); + if (status == UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + hid->ux_host_class_hid_semaphore.tx_semaphore_id --; + + /**************************************************/ + /** Test case: Can't find report with specified report id. **/ + /** Why direct: Normally, the id passed to this function is the id of an already-found report, so it will always find it. **/ + /**************************************************/ + + /* Set an unknown report id. */ + hid_report_callback.ux_host_class_hid_report_callback_id = 0xdeadbeef; + + status = _ux_host_class_hid_report_callback_register(hid, &hid_report_callback); + if (status != UX_HOST_CLASS_HID_REPORT_ERROR) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + 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_hid_report_descriptor_get_test.c b/test/regression/usbx_ux_host_class_hid_report_descriptor_get_test.c new file mode 100644 index 00000000..e1e650ec --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_report_descriptor_get_test.c @@ -0,0 +1,332 @@ +/**************************************************/ +/** Test case: default case of **/ +/** switch(item.ux_host_class_hid_item_report_type) **/ +/**************************************************/ + +#include "usbx_test_common_hid.h" + +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + + /* Add an unknown item type. bits 2-3 must be equal to 3. */ + 0x0d, 0x00, + + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + +#if 0 + //if (error_code != ) + printf("hello"); + { + + /* Something went wrong. */ + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } +#endif +} + +/* 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_descriptor_get_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_report_descriptor_get 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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); + } + + /* 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_hid_report_descriptor_get_test2.c b/test/regression/usbx_ux_host_class_hid_report_descriptor_get_test2.c new file mode 100644 index 00000000..a737ce27 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_report_descriptor_get_test2.c @@ -0,0 +1,377 @@ +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static UINT ux_hcd_sim_host_entry_filter(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; +UX_TRANSFER *transfer_request; + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + + switch(function) + { + case UX_HCD_GET_PORT_STATUS: + + break; + + case UX_HCD_TRANSFER_REQUEST: + + transfer_request = parameter; + + /* Is this the transfer request from descriptor_get()? */ + if (transfer_request -> ux_transfer_request_function == UX_GET_DESCRIPTOR && + transfer_request -> ux_transfer_request_type == (UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_INTERFACE) && + transfer_request -> ux_transfer_request_value == UX_HOST_CLASS_HID_REPORT_DESCRIPTOR << 8 && + transfer_request -> ux_transfer_request_index == 2) + { + + status = UX_ERROR; + } + + break; + + default: + + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + } + + return status; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_DESCRIPTOR_CORRUPTED) + { + + /* 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_descriptor_get_test2_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +UX_HCD *hcd; +ALIGN_TYPE tmp; + + + /* Inform user. */ + printf("Running ux_host_class_hid_report_descriptor_get Test 2....................... "); + + /* 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: status == UX_SUCCESS fails in **/ + /** if ((status == UX_SUCCESS) && (transfer_request -> ux_transfer_request_actual_length == length)) **/ + /**************************************************/ + + /* Swap the hcd entry function. */ + hcd = &_ux_system_host -> ux_system_host_hcd_array[0]; + tmp = (ALIGN_TYPE)hcd -> ux_hcd_entry_function; + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter; + + /**************************************************/ + /** END TEST **/ + /**************************************************/ + + /* 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, error code: %d\n", __LINE__, status); + 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); + } + + /* 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_hid_report_descriptor_get_test3.c b/test/regression/usbx_ux_host_class_hid_report_descriptor_get_test3.c new file mode 100644 index 00000000..45fc8e9c --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_report_descriptor_get_test3.c @@ -0,0 +1,377 @@ +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static UINT ux_hcd_sim_host_entry_filter(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; +UX_TRANSFER *transfer_request; + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + + switch(function) + { + case UX_HCD_GET_PORT_STATUS: + + break; + + case UX_HCD_TRANSFER_REQUEST: + + transfer_request = parameter; + + /* Is this the transfer request from descriptor_get()? */ + if (transfer_request -> ux_transfer_request_function == UX_GET_DESCRIPTOR && + transfer_request -> ux_transfer_request_type == (UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_INTERFACE) && + transfer_request -> ux_transfer_request_value == UX_HOST_CLASS_HID_REPORT_DESCRIPTOR << 8 && + transfer_request -> ux_transfer_request_index == 2) + { + + transfer_request -> ux_transfer_request_actual_length = 0; + } + + break; + + default: + + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + } + + return status; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_DESCRIPTOR_CORRUPTED) + { + + /* 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_descriptor_get_test3_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +UX_HCD *hcd; +ALIGN_TYPE tmp; + + + /* Inform user. */ + printf("Running ux_host_class_hid_report_descriptor_get Test 3....................... "); + + /* 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: transfer_request -> ux_transfer_request_actual_length == length fails in **/ + /** if ((status == UX_SUCCESS) && (transfer_request -> ux_transfer_request_actual_length == length)) **/ + /**************************************************/ + + /* Swap the hcd entry function. */ + hcd = &_ux_system_host -> ux_system_host_hcd_array[0]; + tmp = (ALIGN_TYPE)hcd -> ux_hcd_entry_function; + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter; + + /**************************************************/ + /** END TEST **/ + /**************************************************/ + + /* 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, error code: %d\n", __LINE__, status); + 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); + } + + /* 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_hid_report_descriptor_get_test4.c b/test/regression/usbx_ux_host_class_hid_report_descriptor_get_test4.c new file mode 100644 index 00000000..b81bb900 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_report_descriptor_get_test4.c @@ -0,0 +1,357 @@ +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + if (error_code != UX_MEMORY_INSUFFICIENT) + { + + /* 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_descriptor_get_test4_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_report_descriptor_get Test 4.............. "); + + /* 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_KEYBOARD *keyboard; +UX_MEMORY_BLOCK *dummy_memory_block_first = (UX_MEMORY_BLOCK *)dummy_usbx_memory; +UX_MEMORY_BLOCK *original_regular_memory_block = (UX_MEMORY_BLOCK *)_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start; +UX_MEMORY_BLOCK *original_cache_safe_memory_block = (UX_MEMORY_BLOCK *)_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_start; + + /* 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); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the keyboard instance */ + keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)hid_client -> ux_host_class_hid_client_local_instance; + + /**************************************************/ + /** Test case: descriptor = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, length); fails **/ + /**************************************************/ + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_byte_pool = UX_NULL; + // dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + // dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + // dummy_memory_block_first -> ux_memory_block_size = 0; + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start = (UCHAR *)dummy_memory_block_first; + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_start = (UCHAR *)dummy_memory_block_first; + + status = _ux_host_class_hid_report_descriptor_get(hid, 3092094); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start = (UCHAR *)original_regular_memory_block; + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_start = (UCHAR *)original_cache_safe_memory_block; + + /* 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_hid_report_get_test.c b/test/regression/usbx_ux_host_class_hid_report_get_test.c new file mode 100644 index 00000000..7c7f8c84 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_report_get_test.c @@ -0,0 +1,589 @@ +/* This test concentrates on the ux_host_class_hid_report_get API. */ + +#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) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* 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_get_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_report_get 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\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 on line %d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the hid class parameters for a keyboard. */ + 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); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, 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 UINT ux_hcd_sim_host_entry_filter(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; + + switch(function) + { + case UX_HCD_TRANSFER_REQUEST: + + status = UX_ERROR; + + break; + + + default: + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + break; + } + + return status; +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; +UX_HOST_CLASS_HID_CLIENT_REPORT input_report_request; +UX_HOST_CLASS_HID_REPORT *input_report_descriptor; +UX_HOST_CLASS_HID_KEYBOARD *keyboard; +UCHAR input_report_buffer_char[1024]; +ULONG *input_report_buffer_long = (ULONG *)input_report_buffer_char; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the keyboard instance */ + keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)hid_client->ux_host_class_hid_client_local_instance; + + /**************************************************/ + /** Test case: functionality test. **/ + /**************************************************/ + + /* Disable the default method of retrieving events (periodic interrupt endpoint) since we'll be using control transfers. */ + status = ux_host_class_hid_periodic_report_stop(hid); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Get the report ID for the keyboard. */ + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + status = _ux_host_class_hid_report_id_get(hid, &report_id); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + input_report_descriptor = report_id.ux_host_class_hid_report_get_report; + + /* Fill out input report request. */ + input_report_request.ux_host_class_hid_client_report = input_report_descriptor; + input_report_request.ux_host_class_hid_client_report_buffer = input_report_buffer_long; + input_report_request.ux_host_class_hid_client_report_length = input_report_descriptor -> ux_host_class_hid_report_byte_length; + + /* For the first part of this test, we request the raw report. */ + + input_report_request.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_RAW; + + /* Poll until we've received an input report with actual data. */ + while (1) + { + + /* Reset the actual length. */ + input_report_request.ux_host_class_hid_client_report_actual_length = 0; + + /* Get a raw input report from the device. */ + status = ux_host_class_hid_report_get(hid, &input_report_request); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Was there actual data? The modifier should be set if there is. */ + if (input_report_buffer_char[0] != 0) + break; + + tx_thread_sleep(10); + } + + /* Check the data. */ + + /* Is this not the modifier we're expecting? */ + if (input_report_buffer_char[0] != 0x45) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Are these not the keys we're expecting? */ + if (input_report_buffer_char[2] != 0x04 || + input_report_buffer_char[3] != 0x05 || + input_report_buffer_char[4] != 0x06 || + input_report_buffer_char[5] != 0x07 || + input_report_buffer_char[6] != 0x08 || + input_report_buffer_char[7] != 0x09) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* We just tested getting the report raw; this second part is getting it decompressed. + Note that the decompressed version is interleaved as 'Usage Value Usage Value...' */ + + input_report_request.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_DECOMPRESSED; + + /* Poll until we've received an input report with actual data. */ + while (1) + { + + /* Reset the actual length. */ + input_report_request.ux_host_class_hid_client_report_actual_length = 0; + + /* Get a raw input report from the device. */ + status = ux_host_class_hid_report_get(hid, &input_report_request); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Was there actual data? This value should be non-zero if it is. */ + if (input_report_buffer_long[2*0 + 1] != 0) + break; + + tx_thread_sleep(10); + } + + /* Check the data. */ + + /* Are these not the modifiers we're expecting? */ + if (input_report_buffer_long[2*0 + 0] != 0x000700e0 || + input_report_buffer_long[2*0 + 1] != 1 || + input_report_buffer_long[2*1 + 0] != 0x000700e1 || + input_report_buffer_long[2*1 + 1] != 0 || + input_report_buffer_long[2*2 + 0] != 0x000700e2 || + input_report_buffer_long[2*2 + 1] != 1 || + input_report_buffer_long[2*3 + 0] != 0x000700e3 || + input_report_buffer_long[2*3 + 1] != 0 || + input_report_buffer_long[2*4 + 0] != 0x000700e4 || + input_report_buffer_long[2*4 + 1] != 0 || + input_report_buffer_long[2*5 + 0] != 0x000700e5 || + input_report_buffer_long[2*5 + 1] != 0 || + input_report_buffer_long[2*6 + 0] != 0x000700e6 || + input_report_buffer_long[2*6 + 1] != 1 || + input_report_buffer_long[2*7 + 0] != 0x000700e7 || + input_report_buffer_long[2*7 + 1] != 0) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Are these not the usages and keys we're expecting? */ + if (input_report_buffer_long[2*9 + 0] != 0x00070004 || + input_report_buffer_long[2*9 + 1] != 0x00000004 || + input_report_buffer_long[2*10 + 0] != 0x00070005 || + input_report_buffer_long[2*10 + 1] != 0x00000005 || + input_report_buffer_long[2*11 + 0] != 0x00070006 || + input_report_buffer_long[2*11 + 1] != 0x00000006 || + input_report_buffer_long[2*12 + 0] != 0x00070007 || + input_report_buffer_long[2*12 + 1] != 0x00000007 || + input_report_buffer_long[2*13 + 0] != 0x00070008 || + input_report_buffer_long[2*13 + 1] != 0x00000008 || + input_report_buffer_long[2*14 + 0] != 0x00070009 || + input_report_buffer_long[2*14 + 1] != 0x00000009) + { + + printf("Error on line %d\n", __LINE__); + 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); +} + +static void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + +UX_SLAVE_DEVICE *device; +UX_SLAVE_INTERFACE *interface; +UX_SLAVE_CLASS_HID *hid; +UX_SLAVE_CLASS_HID_EVENT hid_event; + + /* Get the pointer to the device. */ + device = &_ux_system_slave -> ux_system_slave_device; + + /* reset the HID event structure. */ + ux_utility_memory_set(&hid_event, 0, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + + while(1) + { + + /* Is the device configured ? */ + while (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED) + + /* Then wait. */ + tx_thread_sleep(10); + + /* Until the device stays configured. */ + while (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED) + { + + /* Get the interface. We use the first interface, this is a simple device. */ + interface = device -> ux_slave_device_first_interface; + + /* Form that interface, derive the HID owner. */ + hid = interface -> ux_slave_interface_class_instance; + + /* Wait for 2 seconds. */ + ux_utility_thread_sleep(20); + + /* Then insert a key into the keyboard event. Length is fixed to 8. */ + hid_event.ux_device_class_hid_event_length = 8; + + /* First byte is a modifier byte. Set some bits: 10100010. */ + hid_event.ux_device_class_hid_event_buffer[0] = 0x45; + + /* Second byte is reserved. */ + hid_event.ux_device_class_hid_event_buffer[1] = 0; + + /* The 6 next bytes are keys. */ + hid_event.ux_device_class_hid_event_buffer[2] = 0x04; + hid_event.ux_device_class_hid_event_buffer[3] = 0x05; + hid_event.ux_device_class_hid_event_buffer[4] = 0x06; + hid_event.ux_device_class_hid_event_buffer[5] = 0x07; + hid_event.ux_device_class_hid_event_buffer[6] = 0x08; + hid_event.ux_device_class_hid_event_buffer[7] = 0x09; + + /* Set the keyboard event. */ + ux_device_class_hid_event_set(hid, &hid_event); + } + } +} + diff --git a/test/regression/usbx_ux_host_class_hid_report_get_test2.c b/test/regression/usbx_ux_host_class_hid_report_get_test2.c new file mode 100644 index 00000000..a5224029 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_report_get_test2.c @@ -0,0 +1,630 @@ +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + +#include "ux_test_utility_sim.h" + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* 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_get_test2_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_report_get Test 2......................... "); + + /* 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static UINT ux_hcd_sim_host_entry_filter(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; +UX_TRANSFER *transfer_request; + + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + + /* Let get port status requests don't return UX_SUCCESS. */ + if (status != UX_SUCCESS && function != UX_HCD_GET_PORT_STATUS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + if (function == UX_HCD_TRANSFER_REQUEST) + { + + transfer_request = parameter; + + if (transfer_request -> ux_transfer_request_requested_length == 8 && + transfer_request -> ux_transfer_request_function == 1 && + transfer_request -> ux_transfer_request_type == 0xa1 && + transfer_request -> ux_transfer_request_value == 0x100 && + transfer_request -> ux_transfer_request_index == 2) + { + + transfer_request -> ux_transfer_request_actual_length = 0; + } + } + + return status; +} + +static UINT ux_hcd_sim_host_entry_filter_transfer_request_failed_test2(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; +UX_TRANSFER *transfer_request; + + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + + /* Let get port status requests don't return UX_SUCCESS. */ + if (status != UX_SUCCESS && function != UX_HCD_GET_PORT_STATUS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + if (function == UX_HCD_TRANSFER_REQUEST) + { + + transfer_request = parameter; + + if (transfer_request -> ux_transfer_request_requested_length == 8 && + transfer_request -> ux_transfer_request_function == 1 && + transfer_request -> ux_transfer_request_type == 0xa1 && + transfer_request -> ux_transfer_request_value == 0x100 && + transfer_request -> ux_transfer_request_index == 2) + { + + status = UX_ERROR; + } + } + + return status; +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_KEYBOARD *keyboard; +UX_HCD *hcd; +ALIGN_TYPE tmp; +UX_HOST_CLASS_HID_CLIENT_REPORT client_report; +UX_HOST_CLASS_HID_REPORT hid_report; +ULONG client_report_buffer[32/4]; + + /**************************************************/ + /**************************************************/ + /** Why direct: this is a user API and not called by USBX. **/ + /**************************************************/ + /**************************************************/ + + /* 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); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the keyboard instance */ + keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)hid_client -> ux_host_class_hid_client_local_instance; + + /**************************************************/ + /** Test case: (status == UX_SUCCESS) fails in + if ((status == UX_SUCCESS) && (transfer_request -> ux_transfer_request_actual_length == hid_report -> ux_host_class_hid_report_byte_length)) **/ + /**************************************************/ + + hid_report.ux_host_class_hid_report_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + + client_report.ux_host_class_hid_client_report = &hid_report; + client_report.ux_host_class_hid_client_report = hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_input_report; + client_report.ux_host_class_hid_client_report_length = 32; + + /* Swap the hcd entry function. */ + hcd = UX_DEVICE_HCD_GET(hid -> ux_host_class_hid_device); + tmp = (ALIGN_TYPE)hcd -> ux_hcd_entry_function; + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter_transfer_request_failed_test2; + + status = _ux_host_class_hid_report_get(hid, &client_report); + if (status != UX_HOST_CLASS_HID_REPORT_ERROR) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /** Restore state for next test. **/ + + /* Restore entry function. */ + hcd -> ux_hcd_entry_function = (UINT (*) (struct UX_HCD_STRUCT *, UINT, VOID *))tmp; + + /* ux_host_stack_transfer_request() doesn't release the device protection semaphore when it fails, so do it manually. */ + _ux_utility_semaphore_put(&hid -> ux_host_class_hid_device -> ux_device_protection_semaphore); + + /**************************************************/ + /** Test case: (transfer_request -> ux_transfer_request_actual_length == hid_report -> ux_host_class_hid_report_byte_length) fails in + if ((status == UX_SUCCESS) && (transfer_request -> ux_transfer_request_actual_length == hid_report -> ux_host_class_hid_report_byte_length)) **/ + /**************************************************/ + + hid_report.ux_host_class_hid_report_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + + client_report.ux_host_class_hid_client_report = &hid_report; + client_report.ux_host_class_hid_client_report = hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_input_report; + client_report.ux_host_class_hid_client_report_length = 32; + + /* Swap the hcd entry function. */ + hcd = UX_DEVICE_HCD_GET(hid -> ux_host_class_hid_device); + tmp = (ALIGN_TYPE)hcd -> ux_hcd_entry_function; + hcd -> ux_hcd_entry_function = ux_hcd_sim_host_entry_filter; + + status = _ux_host_class_hid_report_get(hid, &client_report); + if (status != UX_HOST_CLASS_HID_REPORT_ERROR) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore entry function. */ + hcd -> ux_hcd_entry_function = (UINT (*) (struct UX_HCD_STRUCT *, UINT, VOID *))tmp; + + /* ux_host_stack_transfer_request() doesn't release the device protection semaphore when it fails, so do it manually. */ + _ux_utility_semaphore_put(&hid -> ux_host_class_hid_device -> ux_device_protection_semaphore); + + /**************************************************/ + /** Test case: status = _ux_utility_semaphore_get(&hid -> ux_host_class_hid_device -> ux_device_protection_semaphore, UX_WAIT_FOREVER); fails **/ + /**************************************************/ + + hid_report.ux_host_class_hid_report_byte_length = 1; + hid_report.ux_host_class_hid_report_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + client_report.ux_host_class_hid_client_report = &hid_report; + + /* Make sure it fails. */ + hid -> ux_host_class_hid_device -> ux_device_protection_semaphore.tx_semaphore_id++; + + status = _ux_host_class_hid_report_get(hid, &client_report); + if(status != TX_SEMAPHORE_ERROR) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state. */ + hid -> ux_host_class_hid_device -> ux_device_protection_semaphore.tx_semaphore_id--; + + /* The function did a get() on the hid semaphore and never put() it, so we must do it!!! FOR THE GOOD OF HUMANITY... BY THE POWER INVESTED IN ME, YOU SHALL BE PUT()'d! */ + status = ux_utility_semaphore_put(&hid -> ux_host_class_hid_semaphore); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: _ux_utility_semaphore_get(&hid -> ux_host_class_hid_semaphore, UX_WAIT_FOREVER); fails **/ + /**************************************************/ + + /* Make sure it fails. */ + hid -> ux_host_class_hid_semaphore.tx_semaphore_id++; + + status = _ux_host_class_hid_report_get(hid, UX_NULL); + if(status != TX_SEMAPHORE_ERROR) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state. */ + hid -> ux_host_class_hid_semaphore.tx_semaphore_id--; + + /**************************************************/ + /** Test case: making ux_utility_memory_allocate() fails **/ + /**************************************************/ + + hid_report.ux_host_class_hid_report_byte_length = 1; + hid_report.ux_host_class_hid_report_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + client_report.ux_host_class_hid_client_report = &hid_report; + + ux_test_utility_sim_mem_alloc_fail_all_start(); + + status = _ux_host_class_hid_report_get(hid, &client_report); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + ux_test_utility_sim_mem_alloc_fail_all_stop(); + + /**************************************************/ + /** Test case: _ux_host_stack_class_instance_verify() fails. **/ + /**************************************************/ + + /* Make sure verify() doesn't find any classes. */ + // tmp = _ux_system_host -> ux_system_host_max_class; + // _ux_system_host -> ux_system_host_max_class = 0; + tmp = _ux_system_host->ux_system_host_class_array->ux_host_class_status; + _ux_system_host->ux_system_host_class_array->ux_host_class_status = UX_UNUSED; + + if (ux_host_class_hid_report_get(hid, &client_report) != UX_HOST_CLASS_INSTANCE_UNKNOWN) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Restore state for next test. */ + // _ux_system_host -> ux_system_host_max_class = (UINT)tmp; + _ux_system_host->ux_system_host_class_array->ux_host_class_status = (UINT)tmp; + + /**************************************************/ + /** Test case: if (hid_report -> ux_host_class_hid_report_type != UX_HOST_CLASS_HID_REPORT_TYPE_INPUT). **/ + /**************************************************/ + + /* Set to a non-input report. */ + hid_report.ux_host_class_hid_report_type = ~UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + + client_report.ux_host_class_hid_client_report = &hid_report; + + if (_ux_host_class_hid_report_get(hid, &client_report) != UX_HOST_CLASS_HID_REPORT_ERROR) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /**************************************************/ + /** Test case: if (hid_report -> ux_host_class_hid_report_type != UX_HOST_CLASS_HID_REPORT_TYPE_FEATURE). **/ + /**************************************************/ + + /* Set to a feature report. */ + hid_report.ux_host_class_hid_report_type = UX_HOST_CLASS_HID_REPORT_TYPE_FEATURE; + + client_report.ux_host_class_hid_client_report = &hid_report; + client_report.ux_host_class_hid_client_report_buffer = client_report_buffer; + tmp = client_report.ux_host_class_hid_client_report_flags; + client_report.ux_host_class_hid_client_report_flags |= UX_HOST_CLASS_HID_REPORT_RAW; + + status = _ux_host_class_hid_report_get(hid, &client_report); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, %x\n", __LINE__, status); + test_control_return(1); + } + + /* Restore. */ + client_report.ux_host_class_hid_client_report_flags = tmp; + + /**************************************************/ + /** Test case: request a zero-length report. **/ + /**************************************************/ + + /* Set to a zero-length input report. */ + hid_report.ux_host_class_hid_report_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + hid_report.ux_host_class_hid_report_byte_length = 0; + + client_report.ux_host_class_hid_client_report = &hid_report; + + if (_ux_host_class_hid_report_get(hid, &client_report) != UX_HOST_CLASS_HID_REPORT_ERROR) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /**************************************************/ + /** Test case: not enough memory to store report. **/ + /**************************************************/ + + /* Set to the report in the main report descriptor. */ + client_report.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_RAW; + client_report.ux_host_class_hid_client_report = hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_input_report; + client_report.ux_host_class_hid_client_report_length = 0; + + if (_ux_host_class_hid_report_get(hid, &client_report) != UX_BUFFER_OVERFLOW) + { + + printf("Error on line %d\n", __LINE__); + 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_hid_report_id_get_test.c b/test/regression/usbx_ux_host_class_hid_report_id_get_test.c new file mode 100644 index 00000000..a3664bab --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_report_id_get_test.c @@ -0,0 +1,453 @@ +/* This file tests ux_host_class_hid_report_id_get() */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + + 0x85, 0x01, // REPORT_ID (1) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + + 0x85, 0x02, // REPORT_ID (2) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + + 0xc0, // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* 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_id_get_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_report_id_get 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, error code: 0x%x\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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: 0x%x\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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + 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, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_REPORT_GET_ID report_get_id = { 0 }; +UX_HOST_CLASS_HID_CLIENT *hid_client; +UX_HOST_CLASS_HID_KEYBOARD *keyboard; + + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the keyboard instance */ + keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)hid_client -> ux_host_class_hid_client_local_instance; + + /**************************************************/ + /** Test case: _ux_host_stack_class_instance_verify() fails. **/ + /**************************************************/ + + status = _ux_host_class_hid_report_id_get(UX_NULL, &report_get_id); + if(status != UX_HOST_CLASS_INSTANCE_UNKNOWN) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: status = _ux_utility_semaphore_get(&hid -> ux_host_class_hid_semaphore, UX_WAIT_FOREVER); fails **/ + /**************************************************/ + + /* Make sure it fails. */ + hid -> ux_host_class_hid_semaphore.tx_semaphore_id++; + + status = _ux_host_class_hid_report_id_get(hid, &report_get_id); + if(status != TX_SEMAPHORE_ERROR) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state. */ + hid -> ux_host_class_hid_semaphore.tx_semaphore_id--; + + /**************************************************/ + /** Test case: switch (report_id -> ux_host_class_hid_report_get_type) feature case. **/ + /** Why direct: can't force internal APIs to use feature report type. **/ + /**************************************************/ + + /* Set the report type to unknown value. */ + report_get_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_FEATURE; + + status = _ux_host_class_hid_report_id_get(hid, &report_get_id); + + /* There ain't any feature reports. */ + if(status == UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: switch (report_id -> ux_host_class_hid_report_get_type) default case. **/ + /** Why direct: can't force internal APIs to use incorrect report type. **/ + /**************************************************/ + + /* Set the report type to unknown value. */ + report_get_id.ux_host_class_hid_report_get_type = 0; + + status = _ux_host_class_hid_report_id_get(hid, &report_get_id); + if(status != UX_HOST_CLASS_HID_REPORT_ERROR) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: read reports until there is no more. **/ + /**************************************************/ + + report_get_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + report_get_id.ux_host_class_hid_report_get_report = UX_NULL; + + /* 1st try: expect OK. */ + status = _ux_host_class_hid_report_id_get(hid, &report_get_id); + if(status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* 2nd try: expect OK. */ + status = _ux_host_class_hid_report_id_get(hid, &report_get_id); + if(status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* 3rd try: expect OK. */ + status = _ux_host_class_hid_report_id_get(hid, &report_get_id); + if(status != UX_SUCCESS) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* 4th try: expect FAIL. */ + + /**************************************************/ + /** Test case: if (hid_report -> ux_host_class_hid_report_next_report == UX_NULL). **/ + /** Why direct: in order to fail, must be called multiple times, but only called once in activate functions (i.e. ux_host_class_hid_keyboard_activate()). **/ + /**************************************************/ + + /* Set the report type to input and the current report to the only report (this will cause the API to get the next report, which doesn't exist). */ + report_get_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + + status = _ux_host_class_hid_report_id_get(hid, &report_get_id); + if(status != UX_HOST_CLASS_HID_REPORT_ERROR) + { + + printf("Error on line %d, error code: 0x%x\n", __LINE__, status); + 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_hid_report_set_int_out_test.c b/test/regression/usbx_ux_host_class_hid_report_set_int_out_test.c new file mode 100644 index 00000000..c09f5365 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_report_set_int_out_test.c @@ -0,0 +1,419 @@ +/* This test concentrates on the ux_host_class_hid_report_set API. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" +#include "ux_device_class_hid.h" +#include "ux_test_hcd_sim_host.h" + +UCHAR buffer[64]; +UINT test_number; +UCHAR buffer_device[64]; +TX_SEMAPHORE test_semaphore; +static UX_SLAVE_CLASS_HID * device_hid; +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + + 0x85, 0x01, // REPORT_ID (1) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x08, // REPORT_SIZE (8) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + + 0xc0 // END_COLLECTION +}; +#define HID_REPORT_LENGTH sizeof(hid_report_descriptor)/sizeof(hid_report_descriptor[0]) + + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 59 +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, 0x29, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x02, 0x00, 0x02, 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, 0x81, 0x03, 0x08, 0x00, 0x08, + + /* Endpoint descriptor (Interrupt OUT) */ + 0x07, 0x05, 0x02, 0x03, 0x01, 0x00, 0x08 + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 69 +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, 0x29, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x02, 0x00, 0x02, 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, 0x81, 0x03, 0x08, 0x00, 0x08, + + /* Endpoint descriptor (Interrupt OUT) */ + 0x07, 0x05, 0x02, 0x03, 0x01, 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 + }; + +static UX_TEST_HCD_SIM_ACTION error_on_transfer_0[] = { +/* 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_SIM_REQ_ANSWER, 0, UX_NULL, 0, UX_ERROR, + UX_ERROR}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION zlp_on_transfer_0[] = { +/* 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_SIM_REQ_ANSWER, 0, UX_NULL, 0, UX_SUCCESS, + UX_SUCCESS}, +{ 0 } +}; + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +static VOID instance_activate_callback(VOID *parameter) +{ + + device_hid = (UX_SLAVE_CLASS_HID *)parameter; + tx_thread_resume(&tx_demo_thread_slave_simulation); +} + +/* 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_set_int_out_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 ux_host_class_hid_report_set_int_out 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); + } + + /* 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; + hid_parameter.ux_slave_class_hid_instance_activate = instance_activate_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_test_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); + } + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_DONT_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } +} + +static UINT demo_thread_hid_callback(UX_SLAVE_CLASS_HID *class, UX_SLAVE_CLASS_HID_EVENT *event) +{ + + + return(UX_SUCCESS); +} +static void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + +UINT status; +UX_SLAVE_TRANSFER *transfer_request; + + transfer_request = &device_hid->ux_device_class_hid_interrupt_endpoint->ux_slave_endpoint_next_endpoint->ux_slave_endpoint_transfer_request; + + status = _ux_device_stack_transfer_request(transfer_request, 1, 1); + + if(status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_CLIENT_REPORT client_report; +UX_HOST_CLASS_HID_REPORT hid_report; +UX_HOST_CLASS_HID_REPORT *hid_report_ptr; +UCHAR buffer[256]; +UX_HOST_CLASS_HID_REPORT_GET_ID report_id; + + + status = ux_utility_semaphore_create(&test_semaphore, "test_semaphore", 0); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + report_id.ux_host_class_hid_report_get_report = UX_NULL; + report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_OUTPUT; + status = _ux_host_class_hid_report_id_get(hid, &report_id); + if(status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + client_report.ux_host_class_hid_client_report = report_id.ux_host_class_hid_report_get_report; + client_report.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_RAW; + client_report.ux_host_class_hid_client_report_length = report_id.ux_host_class_hid_report_get_report->ux_host_class_hid_report_byte_length; + client_report.ux_host_class_hid_client_report_buffer = (ULONG *)buffer; + + status = _ux_host_class_hid_report_set(hid, &client_report); + if(status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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); +} diff --git a/test/regression/usbx_ux_host_class_hid_report_set_test.c b/test/regression/usbx_ux_host_class_hid_report_set_test.c new file mode 100644 index 00000000..37b25a3c --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_report_set_test.c @@ -0,0 +1,625 @@ +/* This test concentrates on the ux_host_class_hid_report_set API. */ + +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + +#include "ux_test_hcd_sim_host.h" + +UCHAR buffer[64]; +UINT test_number; +UCHAR buffer_device[64]; +TX_SEMAPHORE test_semaphore; + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +#define NUM_TESTS 5 +UCHAR test_buffers[NUM_TESTS][5] = { + {0xab, 0xcd, 0xef, 0x01, 0x23}, + {0x23, 0xab, 0xcd, 0xef, 0x01}, + {0x01, 0x23, 0xab, 0xcd, 0xef}, + {0xef, 0x01, 0x23, 0xab, 0xcd}, + {0xcd, 0xef, 0x01, 0x23, 0xab}, +}; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + + 0x85, 0x01, // REPORT_ID (1) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x08, // REPORT_SIZE (8) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + + 0xc0 // END_COLLECTION +}; +#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 + }; + +static UX_TEST_HCD_SIM_ACTION error_on_transfer_0[] = { +/* 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_SIM_REQ_ANSWER, 0, UX_NULL, 0, UX_ERROR, + UX_ERROR}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION zlp_on_transfer_0[] = { +/* 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_SIM_REQ_ANSWER, 0, UX_NULL, 0, UX_SUCCESS, + UX_SUCCESS}, +{ 0 } +}; + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +/* 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_set_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 ux_host_class_hid_report_set 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_test_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 UINT demo_thread_hid_callback(UX_SLAVE_CLASS_HID *class, UX_SLAVE_CLASS_HID_EVENT *event) +{ + + if (event -> ux_device_class_hid_event_report_type == UX_DEVICE_CLASS_HID_REPORT_TYPE_OUTPUT) + { + + if (test_number > 0) + { + + /* Ensure report id is correct. */ + if (event -> ux_device_class_hid_event_buffer[0] != 0x01) + { + + printf("Error on line %d: test number %d, report id %d\n", __LINE__, test_number, event -> ux_device_class_hid_event_buffer[0]); + test_control_return(1); + } + + if (ux_utility_memory_compare(test_buffers[test_number - 1], event->ux_device_class_hid_event_buffer + 1, 5) != UX_SUCCESS) + { + + printf("Error on line %d: test number %d\n -", __LINE__, test_number); + for (int i = 0; i < 5; i ++) + printf(" %2x", test_buffers[test_number - 1][i]); + printf(" <>\n -"); + for (int i = 0; i < 5; i ++) + printf(" %2x", event->ux_device_class_hid_event_buffer[i + 1]); + printf("\n"); + test_control_return(1); + } + + ux_utility_semaphore_put(&test_semaphore); + } + } + + return(UX_SUCCESS); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS_HID_CLIENT_REPORT client_report; +UX_HOST_CLASS_HID_REPORT hid_report; +UX_HOST_CLASS_HID_REPORT *hid_report_ptr; +ULONG tmp; +UX_MEMORY_BLOCK *dummy_memory_block_first = (UX_MEMORY_BLOCK *)dummy_usbx_memory; +UX_MEMORY_BLOCK *original_regular_memory_block = (UX_MEMORY_BLOCK *)_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start; +UX_MEMORY_BLOCK *original_cache_safe_memory_block = (UX_MEMORY_BLOCK *)_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_start; +UCHAR buffer[256]; + + + status = ux_utility_semaphore_create(&test_semaphore, "test_semaphore", 0); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Find the HID class */ + status = demo_class_hid_get(); + if (status != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /**************************************************/ + /** Test case: status = _ux_utility_semaphore_get(&hid -> ux_host_class_hid_device -> ux_device_protection_semaphore, UX_WAIT_FOREVER); fails **/ + /**************************************************/ + + client_report.ux_host_class_hid_client_report = hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_output_report -> ux_host_class_hid_report_next_report; + client_report.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_RAW; + client_report.ux_host_class_hid_client_report_length = 5; + client_report.ux_host_class_hid_client_report_buffer = (ULONG *)buffer; + + /* Make sure it fails. */ + hid -> ux_host_class_hid_device -> ux_device_protection_semaphore.tx_semaphore_id++; + + status = _ux_host_class_hid_report_set(hid, &client_report); + if(status != TX_SEMAPHORE_ERROR) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state. */ + hid -> ux_host_class_hid_device -> ux_device_protection_semaphore.tx_semaphore_id--; + + /* The function did a get() on the hid semaphore and never put() it since we error'd out, so we must do it! */ + status = ux_utility_semaphore_put(&hid -> ux_host_class_hid_semaphore); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /**************************************************/ + /** Test case: status = _ux_utility_semaphore_get(&hid -> ux_host_class_hid_semaphore, UX_WAIT_FOREVER); fails **/ + /**************************************************/ + + client_report.ux_host_class_hid_client_report = hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_output_report -> ux_host_class_hid_report_next_report; + client_report.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_RAW; + client_report.ux_host_class_hid_client_report_length = 5; + + /* Make sure it fails. */ + hid -> ux_host_class_hid_semaphore.tx_semaphore_id++; + + status = _ux_host_class_hid_report_set(hid, &client_report); + if(status != TX_SEMAPHORE_ERROR) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state. */ + hid -> ux_host_class_hid_semaphore.tx_semaphore_id--; + + /**************************************************/ + /** Test case: Template for making ux_utility_memory_allocate() fail **/ + /**************************************************/ + + hid_report.ux_host_class_hid_report_type = UX_HOST_CLASS_HID_REPORT_TYPE_OUTPUT; + client_report.ux_host_class_hid_client_report = &hid_report; + + /* Set up the dummy memory block. */ + dummy_memory_block_first -> ux_memory_block_next = UX_NULL; + dummy_memory_block_first -> ux_memory_byte_pool = UX_NULL; + // dummy_memory_block_first -> ux_memory_block_previous = UX_NULL; + // dummy_memory_block_first -> ux_memory_block_status = UX_MEMORY_UNUSED; + // dummy_memory_block_first -> ux_memory_block_size = 0; + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start = (UCHAR*)dummy_memory_block_first; + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_start = (UCHAR*)dummy_memory_block_first; + + status = _ux_host_class_hid_report_set(hid, &client_report); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Restore state for next test. */ + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start = (UCHAR*)original_regular_memory_block; + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_start = (UCHAR*)original_cache_safe_memory_block; + + /**************************************************/ + /** Test case: _ux_host_stack_class_instance_verify() fails. **/ + /**************************************************/ + + /* Make sure verify() doesn't find any classes. */ + // tmp = _ux_system_host -> ux_system_host_max_class; + // _ux_system_host -> ux_system_host_max_class = 0; + tmp = _ux_system_host->ux_system_host_class_array->ux_host_class_status; + _ux_system_host->ux_system_host_class_array->ux_host_class_status = UX_UNUSED; + + if (_ux_host_class_hid_report_set(hid, UX_NULL) != UX_HOST_CLASS_INSTANCE_UNKNOWN) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Restore state for next test. */ + // _ux_system_host -> ux_system_host_max_class = tmp; + _ux_system_host->ux_system_host_class_array->ux_host_class_status = (UINT)tmp; + + /**************************************************/ + /** Test case: if (hid_report -> ux_host_class_hid_report_type == UX_HOST_CLASS_HID_REPORT_TYPE_INPUT) **/ + /**************************************************/ + + /* Set to an input report. */ + hid_report.ux_host_class_hid_report_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT; + + client_report.ux_host_class_hid_client_report = &hid_report; + + if (_ux_host_class_hid_report_set(hid, &client_report) != UX_HOST_CLASS_HID_REPORT_ERROR) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /**************************************************/ + /** Test case: if (hid_report -> ux_host_class_hid_report_byte_length < client_report -> ux_host_class_hid_client_report_length) **/ + /**************************************************/ + + /* Set client report length to less than hid report length. */ + hid_report.ux_host_class_hid_report_type = UX_HOST_CLASS_HID_REPORT_TYPE_FEATURE; + hid_report.ux_host_class_hid_report_byte_length = 1; + client_report.ux_host_class_hid_client_report_length = hid_report.ux_host_class_hid_report_byte_length + 1; + + client_report.ux_host_class_hid_client_report = &hid_report; + client_report.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_RAW; + + if (_ux_host_class_hid_report_set(hid, &client_report) != UX_HOST_CLASS_HID_REPORT_OVERFLOW) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /**************************************************/ + /** Test case: call _ux_host_class_hid_report_compress(). **/ + /**************************************************/ + + hid_report_ptr = hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_output_report; + + client_report.ux_host_class_hid_client_report = hid_report_ptr; + client_report.ux_host_class_hid_client_report_length = hid_report_ptr -> ux_host_class_hid_report_byte_length; + client_report.ux_host_class_hid_client_report_buffer = (ULONG *)buffer; + client_report.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_DECOMPRESSED; + + if (_ux_host_class_hid_report_set(hid, &client_report) != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /**************************************************/ + /** Test case: ux_host_stack_transfer_request() fails. **/ + /**************************************************/ + + ux_test_hcd_sim_host_set_actions(error_on_transfer_0); + + if (_ux_host_class_hid_report_set(hid, &client_report) != UX_HOST_CLASS_HID_REPORT_ERROR) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /** Restore state for next test. **/ + + /* ux_host_stack_transfer_request() doesn't release the device protection semaphore when it fails, so do it manually. */ + ux_utility_semaphore_put(&hid -> ux_host_class_hid_device -> ux_device_protection_semaphore); + + /**************************************************/ + /** Test case: ux_host_stack_transfer_request() length error. **/ + /**************************************************/ + + ux_test_hcd_sim_host_set_actions(zlp_on_transfer_0); + + if (_ux_host_class_hid_report_set(hid, &client_report) != UX_HOST_CLASS_HID_REPORT_ERROR) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /** Restore state for next test. **/ + + /* ux_host_stack_transfer_request() doesn't release the device protection semaphore when it fails, so do it manually. */ + ux_utility_semaphore_put(&hid -> ux_host_class_hid_device -> ux_device_protection_semaphore); + +#if 0 /* TODO: USBX-246, USBX-247 */ + /**************************************************/ + /** Test case: functionality test. **/ + /**************************************************/ + + client_report.ux_host_class_hid_client_report = hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_output_report -> ux_host_class_hid_report_next_report; + client_report.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_RAW; + client_report.ux_host_class_hid_client_report_length = 5; + + /* Perform tests. */ + for (test_number = 1; test_number <= NUM_TESTS; test_number++) + { + client_report.ux_host_class_hid_client_report_buffer = (ULONG *)test_buffers[test_number - 1]; + + if (_ux_host_class_hid_report_set(hid, &client_report) != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /* Wait for device to receive our request. */ + if (ux_utility_semaphore_get(&test_semaphore, 10) != UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + } +#endif + /* 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); +} diff --git a/test/regression/usbx_ux_host_class_hid_transfer_request_completed_test.c b/test/regression/usbx_ux_host_class_hid_transfer_request_completed_test.c new file mode 100644 index 00000000..e57c2c91 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hid_transfer_request_completed_test.c @@ -0,0 +1,483 @@ +#include "usbx_test_common_hid.h" +#include "ux_host_class_hid_keyboard.h" + +#include "ux_test_utility_sim.h" + +#define DUMMY_USBX_MEMORY_SIZE (64*1024) +static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE]; + +static UCHAR hid_report_descriptor[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; +#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 + }; + + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + + +static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c) +{ + return 0; +} + + +static UINT error_counts = 0; +static UINT last_error = UX_SUCCESS; +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + error_counts ++; + last_error = error_code; + if (error_code != UX_MEMORY_INSUFFICIENT && + error_code != UX_TRANSFER_NOT_READY) + { + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + 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_transfer_request_completed_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_hid_transfer_request_completed 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, error code: %d\n", __LINE__, status); + 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_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + 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, error code: %d\n", __LINE__, status); + test_control_return(1); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Error on line %d, error code: %d\n", __LINE__, status); + test_control_return(1); + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ALIGN_TYPE tmp; +UX_TRANSFER transfer_request; +UX_DEVICE device; +UX_ENDPOINT endpoint; +UX_HOST_CLASS_HID_KEYBOARD *keyboard; + + /* 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); + } + + /* Get the HID client */ + hid_client = hid -> ux_host_class_hid_client; + + /* Check if the instance of the keyboard is live */ + while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL) + tx_thread_sleep(10); + + /* Get the keyboard instance */ + keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)hid_client -> ux_host_class_hid_client_local_instance; + + /**************************************************/ + /** Test case: Template for making ux_utility_memory_allocate() fail **/ + /**************************************************/ + + device.ux_device_state = UX_DEVICE_RESET; + endpoint.ux_endpoint_device = &device; + transfer_request.ux_transfer_request_endpoint = &endpoint; + transfer_request.ux_transfer_request_class_instance = hid; + transfer_request.ux_transfer_request_completion_code = UX_SUCCESS; + + ux_test_utility_sim_mem_alloc_fail_all_start(); + + _ux_host_class_hid_transfer_request_completed(&transfer_request); + + /* Restore state for next test. */ + ux_test_utility_sim_mem_alloc_fail_all_stop(); + + /**************************************************/ + /** Test case: if (hid_report -> ux_host_class_hid_report_callback_function != UX_NULL) fails **/ + /**************************************************/ + + tmp = (ALIGN_TYPE)hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_input_report -> ux_host_class_hid_report_callback_function; + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_input_report -> ux_host_class_hid_report_callback_function = UX_NULL; + + /* Wait for transfer_completed() to run. */ + tx_thread_sleep(50); + + /* Restore state for next test. */ + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_input_report -> ux_host_class_hid_report_callback_function = (VOID (*) (struct UX_HOST_CLASS_HID_REPORT_CALLBACK_STRUCT *))tmp; + + /**************************************************/ + /** Test case: (hid_report->ux_host_class_hid_report_number_item * 8) overflow **/ + /**************************************************/ + + tmp = hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_input_report -> ux_host_class_hid_report_number_item; + + last_error = UX_SUCCESS; + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_input_report -> ux_host_class_hid_report_number_item = 0xFFFFFFFF; + + /* Wait for transfer_completed() to run. */ + tx_thread_sleep(50); + + if (last_error != UX_MEMORY_INSUFFICIENT) + { + printf("Error on line %d, expect error code: %d\n", __LINE__, last_error); + test_control_return(1); + } + + /* Restore state for next test. */ + hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_input_report -> ux_host_class_hid_report_number_item = (ULONG)tmp; + + /* 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 void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + +UX_SLAVE_DEVICE *device; +UX_SLAVE_INTERFACE *interface; +UX_SLAVE_CLASS_HID *hid; +UX_SLAVE_CLASS_HID_EVENT hid_event; +UCHAR key; + + /* Get the pointer to the device. */ + device = &_ux_system_slave -> ux_system_slave_device; + + /* Set the first key to 'a' which is 04. */ + key = 0x04; + + /* reset the HID event structure. */ + ux_utility_memory_set(&hid_event, 0, sizeof(UX_SLAVE_CLASS_HID_EVENT)); + + while(1) + { + + /* Is the device configured ? */ + while (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED) + + /* Then wait. */ + tx_thread_sleep(10); + + /* Until the device stays configured. */ + while (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED) + { + + /* Get the interface. We use the first interface, this is a simple device. */ + interface = device -> ux_slave_device_first_interface; + + /* Form that interface, derive the HID owner. */ + hid = interface -> ux_slave_interface_class_instance; + + /* Wait for 2 seconds. */ + ux_utility_thread_sleep(20); + + /* Then insert a key into the keyboard event. Length is fixed to 8. */ + hid_event.ux_device_class_hid_event_length = 8; + + /* First byte is a modifier byte. */ + hid_event.ux_device_class_hid_event_buffer[0] = 0; + + /* Second byte is reserved. */ + hid_event.ux_device_class_hid_event_buffer[1] = 0; + + /* The 6 next bytes are keys. We only have one key here. */ + hid_event.ux_device_class_hid_event_buffer[2] = key; + + /* Set the keyboard event. */ + ux_device_class_hid_event_set(hid, &hid_event); + + /* Next event has the key depressed. */ + hid_event.ux_device_class_hid_event_buffer[2] = 0; + + /* Length is fixed to 8. */ + hid_event.ux_device_class_hid_event_length = 8; + + /* Set the keyboard event. */ + ux_device_class_hid_event_set(hid, &hid_event); + + /* Are we at the end of alphabet ? */ + if (key != (0x04 + 26)) + + /* Next key. */ + key++; + + else + + /* Start over again. */ + key = 0x04; + + } + } +} + + +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_hub_descriptor_get_coverage_test.c b/test/regression/usbx_ux_host_class_hub_descriptor_get_coverage_test.c new file mode 100644 index 00000000..6cfc93b4 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hub_descriptor_get_coverage_test.c @@ -0,0 +1,90 @@ +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" +#include "ux_test.h" +#include "ux_host_class_hub.h" +#include "ux_test_utility_sim.h" + + +static UX_HOST_CLASS_HUB hub; +static UX_DEVICE hub_device; +static UX_DEVICE device; +static UX_INTERFACE hub_interface; +static UX_TRANSFER *transfer_request; +static UX_ENDPOINT transfer_request_endpoint; +static UX_SYSTEM_HOST ux_system_host; +static UX_HCD hcd; +static int count = 0; +static UINT entry_function(struct UX_HCD_STRUCT *parm1, UINT parm2, VOID *parm3) +{ + UX_TRANSFER *t_request; + UCHAR *data; + + + t_request = (UX_TRANSFER*)parm3; + data = t_request -> ux_transfer_request_data_pointer; + if(count == 0) + data[2] = 1; + else if(count == 1) + data[2] = 9; + + count++; + + return(UX_SUCCESS); +} + +#define UX_MEMORY_BUFFER_SIZE 4096 + +static UCHAR memory_buffer[UX_MEMORY_BUFFER_SIZE]; +static UCHAR cache_safe_memory_buffer[UX_MEMORY_BUFFER_SIZE]; + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_hub_descriptor_get_coverage_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status = 0; +UX_ENDPOINT *control_endpoint; + + + /* Inform user. */ + printf("Running USB host Class Hub Descriptor Get Coverage Test ............ "); + + ux_system_initialize(memory_buffer, UX_MEMORY_BUFFER_SIZE, cache_safe_memory_buffer, UX_MEMORY_BUFFER_SIZE); + + _ux_system_host = &ux_system_host; + ux_system_host.ux_system_host_hcd_array = &hcd; + + + hub.ux_host_class_hub_device = &hub_device; + control_endpoint = &hub_device.ux_device_control_endpoint; + control_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_actual_length = UX_HUB_DESCRIPTOR_LENGTH; + hub.ux_host_class_hub_device->ux_device_descriptor.bDeviceProtocol = UX_HOST_CLASS_HUB_PROTOCOL_MULTIPLE_TT; + hub.ux_host_class_hub_interface = &hub_interface; + hub_interface.ux_interface_descriptor.bInterfaceProtocol = UX_HOST_CLASS_HUB_PROTOCOL_MULTIPLE_TT; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + transfer_request -> ux_transfer_request_endpoint = &transfer_request_endpoint; + transfer_request_endpoint.ux_endpoint_device = &device; + device.ux_device_state = UX_DEVICE_ATTACHED; +#if UX_MAX_HCD > 1 + device.ux_device_hcd = &hcd; +#endif + transfer_request_endpoint.ux_endpoint_descriptor.bEndpointAddress = 0x70; + /* Test to cover line 177 */ + hcd.ux_hcd_entry_function = entry_function; + + _ux_host_class_hub_descriptor_get(&hub); + + /* Test again to cover line 181 */ + _ux_host_class_hub_descriptor_get(&hub); + + + printf(" Passed\n"); + test_control_return(0); + return; +} diff --git a/test/regression/usbx_ux_host_class_hub_entry_test.c b/test/regression/usbx_ux_host_class_hub_entry_test.c new file mode 100644 index 00000000..db59daa0 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hub_entry_test.c @@ -0,0 +1,35 @@ +/* This tests the ux_host_class_hub_entry.c API. */ + +#include "usbx_ux_test_hub.h" + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_hub_entry_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running ux_host_class_hub_entry Test................................ "); + + stepinfo("\n"); + + initialize_hub(first_unused_memory); +} + +static void post_init_host() +{ + +UX_HOST_CLASS_COMMAND command; + + /** Test unknown function. **/ + + command.ux_host_class_command_request = (~0); + + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_FUNCTION_NOT_SUPPORTED)); + UX_TEST_ASSERT(_ux_host_class_hub_entry(&command) != UX_SUCCESS); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_ux_host_class_hub_status_get_test.c b/test/regression/usbx_ux_host_class_hub_status_get_test.c new file mode 100644 index 00000000..5da0a4d2 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hub_status_get_test.c @@ -0,0 +1,57 @@ +/* This tests the ux_host_class_hub_status_get.c API. */ + +#include "usbx_ux_test_hub.h" + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_hub_status_get_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running ux_host_class_hub_status_get Test........................... "); + + stepinfo("\n"); + + initialize_hub(first_unused_memory); +} + +static void post_init_host() +{ + +USHORT port_status; +USHORT port_change; + + /** Test sending request to port 0 (hub itself). **/ + + /* Make get port status action for returning immediately. */ + + UX_TEST_SETUP get_port_status_setup = {0}; + get_port_status_setup.ux_test_setup_request = UX_HOST_CLASS_HUB_GET_STATUS; + get_port_status_setup.ux_test_setup_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_DEVICE; + get_port_status_setup.ux_test_setup_index = 0; + + UX_TEST_ACTION get_port_status_match_action = {0}; + get_port_status_match_action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY; + get_port_status_match_action.function = UX_HCD_TRANSFER_REQUEST; + get_port_status_match_action.req_action = UX_TEST_SETUP_MATCH_REQUEST | UX_TEST_SETUP_MATCH_INDEX; + get_port_status_match_action.req_setup = &get_port_status_setup; + get_port_status_match_action.no_return = 1; + + ux_test_add_action_to_main_list(get_port_status_match_action); + + UX_TEST_CHECK_SUCCESS(_ux_host_class_hub_status_get(g_hub_host, 0, &port_status, &port_change)); + + UX_TEST_ASSERT(ux_test_check_actions_empty() == UX_TRUE); + + /** Test memory allocation failure. **/ + + ux_test_utility_sim_mem_allocate_until_flagged(0, UX_REGULAR_MEMORY); + ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_UTILITY, UX_MEMORY_INSUFFICIENT)); + UX_TEST_CHECK_NOT_SUCCESS(_ux_host_class_hub_status_get(g_hub_host, 0, &port_status, &port_change)); +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_ux_host_class_hub_transfer_request_completed_test.c b/test/regression/usbx_ux_host_class_hub_transfer_request_completed_test.c new file mode 100644 index 00000000..f0ed89e5 --- /dev/null +++ b/test/regression/usbx_ux_host_class_hub_transfer_request_completed_test.c @@ -0,0 +1,64 @@ +/* This tests the ux_host_class_hub_transfer_request_completed.c API. */ + +#include "usbx_ux_test_hub.h" + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_hub_transfer_request_completed_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running ux_host_class_hub_status_get Test........................... "); + + stepinfo("\n"); + + initialize_hub(first_unused_memory); +} + +static void post_init_host() +{ + +UX_TRANSFER transfer; +UX_TRANSFER *actual_interrupt_transfer; +UX_HOST_CLASS_HUB hub; + + transfer.ux_transfer_request_class_instance = (VOID *)&hub; + + /** Test class in shutdown. **/ + hub.ux_host_class_hub_state = UX_HOST_CLASS_INSTANCE_SHUTDOWN; + _ux_host_class_hub_transfer_request_completed(&transfer); + + /** Test aborted transfer. **/ + hub.ux_host_class_hub_state = UX_HOST_CLASS_INSTANCE_LIVE; + transfer.ux_transfer_request_completion_code = UX_TRANSFER_STATUS_ABORT; + _ux_host_class_hub_transfer_request_completed(&transfer); + + /** Test no answer from transfer. **/ + hub.ux_host_class_hub_state = UX_HOST_CLASS_INSTANCE_LIVE; + transfer.ux_transfer_request_completion_code = UX_TRANSFER_NO_ANSWER; + _ux_host_class_hub_transfer_request_completed(&transfer); + + /** Test completion code that triggers interrupt transfer reactivation. **/ + + actual_interrupt_transfer = &g_hub_host->ux_host_class_hub_interrupt_endpoint->ux_endpoint_transfer_request; + actual_interrupt_transfer->ux_transfer_request_completion_code = UX_TRANSFER_STALLED; + + /* First, abort current transfer. */ + ux_host_stack_transfer_request_abort(actual_interrupt_transfer); + + /* Now call it. */ + _ux_host_class_hub_transfer_request_completed(actual_interrupt_transfer); + +#if UX_MAX_DEVICES > 1 + /* Make sure the interrupt EP still works. */ + connect_device_to_hub(); + + class_dpump_get(); +#endif +} + +static void post_init_device() +{ +} \ No newline at end of file diff --git a/test/regression/usbx_ux_host_class_printer_basic_tests.c b/test/regression/usbx_ux_host_class_printer_basic_tests.c new file mode 100644 index 00000000..322fb862 --- /dev/null +++ b/test/regression/usbx_ux_host_class_printer_basic_tests.c @@ -0,0 +1,870 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_dummy_printer.h" +#include "ux_device_stack.h" +#include "ux_host_class_printer.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); + +static TX_THREAD tx_test_thread_printer_read; +static TX_THREAD tx_test_thread_printer_write; +static TX_SEMAPHORE tx_test_semaphore_printer_trigger; +static VOID tx_test_printer_read_entry(ULONG); +static VOID tx_test_printer_write_entry(ULONG); + +static VOID ux_test_hcd_entry_should_not_be_called(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_disconnect(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +static UX_DEVICE *device = UX_NULL; +static UX_HOST_CLASS_PRINTER *host_printer = UX_NULL; +static UCHAR host_buffer[UX_DEMO_BUFFER_SIZE * 8]; + +static ULONG enum_counter; + +static ULONG error_counter; +static ULONG error_callback_counter; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_on_set_cfg; +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_enum_mem_alloc_count; + +static ULONG rsc_test_sem_usage; +static ULONG rsc_test_sem_get_count; +static ULONG rsc_test_mutex_usage; +static ULONG rsc_test_mem_alloc_count; + +static UX_DEVICE_CLASS_PRINTER *device_printer = UX_NULL; +static UX_DEVICE_CLASS_PRINTER_PARAMS device_printer_parameter; +static UCHAR device_buffer[UX_DEMO_BUFFER_SIZE * 8]; +static ULONG device_buffer_length = 0; + +/* Device printer device ID. */ +static UCHAR printer_device_id[] = + { + "MFG:Generic;" // manufacturer (case sensitive) + "MDL:Generic_/_Text_Only;" // model (case sensitive) + "CMD:1284.4;" // PDL command set + "CLS:PRINTER;" // class + "DES:Generic text only printer;" // description + }; + +/* Define device framework. */ + +#define _W0(w) ( (w) & 0xFF) +#define _W1(w) (((w) >> 8) & 0xFF) + +#define _CONFIGURATION_DESCRIPTOR(total_len, n_ifc, cfg_val) \ + 0x09, 0x02, _W0(total_len), _W1(total_len), (n_ifc), (cfg_val), \ + 0x00, 0xc0, 0x32, + +#define _INTERFACE_DESCRIPTOR(ifc_n, alt, n_ep, cls, sub, protocol) \ + 0x09, 0x04, (ifc_n), (alt), (n_ep), (cls), (sub), (protocol), 0x00, + +#define _ENDPOINT_DESCRIPTOR(addr, attr, pktsize, interval) \ + 0x07, 0x05, (addr), (attr), _W0(pktsize), _W1(pktsize), (interval), + +#define _CFG_TOTAL_LEN (9+9+7+7) + +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0xEF bDeviceClass: Composite class code + 0x02 bDeviceSubclass: class sub code + 0x00 bDeviceProtocol: Device protocol + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0x00, 0x00, 0x00, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 0x03, + 0x01, + + _CONFIGURATION_DESCRIPTOR(_CFG_TOTAL_LEN, 1, 1) + _INTERFACE_DESCRIPTOR(0, 0, 2, 0x07, 0x01, 0x02) + _ENDPOINT_DESCRIPTOR(0x01, 0x02, 64, 0x00) + _ENDPOINT_DESCRIPTOR(0x82, 0x02, 64, 0x00) +}; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_full_speed) +#define device_framework_high_speed device_framework_full_speed + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "AzureRTOS" */ + 0x09, 0x04, 0x01, 9, + 'A','z','u','r','e','R','T','O','S', + + /* Product string descriptor : Index 2 - "Printer device" */ + 0x09, 0x04, 0x02, 14, + 'P','r','i','n','t','e','r',' ','d','e','v','i','c','e', + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; + +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +/* Test interactions */ + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT test_slave_change_function(ULONG change) +{ + return 0; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_PRINTER *printer_inst = (UX_HOST_CLASS_PRINTER *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + host_printer = printer_inst; + break; + + case UX_DEVICE_REMOVAL: + if (host_printer == printer_inst) + host_printer = UX_NULL; + break; + + case UX_DEVICE_CONNECTION: + device = (UX_DEVICE *)inst; + break; + + case UX_DEVICE_DISCONNECTION: + if ((VOID *)device == inst) + device = UX_NULL; + break; + +#if defined(UX_HOST_STANDALONE) + case UX_STANDALONE_WAIT_BACKGROUND_TASK: + tx_thread_relinquish(); + break; +#endif + + default: + break; + } + return 0; +} + +static VOID test_printer_instance_activate(VOID *dummy_instance) +{ + if (device_printer == UX_NULL) + device_printer = (UX_DEVICE_CLASS_PRINTER *)dummy_instance; +} +static VOID test_printer_instance_deactivate(VOID *dummy_instance) +{ + if ((VOID*)device_printer == dummy_instance) + device_printer = UX_NULL; +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + error_callback_counter ++; +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = _ux_system->ux_system_regular_memory_pool_free; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_enum_sem_get_count = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_host_class_printer_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + printf("Running Host Class Printer Basic Functionality Test................. "); +#if defined(UX_DEVICE_STANDALONE) + printf("Skip\n"); + test_control_return(0); +#endif + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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(); + + /* Initialize the free memory pointer */ + stack_pointer = (CHAR *) usbx_memory; + memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 4); + + /* 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 #1\n"); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + if (status != UX_SUCCESS) + { + + printf(" ERROR #2\n"); + test_control_return(1); + } + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_printer_name, ux_host_class_printer_entry); + if (status != UX_SUCCESS) + { + + printf(" ERROR #3\n"); + 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, + test_slave_change_function); + if(status!=UX_SUCCESS) + { + + printf(" ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a printer device. */ + _ux_utility_memory_set(&device_printer_parameter, 0, sizeof(device_printer_parameter)); + device_printer_parameter.device_id = printer_device_id; + device_printer_parameter.device_id_length = sizeof(printer_device_id); + device_printer_parameter.instance_activate = test_printer_instance_activate; + device_printer_parameter.instance_deactivate = test_printer_instance_deactivate; + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_device_class_printer_name, + _ux_device_class_printer_entry, + 1, 0, &device_printer_parameter); + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #8\n"); + 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 #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #9\n"); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + stack_pointer += UX_DEMO_STACK_SIZE; + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #10\n"); + test_control_return(1); + } + + /* Create the device printer read thread. */ + stack_pointer += UX_DEMO_STACK_SIZE; + status = tx_thread_create(&tx_test_thread_printer_read, "tx test printer read", + tx_test_printer_read_entry, UX_TRUE, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the device printer write thread. */ + stack_pointer += UX_DEMO_STACK_SIZE; + status = tx_thread_create(&tx_test_thread_printer_write, "tx test printer write", + tx_test_printer_write_entry, UX_FALSE, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the device printer write trigger. */ + status = tx_semaphore_create(&tx_test_semaphore_printer_trigger, + "tx test printer trigger", + 0); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +static UINT _test_check_host_connection_error(VOID) +{ + if (device_printer && host_printer) + return(UX_SUCCESS); + if (error_callback_counter >= 3) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_connection_success(VOID) +{ + if (device_printer && host_printer) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static UINT _test_check_host_disconnection_success(VOID) +{ + if (device_printer == UX_NULL && host_printer == UX_NULL) + return(UX_SUCCESS); + return(UX_ERROR); +} + +static VOID _printer_enumeration_test(VOID) +{ +UINT status; +ULONG mem_free; +ULONG test_n; + + stepinfo(">>>>>>>>>>>> Enumeration information collection\n"); + { + + /* Test disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check connection. */ + status = ux_test_sleep_break_on_success(100, _test_check_host_disconnection_success); + UX_TEST_ASSERT(status == UX_SUCCESS); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_count_reset(); + ux_test_utility_sim_mutex_create_count_reset(); + ux_test_utility_sim_sem_create_count_reset(); + ux_test_utility_sim_sem_get_count_reset(); + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + + /* Save free memory usage. */ + mem_free = _ux_system->ux_system_regular_memory_pool_free; + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Check connection. */ + status = ux_test_sleep_break_on_success(100, _test_check_host_connection_success); + UX_TEST_ASSERT(status == UX_SUCCESS); + + /* Log create counts for further tests. */ + rsc_enum_mutex_usage = rsc_mutex_on_set_cfg; + rsc_enum_sem_usage = rsc_sem_on_set_cfg; + rsc_enum_mem_alloc_count = rsc_mem_alloc_cnt_on_set_cfg; + /* Log create counts when instances active for further tests. */ + rsc_test_mutex_usage = ux_test_utility_sim_mutex_create_count() - rsc_enum_mutex_usage; + rsc_test_sem_usage = ux_test_utility_sim_sem_create_count() - rsc_enum_sem_usage; + rsc_test_mem_alloc_count = ux_test_utility_sim_mem_alloc_count() - rsc_enum_mem_alloc_count; + + /* Lock log base for tests. */ + ux_test_utility_sim_mem_alloc_log_lock(); + + stepinfo("enum mem: %ld\n", rsc_enum_mem_alloc_count); + stepinfo("test mem : %ld\n", rsc_test_mem_alloc_count); + stepinfo("mem free: %ld, %ld\n", _ux_system->ux_system_regular_memory_pool_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available); + } + + stepinfo(">>>>>>>>>>>> Enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < 3; test_n++) + { + stepinfo("%4ld / 2\n", test_n); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check */ + status = ux_test_sleep_break_on_success(100, _test_check_host_disconnection_success); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d.%ld: Disconnect fail\n", __LINE__, test_n); + test_control_return(1); + } + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system->ux_system_regular_memory_pool_free; + else if (mem_free != _ux_system->ux_system_regular_memory_pool_free) + { + + printf("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system->ux_system_regular_memory_pool_free); + test_control_return(1); + } + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Wait and break on error. */ + error_callback_counter = 0; + status = ux_test_sleep_break_on_success(100, _test_check_host_connection_error); + + /* Check */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d.%ld: Enumeration fail\n", __LINE__, test_n); + test_control_return(1); + } + } + stepinfo("\n"); + + if (rsc_test_mem_alloc_count) stepinfo(">>>>>>>>>>>> Memory errors enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_test_mem_alloc_count; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_test_mem_alloc_count - 1); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check */ + status = ux_test_sleep_break_on_success(100, _test_check_host_disconnection_success); + if (status != UX_SUCCESS) + { + + stepinfo("ERROR #%d.%ld: Disconnect fail\n", __LINE__, test_n); + test_control_return(1); + } + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system->ux_system_regular_memory_pool_free; + else if (mem_free != _ux_system->ux_system_regular_memory_pool_free) + { + + stepinfo("ERROR #%d.%ld: Memory level different after re-enumerations %ld <> %ld\n", __LINE__, test_n, mem_free, _ux_system->ux_system_regular_memory_pool_free); + test_control_return(1); + } + + /* Set memory error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n + rsc_enum_mem_alloc_count); + + /* Connect. */ + error_callback_counter = 0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait and break on errors. */ + status = ux_test_sleep_break_on_success(100, _test_check_host_connection_error); + + /* Check error */ + if (status != UX_SUCCESS) + { + + /* Check error trap. */ + if (error_callback_counter == 0) + { + stepinfo("ERROR #%d.%ld: device detected when there is memory error\n", __LINE__, test_n); + test_control_return(1); + } + } + stepinfo("mem free: %ld\n", _ux_system->ux_system_regular_memory_pool_free); + } + ux_test_utility_sim_mem_alloc_error_generation_stop(); + if (rsc_test_mem_alloc_count) stepinfo("\n"); + + /* If device disconnected, re-connect. */ + if (_test_check_host_connection_success() != UX_SUCCESS) + { + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Check */ + status = ux_test_sleep_break_on_success(100, _test_check_host_connection_success); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: Enumeration fail\n", __LINE__); + test_control_return(1); + } + } +} +static VOID _printer_requests_test(VOID) +{ +UINT status; +ULONG printer_port_status; + + stepinfo(">>>>>>>>>>>>>>>> Test GET_DEVICE_ID\n"); + status = ux_host_class_printer_device_id_get(host_printer, host_buffer, sizeof(host_buffer)); + UX_TEST_ASSERT(status == UX_SUCCESS); + + stepinfo(">>>>>>>>>>>>>>>> Test GET_PORT_STATUS\n"); + device_printer->port_status = 0x73; + status = ux_host_class_printer_status_get(host_printer, &printer_port_status); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(printer_port_status == 0x73); + + stepinfo(">>>>>>>>>>>>>>>> Test SOFT_RESET\n"); + device_printer->soft_reset = 0; + status = ux_host_class_printer_soft_reset(host_printer); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(device_printer->soft_reset != 0); +} + +void tx_test_printer_read_entry(ULONG arg) +{ +UINT status; +UX_SLAVE_TRANSFER *transfer; +ULONG save_length; + while(1) + { + if (device_printer == UX_NULL || + device_printer->bulk_out_endpoint == UX_NULL) + { + tx_thread_sleep(10); + continue; + } + transfer = &device_printer->bulk_out_endpoint->ux_slave_endpoint_transfer_request; + transfer->ux_slave_transfer_request_timeout=UX_WAIT_FOREVER; + status = ux_device_stack_transfer_request(transfer, + UX_SLAVE_REQUEST_DATA_MAX_LENGTH, + UX_SLAVE_REQUEST_DATA_MAX_LENGTH); + if (status != UX_SUCCESS) + { + tx_thread_sleep(1); + continue; + } + save_length = transfer->ux_slave_transfer_request_actual_length; + if (save_length) + { + if (device_buffer_length >= sizeof(device_buffer)) + { + /* Discard data. */ + continue; + } + /* Save data. */ + if (device_buffer_length + save_length > sizeof(device_buffer)) + save_length = sizeof(device_buffer) - device_buffer_length; + ux_utility_memory_copy(device_buffer + device_buffer_length, + transfer->ux_slave_transfer_request_data_pointer, + save_length); + device_buffer_length += save_length; + } + } +} + +void tx_test_printer_write_entry(ULONG arg) +{ +UINT status; +UX_SLAVE_TRANSFER *transfer; +ULONG send_length; +ULONG send_total; + while(1) + { + /* Wait a trigger. */ + status = tx_semaphore_get(&tx_test_semaphore_printer_trigger, TX_WAIT_FOREVER); + if (status != TX_SUCCESS) + { + tx_thread_sleep(10); + continue; + } + /* Send device_buffer_length. */ + send_total = 0; + while (device_printer != UX_NULL && + device_printer->bulk_in_endpoint != UX_NULL) + { + /* All sent. */ + if (send_total >= device_buffer_length) + break; + transfer = &device_printer->bulk_in_endpoint->ux_slave_endpoint_transfer_request; + send_length = device_buffer_length - send_total; + if (send_length >= UX_SLAVE_REQUEST_DATA_MAX_LENGTH) + send_length = UX_SLAVE_REQUEST_DATA_MAX_LENGTH; + ux_utility_memory_copy(transfer->ux_slave_transfer_request_data_pointer, + device_buffer + send_total, send_length); + status = ux_device_stack_transfer_request(transfer, send_length, send_length); + if (status != UX_SUCCESS) + break; + send_total += send_length; + } + } +} + +static VOID _printer_read_write_test(VOID) +{ +struct _TEST_DEF { + ULONG fill; + ULONG length; + ULONG zlp; +} tests[] = { + {0x5A, 1, 0}, + {0x7E, 512, 1}, + {0xC2, 513, 0}, + {0x4C, UX_SLAVE_REQUEST_DATA_MAX_LENGTH, 0}, + {0xA5, UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1, 0}, + {0x3C, sizeof(device_buffer), 0}, + {0xC4, sizeof(device_buffer) - 1, 0}, +}; +#define _TEST_N (sizeof(tests)/sizeof(struct _TEST_DEF)) +INT i; +ULONG actual_length; +UINT status; + for(i = 0; i < _TEST_N; i ++) + { + stepinfo(">>>>>>>>>>>>>>>> Test Write %ld\n", tests[i].length); + device_buffer_length = 0; + ux_utility_memory_set(device_buffer, ~tests[i].fill, tests[i].length); + ux_utility_memory_set(host_buffer, tests[i].fill, tests[i].length); + status = ux_host_class_printer_write(host_printer, host_buffer, tests[i].length, &actual_length); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(tests[i].length == actual_length); + if (tests[i].zlp) + { + status = ux_host_class_printer_write(host_printer, host_buffer, 0, &actual_length); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(0 == actual_length); + } + UX_TEST_ASSERT(device_buffer_length == tests[i].length); + status = ux_utility_memory_compare(device_buffer, host_buffer, tests[i].length); + UX_TEST_ASSERT(status == UX_SUCCESS); + + stepinfo(">>>>>>>>>>>>>>>> Test Read %ld\n", tests[i].length); + status = tx_semaphore_put(&tx_test_semaphore_printer_trigger); + UX_TEST_ASSERT(status == TX_SUCCESS); + ux_utility_memory_set(host_buffer, ~tests[i].fill, tests[i].length); + status = ux_host_class_printer_read(host_printer, host_buffer, tests[i].length, &actual_length); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(tests[i].length == actual_length); + UX_TEST_ASSERT(host_buffer[0] == tests[i].fill); + UX_TEST_ASSERT(host_buffer[tests[i].length - 1] == tests[i].fill); + + } +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +ULONG mem_free; +ULONG loop; +ULONG parameter_u32[64/4]; +USHORT *parameter_u16 = (USHORT*)parameter_u32; +UCHAR *parameter_u8 = (UCHAR*)parameter_u32; + + + stepinfo("\n"); + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + status = ux_test_sleep_break_on_success(100, _test_check_host_connection_success); + UX_TEST_ASSERT(status == UX_SUCCESS); + + _printer_enumeration_test(); + _printer_requests_test(); + _printer_read_write_test(); + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + if (host_printer != UX_NULL) + { + + printf("ERROR #13: instance not removed when disconnect"); + test_control_return(1); + } + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_device_class_printer_name, _ux_device_class_printer_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); + tx_thread_relinquish(); +#else + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); +#endif + } +} diff --git a/test/regression/usbx_ux_host_class_storage_activate_test.c b/test/regression/usbx_ux_host_class_storage_activate_test.c new file mode 100644 index 00000000..e416d0ce --- /dev/null +++ b/test/regression/usbx_ux_host_class_storage_activate_test.c @@ -0,0 +1,657 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static CHAR ram_disk_flush = 0; +static UINT ram_disk_flush_status = UX_SUCCESS; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + +static UX_TEST_SETUP _GetMaxLun = UX_TEST_SETUP_STORAGE_GetMaxLun; + +static UX_TEST_HCD_SIM_ACTION stall_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_TRANSFER_STALLED, + UX_TRANSFER_STALLED, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION length_error_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 2, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION replaced_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_storage_activate_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_storage_activate Test......................... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_parameter); + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + // status = _ux_test_dcd_sim_slave_initialize(); + status = ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + // 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 #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +UX_HOST_CLASS_COMMAND command; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done. */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_activate - configure - configuration_get FAIL\n"); + + configuration = device -> ux_device_first_configuration; + interface = configuration -> ux_configuration_first_interface; + + device -> ux_device_handle = 0; + device -> ux_device_state = UX_DEVICE_ADDRESSED; + + command.ux_host_class_command_container = (VOID *)interface; + command.ux_host_class_command_class_ptr = (VOID *)class; + + status = _ux_host_class_storage_activate(&command); + if (status != UX_CONFIGURATION_HANDLE_UNKNOWN) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + device -> ux_device_handle = (ULONG)(ALIGN_TYPE)device; + device -> ux_device_state = UX_DEVICE_CONFIGURED; + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_activate - semaphore - semaphore create FAIL\n"); + + ux_test_utility_sim_sem_create_count_reset(); + ux_test_utility_sim_sem_error_generation_start(0); + + configuration = device -> ux_device_first_configuration; + interface = configuration -> ux_configuration_first_interface; + + command.ux_host_class_command_container = (VOID *)interface; + command.ux_host_class_command_class_ptr = (VOID *)class; + + status = _ux_host_class_storage_activate(&command); + if (status != UX_SEMAPHORE_ERROR) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + device -> ux_device_handle = (ULONG)(ALIGN_TYPE)device; + device -> ux_device_state = UX_DEVICE_CONFIGURED; + + ux_test_utility_sim_sem_error_generation_stop(); + + /* Wait a while so the thread goes. */ + _ux_utility_delay_ms(10); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)number_blocks; + (void)lba; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + 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_storage_configure_coverage_test.c b/test/regression/usbx_ux_host_class_storage_configure_coverage_test.c new file mode 100644 index 00000000..7c57b30f --- /dev/null +++ b/test/regression/usbx_ux_host_class_storage_configure_coverage_test.c @@ -0,0 +1,40 @@ +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" +#include "ux_test.h" +#include "ux_test_utility_sim.h" +#include "ux_host_class_storage.h" + +static UX_SYSTEM ux_system; +static UX_CONFIGURATION storage_configuration; +static UX_DEVICE device; + +static UX_HOST_CLASS_STORAGE storage; +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_storage_configure_overage_test_application_define(void *first_unused_memory) +#endif +{ + + /* Inform user. */ + printf("Running USB host Class Storage Configure Coverage Test ............. "); + + _ux_system = &ux_system; + storage.ux_host_class_storage_device = &device; + device.ux_device_state = UX_DEVICE_RESET; + device.ux_device_handle = (ULONG)&device; + device.ux_device_first_configuration = &storage_configuration; + device.ux_device_power_source = UX_DEVICE_SELF_POWERED; + storage_configuration.ux_configuration_handle = 0; + + _ux_host_class_storage_configure(&storage); + + printf(" Passed\n"); + + test_control_return(0); + return; +} diff --git a/test/regression/usbx_ux_host_class_storage_configure_test.c b/test/regression/usbx_ux_host_class_storage_configure_test.c new file mode 100644 index 00000000..00f433e2 --- /dev/null +++ b/test/regression/usbx_ux_host_class_storage_configure_test.c @@ -0,0 +1,692 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static CHAR ram_disk_flush = 0; +static UINT ram_disk_flush_status = UX_SUCCESS; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + +static UX_TEST_SETUP _GetMaxLun = UX_TEST_SETUP_STORAGE_GetMaxLun; + +static UX_TEST_HCD_SIM_ACTION stall_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_TRANSFER_STALLED, + UX_TRANSFER_STALLED, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION length_error_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 2, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION replaced_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_storage_configure_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_storage_configure Test........................ "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_parameter); + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + // status = _ux_test_dcd_sim_slave_initialize(); + status = ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + // 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 #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +UX_DEVICE parent_device; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done. */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + stepinfo(">>>>>>>>>>>>>>> ux_host_stack_device_configuration_reset\n"); + status = _ux_host_stack_device_configuration_reset(device); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_configure - SUCCESS\n"); + status = _ux_host_class_storage_configure(storage); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_configure - configuration_get FAIL\n"); + status = _ux_host_stack_device_configuration_reset(device); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + device -> ux_device_handle = 0; + status = _ux_host_class_storage_configure(storage); + if (status != UX_CONFIGURATION_HANDLE_UNKNOWN) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + device -> ux_device_handle = (ULONG)(ALIGN_TYPE)device; +#if UX_MAX_DEVICES > 1 + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_configure - BUS_POWERED parent and me\n"); + parent_device.ux_device_power_source = UX_DEVICE_BUS_POWERED; + device -> ux_device_power_source = UX_DEVICE_BUS_POWERED; + device -> ux_device_parent = &parent_device; + status = _ux_host_class_storage_configure(storage); + if (status != UX_CONNECTION_INCOMPATIBLE) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } +#endif + parent_device.ux_device_power_source = UX_DEVICE_SELF_POWERED; + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_configure - configuration_select FAIL\n"); + configuration = device -> ux_device_first_configuration; + configuration -> ux_configuration_handle = 0; + + status = _ux_host_class_storage_configure(storage); + if (status != UX_CONFIGURATION_HANDLE_UNKNOWN) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + UX_DEVICE_PARENT_SET(device, UX_NULL); + status = _ux_host_class_storage_configure(storage); + if (status != UX_CONFIGURATION_HANDLE_UNKNOWN) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + configuration -> ux_configuration_handle = (ULONG)(ALIGN_TYPE)configuration; + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_configure - interface_get FAIL\n"); + interface = configuration -> ux_configuration_first_interface; + configuration -> ux_configuration_first_interface = UX_NULL; + + status = _ux_host_class_storage_configure(storage); + if (status != UX_INTERFACE_HANDLE_UNKNOWN) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + configuration -> ux_configuration_first_interface = interface; + + /* Wait a while so the thread goes. */ + _ux_utility_delay_ms(10); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)number_blocks; + (void)lba; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + 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_storage_device_initialize_test.c b/test/regression/usbx_ux_host_class_storage_device_initialize_test.c new file mode 100644 index 00000000..bc9c3a21 --- /dev/null +++ b/test/regression/usbx_ux_host_class_storage_device_initialize_test.c @@ -0,0 +1,664 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static CHAR ram_disk_flush = 0; +static UINT ram_disk_flush_status = UX_SUCCESS; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + +static UX_TEST_SETUP _GetMaxLun = UX_TEST_SETUP_STORAGE_GetMaxLun; + +static UX_TEST_HCD_SIM_ACTION stall_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_TRANSFER_STALLED, + UX_TRANSFER_STALLED, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION length_error_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 2, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION replaced_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_storage_device_initialize_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_storage_device_initialize Test................ "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 2; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_parameter); + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + // status = _ux_test_dcd_sim_slave_initialize(); + status = ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + // 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 #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +UX_SLAVE_DEVICE *slave_device; +UX_SLAVE_CLASS *slave_class; +UX_SLAVE_CLASS_STORAGE *slave_storage; +ULONG temp; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done (). */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + configuration = device -> ux_device_first_configuration; + interface = configuration -> ux_configuration_first_interface; +#if 0 // [CQ: moved to _activate 202308] + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_device_initialize - support_check - Protocol FAIL\n"); + + temp = storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceProtocol; + storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceProtocol = 0xAA; + + status = _ux_host_class_storage_device_initialize(storage); + if (status != UX_HOST_CLASS_PROTOCOL_ERROR) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceProtocol = temp; +#endif + + slave_device = &_ux_system_slave->ux_system_slave_device; + slave_class = _ux_system_slave->ux_system_slave_interface_class_array[0]; + slave_storage = (UX_SLAVE_CLASS_STORAGE *)slave_class->ux_slave_class_instance; + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_device_initialize - media_type CDROM SUCCESS/NOT SUPPORTED\n"); + + temp = slave_storage -> ux_slave_class_storage_lun[0].ux_slave_class_storage_media_type; + slave_storage -> ux_slave_class_storage_lun[0].ux_slave_class_storage_media_type = UX_SLAVE_CLASS_STORAGE_MEDIA_CDROM; + slave_storage -> ux_slave_class_storage_lun[1].ux_slave_class_storage_media_type = 0xF3; + + status = _ux_host_class_storage_device_initialize(storage); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_device_initialize - media_type Unsupported\n"); + + slave_storage -> ux_slave_class_storage_lun[0].ux_slave_class_storage_media_type = UX_SLAVE_CLASS_STORAGE_MEDIA_CDROM; + + status = _ux_host_class_storage_device_initialize(storage); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + slave_storage -> ux_slave_class_storage_lun[0].ux_slave_class_storage_media_type = temp; + + /* Wait a while so the thread goes. */ + _ux_utility_delay_ms(10); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)number_blocks; + (void)lba; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + 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_storage_device_support_check_test.c b/test/regression/usbx_ux_host_class_storage_device_support_check_test.c new file mode 100644 index 00000000..8126c0e8 --- /dev/null +++ b/test/regression/usbx_ux_host_class_storage_device_support_check_test.c @@ -0,0 +1,644 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static CHAR ram_disk_flush = 0; +static UINT ram_disk_flush_status = UX_SUCCESS; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + +static UX_TEST_SETUP _GetMaxLun = UX_TEST_SETUP_STORAGE_GetMaxLun; + +static UX_TEST_HCD_SIM_ACTION stall_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_TRANSFER_STALLED, + UX_TRANSFER_STALLED, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION length_error_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 2, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION replaced_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_storage_device_support_check_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_storage_device_support_check Test............. "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_parameter); + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + // status = _ux_test_dcd_sim_slave_initialize(); + status = ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + // 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 #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +ULONG temp; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done. */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + configuration = device -> ux_device_first_configuration; + interface = configuration -> ux_configuration_first_interface; + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_device_support_check - Protocol FAIL\n"); + + temp = storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceProtocol; + storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceProtocol = 0xAA; + + status = _ux_host_class_storage_device_support_check(storage); + if (status != UX_HOST_CLASS_PROTOCOL_ERROR) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceProtocol = temp; + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_device_support_check - SubClass FAIL\n"); + + temp = storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceSubClass; + storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceSubClass = 0xAA; + + status = _ux_host_class_storage_device_support_check(storage); + if (status != UX_HOST_CLASS_PROTOCOL_ERROR) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceSubClass = temp; + + /* Wait a while so the thread goes. */ + _ux_utility_delay_ms(10); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)number_blocks; + (void)lba; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + 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_storage_driver_entry_test.c b/test/regression/usbx_ux_host_class_storage_driver_entry_test.c new file mode 100644 index 00000000..3d681129 --- /dev/null +++ b/test/regression/usbx_ux_host_class_storage_driver_entry_test.c @@ -0,0 +1,789 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; +static UCHAR cbw_buffer[UX_SLAVE_CLASS_STORAGE_CBW_LENGTH]; +static UCHAR csw_buffer[UX_SLAVE_CLASS_STORAGE_CSW_LENGTH]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static UINT ram_disk_read_status = UX_SUCCESS; +static ULONG ram_disk_read_media_status = 0; +static CHAR ram_disk_read_sent = 0; + +static UINT ram_disk_write_status = UX_SUCCESS; +static ULONG ram_disk_write_media_status = 0; +static CHAR ram_disk_write_sent = 0; + +static CHAR ram_disk_flush = 0; +static UINT ram_disk_flush_status = UX_SUCCESS; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + +static UX_TEST_SETUP _GetMaxLun = UX_TEST_SETUP_STORAGE_GetMaxLun; + +static UX_TEST_HCD_SIM_ACTION stall_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_TRANSFER_STALLED, + UX_TRANSFER_STALLED, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION length_error_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 2, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION replaced_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION fail_bulk_out[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_ERROR, + UX_ERROR, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION fail_2nd_bulk_out[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_SUCCESS, + UX_SUCCESS, UX_NULL, + UX_TRUE}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_ERROR, + UX_ERROR, UX_NULL}, +{ 0 } +}; + +static VOID sending_cbw(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UCHAR *cbw = (UCHAR *)storage -> ux_host_class_storage_cbw; +UX_TRANSFER *transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + + + _ux_utility_memory_copy(cbw_buffer, cbw, 31); + + /* Prepare CSW. */ + _ux_utility_memory_copy(csw_buffer + 0, cbw_buffer + 0, 4); /* dCBWSignature -> dCSWSignature */ + _ux_utility_memory_copy(csw_buffer + 4, cbw_buffer + 4, 4); /* dCBWTag -> dCSWTag */ + _ux_utility_memory_set (csw_buffer + 8, 0x00, 4); /* dCSWDataResidue <= 0 */ + _ux_utility_memory_set (csw_buffer + 12, 0x00, 1); /* bCSWStatus <= 0 */ + + _ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); +} + +static VOID getting_data(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TRANSFER *transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + + _ux_utility_long_put(csw_buffer + 8, 1); /* dCSWDataResidue <= 1 for error test */ + _ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); +} + +static VOID getting_csw(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UCHAR *csw = (UCHAR *)storage -> ux_host_class_storage_csw; +UX_TRANSFER *transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + + _ux_utility_memory_copy(csw, csw_buffer, 13); + _ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); +} + +static UX_TEST_HCD_SIM_ACTION replace_cbw_data_csw[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 31, UX_SUCCESS, + UX_SUCCESS, + .action_func = sending_cbw, + .no_return = UX_FALSE, + .do_after = UX_FALSE}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP | UX_TEST_SIM_REQ_ANSWER, 0x81, buffer, 63, UX_SUCCESS, + UX_SUCCESS, + .action_func = getting_data, + .no_return = UX_FALSE, + .do_after = UX_FALSE}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP | UX_TEST_SIM_REQ_ANSWER, 0x81, csw_buffer, 13, UX_SUCCESS, + UX_SUCCESS, + .action_func = getting_csw, + .no_return = UX_FALSE, + .do_after = UX_FALSE}, +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_storage_driver_entry_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_storage_driver_entry Test..................... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 2; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_parameter); + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + // status = _ux_test_dcd_sim_slave_initialize(); + status = ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + // 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 #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} +#endif + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +FX_MEDIA *media; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + media = &storage_media->ux_host_class_storage_media; + + /* Confirm media enum done (). */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + configuration = device -> ux_device_first_configuration; + interface = configuration -> ux_configuration_first_interface; + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_driver_entry - FX_DRIVER_INIT SUCCESS\n"); + media->fx_media_driver_request = FX_DRIVER_INIT; + storage -> ux_host_class_storage_write_protected_media = UX_TRUE; + _ux_host_class_storage_driver_entry(media); + status = media->fx_media_driver_status; + if (status != FX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_driver_entry - FX_DRIVER_WRITE ERROR\n"); + ram_disk_write_status = UX_ERROR; + ram_disk_write_media_status = 0x003A02; + media->fx_media_driver_request = FX_DRIVER_WRITE; + media->fx_media_driver_logical_sector = 0; + media->fx_media_driver_sectors = 1; + media->fx_media_driver_buffer = buffer; + _ux_host_class_storage_driver_entry(media); + status = media->fx_media_driver_status; + if (status == FX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + ram_disk_write_status = 0; + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_driver_entry - FX_DRIVER_BOOT_WRITE ERROR\n"); + ram_disk_write_status = UX_ERROR; + ram_disk_write_media_status = 0x003A02; + media->fx_media_driver_request = FX_DRIVER_BOOT_WRITE; + media->fx_media_driver_buffer = buffer; + _ux_host_class_storage_driver_entry(media); + status = media->fx_media_driver_status; + if (status == FX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + ram_disk_write_status = 0; + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_driver_entry - FX_DRIVER_BOOT_WRITE SUCCESS\n"); + media->fx_media_driver_request = FX_DRIVER_BOOT_WRITE; + media->fx_media_driver_buffer = buffer; + _ux_host_class_storage_driver_entry(media); + status = media->fx_media_driver_status; + if (status != FX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } +#endif + + /* Wait a while so the thread goes. */ + _ux_utility_delay_ms(10); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + + if (lun > 1) + return UX_ERROR; + + ram_disk_read_sent = UX_TRUE; + if (ram_disk_read_status != UX_SUCCESS) + { + if (media_status != UX_NULL) + *media_status = ram_disk_read_media_status; + + return ram_disk_read_status; + } + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + + if (lun > 1) + return UX_ERROR; + + ram_disk_write_sent = UX_TRUE; + if (ram_disk_write_status != UX_SUCCESS) + { + if (media_status != UX_NULL) + *media_status = ram_disk_write_media_status; + + return ram_disk_write_status; + } + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)number_blocks; + (void)lba; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + 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_storage_entry_test.c b/test/regression/usbx_ux_host_class_storage_entry_test.c new file mode 100644 index 00000000..a64739f5 --- /dev/null +++ b/test/regression/usbx_ux_host_class_storage_entry_test.c @@ -0,0 +1,827 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; +static UCHAR stack_buffer[UX_HOST_CLASS_STORAGE_THREAD_STACK_SIZE]; +static UCHAR cbw_buffer[UX_SLAVE_CLASS_STORAGE_CBW_LENGTH]; +static UCHAR csw_buffer[UX_SLAVE_CLASS_STORAGE_CSW_LENGTH]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static UINT ram_disk_read_status = UX_SUCCESS; +static ULONG ram_disk_read_media_status = 0; +static CHAR ram_disk_read_sent = 0; + +static UINT ram_disk_write_status = UX_SUCCESS; +static ULONG ram_disk_write_media_status = 0; +static CHAR ram_disk_write_sent = 0; + +static CHAR ram_disk_flush = 0; +static UINT ram_disk_flush_status = UX_SUCCESS; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + +static UX_TEST_SETUP _GetMaxLun = UX_TEST_SETUP_STORAGE_GetMaxLun; + +static UX_TEST_HCD_SIM_ACTION stall_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_TRANSFER_STALLED, + UX_TRANSFER_STALLED, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION length_error_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 2, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION replaced_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION fail_bulk_out[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_ERROR, + UX_ERROR, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION fail_2nd_bulk_out[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_SUCCESS, + UX_SUCCESS, UX_NULL, + UX_TRUE}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_ERROR, + UX_ERROR, UX_NULL}, +{ 0 } +}; + +static VOID sending_cbw(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UCHAR *cbw = (UCHAR *)storage -> ux_host_class_storage_cbw; +UX_TRANSFER *transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + + + _ux_utility_memory_copy(cbw_buffer, cbw, 31); + + /* Prepare CSW. */ + _ux_utility_memory_copy(csw_buffer + 0, cbw_buffer + 0, 4); /* dCBWSignature -> dCSWSignature */ + _ux_utility_memory_copy(csw_buffer + 4, cbw_buffer + 4, 4); /* dCBWTag -> dCSWTag */ + _ux_utility_memory_set (csw_buffer + 8, 0x00, 4); /* dCSWDataResidue <= 0 */ + _ux_utility_memory_set (csw_buffer + 12, 0x00, 1); /* bCSWStatus <= 0 */ + + _ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); +} + +static VOID getting_data(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TRANSFER *transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + + _ux_utility_long_put(csw_buffer + 8, 1); /* dCSWDataResidue <= 1 for error test */ + _ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); +} + +static VOID getting_csw(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UCHAR *csw = (UCHAR *)storage -> ux_host_class_storage_csw; +UX_TRANSFER *transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + + _ux_utility_memory_copy(csw, csw_buffer, 13); + _ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); +} + +static UX_TEST_HCD_SIM_ACTION replace_cbw_data_csw[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 31, UX_SUCCESS, + UX_SUCCESS, + .action_func = sending_cbw, + .no_return = UX_FALSE, + .do_after = UX_FALSE}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP | UX_TEST_SIM_REQ_ANSWER, 0x81, buffer, 63, UX_SUCCESS, + UX_SUCCESS, + .action_func = getting_data, + .no_return = UX_FALSE, + .do_after = UX_FALSE}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP | UX_TEST_SIM_REQ_ANSWER, 0x81, csw_buffer, 13, UX_SUCCESS, + UX_SUCCESS, + .action_func = getting_csw, + .no_return = UX_FALSE, + .do_after = UX_FALSE}, +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_storage_entry_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_storage_entry Test............................ "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 2; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_parameter); + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + // status = _ux_test_dcd_sim_slave_initialize(); + status = ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + // 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 #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_EXT *storage_ext0, *storage_ext1; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +ULONG rfree, cfree; +FX_MEDIA *media; +UX_HOST_CLASS_COMMAND command; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + media = &storage_media->ux_host_class_storage_media; +#endif + + /* Confirm media enum done (). */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + configuration = device -> ux_device_first_configuration; + interface = configuration -> ux_configuration_first_interface; + + /* Disconnect. */ + // Seems there is memory problem if do resource free here???!!! + // _ux_utility_thread_delete(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + // _ux_utility_memory_free(class->ux_host_class_media); + // _ux_utility_memory_free(class->ux_host_class_ext); + class->ux_host_class_media = UX_NULL; + class->ux_host_class_ext = UX_NULL; + + /* Command. */ + command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_ACTIVATE; + command.ux_host_class_command_class_ptr = class; + command.ux_host_class_command_container = interface; + + rfree = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + cfree = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available; + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_entry - UX_HOST_CLASS_COMMAND_ACTIVATE ext memory ERROR\n"); + ux_test_utility_sim_mem_alloc_fail_all_start(); + command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_ACTIVATE; + status = _ux_host_class_storage_entry(&command); + ux_test_utility_sim_mem_alloc_fail_all_stop(); + if (status != UX_MEMORY_INSUFFICIENT) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_DESTROY; + _ux_host_class_storage_entry(&command); + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_entry - UX_HOST_CLASS_COMMAND_ACTIVATE media memory ERROR\n"); + ux_test_utility_sim_mem_allocate_until(sizeof(UX_HOST_CLASS_STORAGE_EXT) + sizeof(UX_HOST_CLASS_STORAGE_MEDIA) / 2); + command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_ACTIVATE; + status = _ux_host_class_storage_entry(&command); + ux_test_utility_sim_mem_free_all(); + if (status != UX_MEMORY_INSUFFICIENT) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_DESTROY; + _ux_host_class_storage_entry(&command); + +#if 0 /* No need since stack is allocated with ext. */ + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_entry - UX_HOST_CLASS_COMMAND_ACTIVATE stack memory ERROR\n"); + ux_test_utility_sim_mem_allocate_until(UX_HOST_CLASS_STORAGE_MAX_MEDIA*sizeof(UX_HOST_CLASS_STORAGE_MEDIA)); + command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_ACTIVATE; + status = _ux_host_class_storage_entry(&command); + ux_test_utility_sim_mem_free_all(); + if (status != UX_MEMORY_INSUFFICIENT) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_DESTROY; + _ux_host_class_storage_entry(&command); +#endif + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_entry - UX_HOST_CLASS_COMMAND_ACTIVATE thread ERROR\n"); + storage_ext0=_ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_HOST_CLASS_STORAGE_EXT) + 128); + storage_ext1=_ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_HOST_CLASS_STORAGE_EXT)); + _ux_utility_thread_create(&storage_ext1->ux_host_class_thread, + "tmp", _ux_host_class_storage_thread_entry, (ULONG)(ALIGN_TYPE)class, + storage_ext0->ux_host_class_thread_stack, UX_HOST_CLASS_STORAGE_THREAD_STACK_SIZE, + UX_HOST_CLASS_STORAGE_THREAD_PRIORITY_CLASS, UX_HOST_CLASS_STORAGE_THREAD_PRIORITY_CLASS, + TX_NO_TIME_SLICE, TX_DONT_START); + UX_THREAD_EXTENSION_PTR_SET(&storage_ext1->ux_host_class_thread, class) + _ux_utility_memory_free(storage_ext0); + command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_ACTIVATE; + status = _ux_host_class_storage_entry(&command); + if (status != UX_THREAD_ERROR) + { + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_utility_thread_delete(&storage_ext1->ux_host_class_thread); + _ux_utility_memory_free(storage_ext1); + command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_DESTROY; + _ux_host_class_storage_entry(&command); + + /* Wait a while so the thread goes. */ + _ux_utility_delay_ms(10); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + + if (lun > 1) + return UX_ERROR; + + ram_disk_read_sent = UX_TRUE; + if (ram_disk_read_status != UX_SUCCESS) + { + if (media_status != UX_NULL) + *media_status = ram_disk_read_media_status; + + return ram_disk_read_status; + } + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + + if (lun > 1) + return UX_ERROR; + + ram_disk_write_sent = UX_TRUE; + if (ram_disk_write_status != UX_SUCCESS) + { + if (media_status != UX_NULL) + *media_status = ram_disk_write_media_status; + + return ram_disk_write_status; + } + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)number_blocks; + (void)lba; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + 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_storage_fats_exfat_test.c b/test/regression/usbx_ux_host_class_storage_fats_exfat_test.c new file mode 100644 index 00000000..86034e83 --- /dev/null +++ b/test/regression/usbx_ux_host_class_storage_fats_exfat_test.c @@ -0,0 +1,749 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (20 * 1000 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ +VOID _fx_ram_driver(FX_MEDIA *media_ptr); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +static FX_MEDIA *storage_disk; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_FILE my_file; + +static FX_MEDIA ram_disk1; +static FX_MEDIA ram_disk2; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static UCHAR buffer1[512]; +static UCHAR buffer2[512]; + +static FX_MEDIA *ram_disks[] = {&ram_disk1, &ram_disk2}; +static UCHAR *buffers[] = {buffer1, buffer2}; +static CHAR *ram_disk_memory[] = { ram_disk_memory1, ram_disk_memory2 }; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00 + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00 + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if ((storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE) && + (class -> ux_host_class_ext != UX_NULL) && + (class -> ux_host_class_media != UX_NULL)) + { + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + storage_disk = &storage_media -> ux_host_class_storage_media; +#endif + return(UX_SUCCESS); + } + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_storage_fats_exfat_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +ULONG mem_free; +ULONG test_n; + + + /* Inform user. */ + printf("Running Storage FATs & exFAT Test................................... "); + stepinfo("\n"); +#if defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + printf("Skip\n"); + test_control_return(0); + return; +#endif + + /* 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 #%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 device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 2; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_parameter); + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_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(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%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 #%d\n", __LINE__); + test_control_return(1); + } +} + +static UINT _test_format_FAT(void) +{ +UINT status; + + status = fx_media_format(&ram_disk1, _fx_ram_driver, ram_disk_memory1, buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + if (status != FX_SUCCESS) + return(status); + status = fx_media_format(&ram_disk2, _fx_ram_driver, ram_disk_memory2, buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + return(status); +} + +static UINT _test_format_exFAT(void) +{ +UINT status; + + /* Format the media. This needs to be done before opening it! */ + status = fx_media_exFAT_format(&ram_disk1, + _fx_ram_driver, // Driver entry + ram_disk_memory1, // RAM disk memory pointer + buffer1, // Media buffer pointer + 512, // Media buffer size + "RAM_DISK1", // Volume Name + 1, // Number of FATs + 0, // Hidden sectors + UX_RAM_DISK_SIZE/512, // Total sectors + 512, // Sector size + 1, // exFAT Sectors per cluster + 11111, // Volume ID + 0); // Boundary unit + if (status != FX_SUCCESS) + return(status); + + status = fx_media_exFAT_format(&ram_disk2, + _fx_ram_driver, // Driver entry + ram_disk_memory2, // RAM disk memory pointer + buffer1, // Media buffer pointer + 512, // Media buffer size + "RAM_DISK1", // Volume Name + 1, // Number of FATs + 0, // Hidden sectors + UX_RAM_DISK_SIZE/512, // Total sectors + 512, // Sector size + 1, // exFAT Sectors per cluster + 22222, // Volume ID + 0); // Boundary unit + return(status); +} + +static UINT _test_media_open(void) +{ +UINT status; + status = fx_media_open(&ram_disk1, "RAM DISK1", _fx_ram_driver, ram_disk_memory1, buffer1, 512); + if (status != FX_SUCCESS) + return(status); + status = fx_media_open(&ram_disk2, "RAM DISK2", _fx_ram_driver, ram_disk_memory2, buffer2, 512); + return(status); +} + +static UINT _test_media_close(void) +{ + fx_media_close(&ram_disk1); + fx_media_close(&ram_disk2); +} + +static VOID _test_storage_disk(void) +{ +UINT status; +ULONG actual; +UCHAR local_buffer[32]; + + // printf("Sector 0: %02x %02x %02x %c %c %c %c %c ...\n", ram_disk_memory1[0], ram_disk_memory1[1], ram_disk_memory1[2], ram_disk_memory1[3], ram_disk_memory1[4], ram_disk_memory1[5], ram_disk_memory1[6], ram_disk_memory1[7]); + + /* Create a file called TEST.TXT in the root directory. */ + status = fx_file_create(storage_disk, "TEST.TXT"); + + /* Check the create status. */ + if (status != FX_SUCCESS) + { + + /* Check for an already created status. This is not fatal, just + let the user know. */ + if (status != FX_ALREADY_CREATED) + { + + printf("f_create ERROR %x!\n", status); + return; + } + } + + /* Open the test file. */ + status = fx_file_open(storage_disk, &my_file, "TEST.TXT", FX_OPEN_FOR_WRITE); + + /* Check the file open status. */ + if (status != FX_SUCCESS) + { + + printf("f_open ERROR %x!\n", status); + return; + } + + /* Seek to the beginning of the test file. */ + status = fx_file_seek(&my_file, 0); + + /* Check the file seek status. */ + if (status != FX_SUCCESS) + { + + printf("f_seek ERROR %x!\n", status); + return; + } + + /* Write a string to the test file. */ + status = fx_file_write(&my_file, " ABCDEFGHIJKLMNOPQRSTUVWXYZ\n", 28); + + /* Check the file write status. */ + if (status != FX_SUCCESS) + { + + printf("f_write ERROR %x!\n", status); + return; + } + + /* Seek to the beginning of the test file. */ + status = fx_file_seek(&my_file, 0); + + /* Check the file seek status. */ + if (status != FX_SUCCESS) + { + + printf("%d:f_seek ERROR %x!\n", __LINE__, status); + return; + } + + /* Read the first 28 bytes of the test file. */ + status = fx_file_read(&my_file, local_buffer, 28, &actual); + + /* Check the file read status. */ + if ((status != FX_SUCCESS) || (actual != 28)) + { + + printf("%d:f_read ERROR %x!\n", __LINE__, status); + return; + } + + /* Close the test file. */ + status = fx_file_close(&my_file); + + /* Check the file close status. */ + if (status != FX_SUCCESS) + { + + printf("%d:f_close ERROR %x!\n", __LINE__, status); + return; + } +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG mem_free; +ULONG test_n; + + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Format the ram drive. */ + status = _test_format_FAT(); + if (status != FX_SUCCESS) + { + + /* Storage basic test error. */ + printf("ERROR #8\n"); + test_control_return(1); + } + + /* Open the ram_disk. */ + status = _test_media_open(); + if (status != FX_SUCCESS) + { + + /* Storage basic test error. */ + printf("ERROR %d\n", __LINE__); + test_control_return(1); + } + + /* Find the storage class. */ + status = host_storage_instance_get(500); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Test (FAT). */ + // printf("Test RW on FAT\n"); + _test_storage_disk(); + + /* Test disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check connection. */ + status = host_storage_instance_get(0); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Close the ram_disk. */ + _test_media_close(); + status = _test_format_exFAT(); + if (status != UX_SUCCESS) + { + + /* Storage basic test error. */ + printf("ERROR %d, 0x%x\n", __LINE__, status); + test_control_return(1); + } + status = _test_media_open(); + if (status != UX_SUCCESS) + { + + /* Storage basic test error. */ + printf("ERROR %d\n", __LINE__); + test_control_return(1); + } + + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Check connection. */ + status = host_storage_instance_get(500); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Test (exFAT). */ + // printf("Test RW on exFAT\n"); + _test_storage_disk(); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +static UCHAR lun_init_done[2] = {0, 0}; +UINT status; +ULONG mstatus = UX_SLAVE_CLASS_STORAGE_SENSE_KEY_NO_SENSE; + + + (void)storage; + (void)media_id; + + + if (lun > 1) + status = (UX_ERROR); + else if (lun_init_done[lun] > 0) + status = (UX_SUCCESS); + else + { + lun_init_done[lun] ++; + mstatus = UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8); + status = (UX_ERROR); + } + + if (media_status) + *media_status = mstatus; + + return status; +} + +UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + +UINT status = 0; + + if(lba == 0) + { + ram_disks[lun]->fx_media_driver_logical_sector = 0; + ram_disks[lun]->fx_media_driver_sectors = 1; + ram_disks[lun]->fx_media_driver_request = FX_DRIVER_BOOT_READ; + ram_disks[lun]->fx_media_driver_buffer = data_pointer; + _fx_ram_driver(ram_disks[lun]); + status = ram_disks[lun]->fx_media_driver_status; + } + else + { + while(number_blocks--) + { + status = fx_media_read(ram_disks[lun],lba,data_pointer); + data_pointer+=512; + lba++; + } + } + return(status); +} + +UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + +UINT status = 0; + + if(lba == 0) + { + ram_disks[lun]->fx_media_driver_logical_sector = 0; + ram_disks[lun]->fx_media_driver_sectors = 1; + ram_disks[lun]->fx_media_driver_request = FX_DRIVER_BOOT_WRITE; + ram_disks[lun]->fx_media_driver_buffer = data_pointer; + _fx_ram_driver(ram_disks[lun]); + + status = ram_disks[lun]->fx_media_driver_status; + + } + else + { + + while(number_blocks--) + { + status = fx_media_write(ram_disks[lun],lba,data_pointer); + data_pointer+=512; + lba++; + } + return(status); + } + return(1); +} \ No newline at end of file diff --git a/test/regression/usbx_ux_host_class_storage_fx_driver.c b/test/regression/usbx_ux_host_class_storage_fx_driver.c new file mode 100644 index 00000000..9940ad0e --- /dev/null +++ b/test/regression/usbx_ux_host_class_storage_fx_driver.c @@ -0,0 +1,336 @@ +/* Implements FX driver entry if FX_MEDIA not integrated in UX Host Class Storage. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.h" + +#if defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + + +VOID _ux_host_class_storage_driver_entry(FX_MEDIA *media); + +VOID _ux_host_class_storage_media_insert(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG format_open); +VOID _ux_host_class_storage_media_remove(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); + +FX_MEDIA *_ux_host_class_storage_driver_medias(void); +FX_MEDIA *_ux_host_class_storage_driver_media(INT i); +UCHAR *_ux_host_class_storage_driver_media_memory(INT i); +INT _ux_host_class_storage_driver_media_index(FX_MEDIA *media); + +INT _ux_host_class_storage_media_index(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +FX_MEDIA *_ux_host_class_storage_media_fx_media(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +UCHAR *_ux_host_class_storage_media_fx_media_memory(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); + +static FX_MEDIA medias[UX_HOST_CLASS_STORAGE_MAX_MEDIA]; +static UCHAR medias_memories[UX_HOST_CLASS_STORAGE_MAX_MEDIA][UX_HOST_CLASS_STORAGE_MEMORY_BUFFER_SIZE]; +static VOID (*_ux_host_class_storage_media_read_write_notify)(UINT, UINT, + UX_HOST_CLASS_STORAGE *, ULONG, ULONG, UCHAR*) = UX_NULL; + +VOID _ux_host_class_storage_driver_read_write_notify( + VOID (*func)(UINT, UINT, UX_HOST_CLASS_STORAGE *, ULONG, ULONG, UCHAR*)) +{ + _ux_host_class_storage_media_read_write_notify = func; +} + +FX_MEDIA *_ux_host_class_storage_driver_medias(void) +{ + return(medias); +} + +FX_MEDIA *_ux_host_class_storage_driver_media(INT i) +{ + return(&medias[i]); +} + +UCHAR *_ux_host_class_storage_driver_media_memory(INT i) +{ + return(medias_memories[i]); +} + +INT _ux_host_class_storage_driver_media_index(FX_MEDIA *media) +{ + +INT media_index; + + + if (media < medias) + return(-1); + media_index = (INT)(media - medias); + if (media_index >= UX_HOST_CLASS_STORAGE_MAX_MEDIA) + return(-1); + return(media_index); +} + +INT _ux_host_class_storage_media_index(UX_HOST_CLASS_STORAGE_MEDIA *storage_media) +{ +UX_HOST_CLASS_STORAGE *storage; +UX_HOST_CLASS *class_inst; +UX_HOST_CLASS_STORAGE_MEDIA *storage_medias; + if (storage_media == UX_NULL) + return(-1); + if (storage_media -> ux_host_class_storage_media_storage == UX_NULL) + return(-1); + storage = storage_media -> ux_host_class_storage_media_storage; + if (storage == UX_NULL) + return(-1); + class_inst = storage -> ux_host_class_storage_class; + if (class_inst == UX_NULL) + return(-1); + storage_medias = (UX_HOST_CLASS_STORAGE_MEDIA *)class_inst -> ux_host_class_media; + if (storage_media < storage_medias) + return(-1); + return((INT)(storage_media - storage_medias)); +} + +FX_MEDIA *_ux_host_class_storage_media_fx_media(UX_HOST_CLASS_STORAGE_MEDIA *storage_media) +{ +INT media_index = _ux_host_class_storage_media_index(storage_media); + if (media_index < 0) + return(UX_NULL); + return(&medias[media_index]); +} +UCHAR *_ux_host_class_storage_media_fx_media_memory(UX_HOST_CLASS_STORAGE_MEDIA *storage_media) +{ +INT media_index = _ux_host_class_storage_media_index(storage_media); + if (media_index < 0) + return(UX_NULL); + return(medias_memories[media_index]); +} + +VOID _ux_host_class_storage_media_insert(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG format_open) +{ +INT media_index = _ux_host_class_storage_media_index(storage_media); +UINT rc = 0; + if (media_index < 0) + { + return; + } + medias[media_index].fx_media_driver_info = storage_media; + /* Format. */ + if (format_open > 1) + { + rc = fx_media_format(&medias[media_index], + _ux_host_class_storage_driver_entry, + storage_media, + medias_memories[media_index], UX_HOST_CLASS_STORAGE_MEMORY_BUFFER_SIZE, + "USB DISK", 2, 512, 0, + storage_media -> ux_host_class_storage_media_number_sectors, + storage_media -> ux_host_class_storage_media_sector_size, + 4, + 1, 1); + if (rc != UX_SUCCESS) + { + printf("%s:%d media_format error 0x%x\n", __FILE__, __LINE__, rc); + } + } + /* Open. */ + if (format_open > 0 && rc == 0) + { + /* Open the media. */ + rc = fx_media_open(&medias[media_index], UX_HOST_CLASS_STORAGE_MEDIA_NAME, + _ux_host_class_storage_driver_entry, + storage_media, + medias_memories[media_index], + UX_HOST_CLASS_STORAGE_MEMORY_BUFFER_SIZE); + if (rc != UX_SUCCESS) + { + printf("%s:%d media_open error 0x%x\n", __FILE__, __LINE__, rc); + } + } + if (rc) + { + /* Inserted but not ready. */ + medias[media_index].fx_media_id = 0; + } + else + { + } +} + +VOID _ux_host_class_storage_media_remove(UX_HOST_CLASS_STORAGE_MEDIA *storage_media) +{ +INT media_index = _ux_host_class_storage_media_index(storage_media); +UINT rc = 0; + + if (media_index < 0) + { + return; + } + if (medias[media_index].fx_media_driver_info == storage_media) + { + rc = fx_media_close(&medias[media_index]); + medias[media_index].fx_media_id = 0; /* Keeping compatible with integrated FX_MEDIA. */ + medias[media_index].fx_media_driver_info = UX_NULL; + if (rc != UX_SUCCESS) + { + printf("%s:%d media_close error %x\n", __FILE__, __LINE__, rc); + } + } +} + +VOID _ux_host_class_storage_driver_entry(FX_MEDIA *media) +{ + +UINT status; +UX_HOST_CLASS_STORAGE *storage; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; + + + /* Get the pointer to the storage media instance. */ + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *) media -> fx_media_driver_info; + + /* Get storage instance. */ + storage = storage_media -> ux_host_class_storage_media_storage; + + /* Ensure the instance is valid. */ + if ((storage -> ux_host_class_storage_state != UX_HOST_CLASS_INSTANCE_LIVE) && + (storage -> ux_host_class_storage_state != UX_HOST_CLASS_INSTANCE_MOUNTING)) + { + + /* Class instance is invalid. Return an error! */ + media -> fx_media_driver_status = FX_PTR_ERROR; + return; + } + + /* Protect Thread reentry to this instance and select media LUN for further access. */ + status = _ux_host_class_storage_media_lock(storage_media, UX_WAIT_FOREVER); + if (status != UX_SUCCESS) + { + printf("%s:%d lock fail 0x%x!\n", __FILE__, __LINE__, status); + media -> fx_media_driver_status = FX_IO_ERROR; + return; + } + + /* Look at the request specified by the FileX caller. */ + switch (media -> fx_media_driver_request) + { + + case FX_DRIVER_READ: + + /* Read one or more sectors. */ + status = _ux_host_class_storage_media_read(storage, media -> fx_media_driver_logical_sector, + media -> fx_media_driver_sectors, media -> fx_media_driver_buffer); + if (_ux_host_class_storage_media_read_write_notify) + _ux_host_class_storage_media_read_write_notify(FX_DRIVER_READ, status, + storage, + media -> fx_media_driver_logical_sector, + media -> fx_media_driver_sectors, + media -> fx_media_driver_buffer); + + /* Check completion status. */ + if (status == UX_SUCCESS) + media -> fx_media_driver_status = FX_SUCCESS; + else + media -> fx_media_driver_status = _ux_host_class_storage_sense_code_translate(storage, status); + break; + + + case FX_DRIVER_WRITE: + + /* Write one or more sectors. */ + status = _ux_host_class_storage_media_write(storage, media -> fx_media_driver_logical_sector, + media -> fx_media_driver_sectors, media -> fx_media_driver_buffer); + if (_ux_host_class_storage_media_read_write_notify) + _ux_host_class_storage_media_read_write_notify(FX_DRIVER_WRITE, status, + storage, + media -> fx_media_driver_logical_sector, + media -> fx_media_driver_sectors, + media -> fx_media_driver_buffer); + + /* Check completion status. */ + if (status == UX_SUCCESS) + media -> fx_media_driver_status = FX_SUCCESS; + else + media -> fx_media_driver_status = _ux_host_class_storage_sense_code_translate(storage,status); + break; + + + case FX_DRIVER_FLUSH: + + /* Nothing to do. Just return a good status! */ + media -> fx_media_driver_status = FX_SUCCESS; + break; + + case FX_DRIVER_ABORT: + + /* Nothing to do. Just return a good status! */ + media -> fx_media_driver_status = FX_SUCCESS; + break; + + case FX_DRIVER_INIT: + + /* Check for media protection. We must do this operation here because FileX clears all the + media fields before init. */ + if (storage -> ux_host_class_storage_write_protected_media == UX_TRUE) + + /* The media is Write Protected. We tell FileX. */ + media -> fx_media_driver_write_protect = UX_TRUE; + + /* This function always succeeds. */ + media -> fx_media_driver_status = FX_SUCCESS; + break; + + + case FX_DRIVER_UNINIT: + + /* Nothing to do. Just return a good status! */ + media -> fx_media_driver_status = FX_SUCCESS; + break; + + + case FX_DRIVER_BOOT_READ: + + /* Read the media boot sector. */ + status = _ux_host_class_storage_media_read(storage, 0, 1, + media -> fx_media_driver_buffer); + if (_ux_host_class_storage_media_read_write_notify) + _ux_host_class_storage_media_read_write_notify(FX_DRIVER_READ, status, + storage, 0, 1, + media -> fx_media_driver_buffer); + + /* Check completion status. */ + if (status == UX_SUCCESS) + media -> fx_media_driver_status = FX_SUCCESS; + else + media -> fx_media_driver_status = _ux_host_class_storage_sense_code_translate(storage,status); + break; + + + case FX_DRIVER_BOOT_WRITE: + + /* Write the boot sector. */ + status = _ux_host_class_storage_media_write(storage, 0, 1, + media -> fx_media_driver_buffer); + if (_ux_host_class_storage_media_read_write_notify) + _ux_host_class_storage_media_read_write_notify(FX_DRIVER_WRITE, status, + storage, 0, 1, + media -> fx_media_driver_buffer); + + /* Check completion status. */ + if (status == UX_SUCCESS) + media -> fx_media_driver_status = FX_SUCCESS; + else + media -> fx_media_driver_status = _ux_host_class_storage_sense_code_translate(storage, status); + break; + + + default: + + /* Invalid request from FileX */ + media -> fx_media_driver_status = FX_IO_ERROR; + break; + } + + /* Unprotect thread reentry to this instance. */ + _ux_host_class_storage_media_unlock(storage_media); +} +#endif diff --git a/test/regression/usbx_ux_host_class_storage_max_lun_get_test.c b/test/regression/usbx_ux_host_class_storage_max_lun_get_test.c new file mode 100644 index 00000000..7c1223c3 --- /dev/null +++ b/test/regression/usbx_ux_host_class_storage_max_lun_get_test.c @@ -0,0 +1,662 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static CHAR ram_disk_flush = 0; +static UINT ram_disk_flush_status = UX_SUCCESS; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + +static UX_TEST_SETUP _GetMaxLun = UX_TEST_SETUP_STORAGE_GetMaxLun; + +static UX_TEST_HCD_SIM_ACTION stall_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_TRANSFER_STALLED, + UX_TRANSFER_STALLED, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION length_error_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 2, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION replaced_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_storage_max_lun_get_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_storage_max_lun_get Test...................... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_parameter); + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + // status = _ux_test_dcd_sim_slave_initialize(); + status = ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + // 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 #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done. */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_max_lun_get - STALLed\n"); + buffer[0] = 2; + ux_test_hcd_sim_host_set_actions(stall_GetMaxLun); + status = _ux_host_class_storage_max_lun_get(storage); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (storage->ux_host_class_storage_max_lun != 0) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_max_lun_get - return length error\n"); + buffer[0] = 2; + ux_test_hcd_sim_host_set_actions(length_error_GetMaxLun); + status = _ux_host_class_storage_max_lun_get(storage); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (storage->ux_host_class_storage_max_lun != 0) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_max_lun_get - over UX_MAX_HOST_LUN - 1\n"); + buffer[0] = UX_MAX_HOST_LUN; + ux_test_hcd_sim_host_set_actions(replaced_GetMaxLun); + error_callback_counter = 0; + status = _ux_host_class_storage_max_lun_get(storage); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (storage->ux_host_class_storage_max_lun != (UX_MAX_HOST_LUN - 1)) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + if (error_callback_counter == 0) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + + /* Wait a while so the thread goes. */ + _ux_utility_delay_ms(10); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)number_blocks; + (void)lba; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + 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_storage_media_capacity_get_test.c b/test/regression/usbx_ux_host_class_storage_media_capacity_get_test.c new file mode 100644 index 00000000..4a60893c --- /dev/null +++ b/test/regression/usbx_ux_host_class_storage_media_capacity_get_test.c @@ -0,0 +1,587 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static CHAR ram_disk_flush = 0; +static UINT ram_disk_flush_status = UX_SUCCESS; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_storage_media_capacity_get_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_storage_media_capacity_get Test............... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_parameter); + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + // status = _ux_test_dcd_sim_slave_initialize(); + status = ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + // 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 #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done. */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_media_capacity_get - UX_HOST_CLASS_STORAGE_MEDIA_CDROM\n"); + storage -> ux_host_class_storage_media_type = UX_HOST_CLASS_STORAGE_MEDIA_CDROM; + status = _ux_host_class_storage_media_capacity_get(storage); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_media_capacity_get - Unsupported\n"); + storage -> ux_host_class_storage_media_type = 0xFF; + status = _ux_host_class_storage_media_capacity_get(storage); + if (status != UX_HOST_CLASS_MEDIA_NOT_SUPPORTED) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Wait a while so the thread goes. */ + _ux_utility_delay_ms(10); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)number_blocks; + (void)lba; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + 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_storage_media_get_test.c b/test/regression/usbx_ux_host_class_storage_media_get_test.c new file mode 100644 index 00000000..3f844ade --- /dev/null +++ b/test/regression/usbx_ux_host_class_storage_media_get_test.c @@ -0,0 +1,690 @@ +/* This test is designed to test the storage host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static UINT ram_disk_read_status = UX_SUCCESS; +static ULONG ram_disk_read_media_status = 0; +static CHAR ram_disk_read_sent = 0; + +static CHAR ram_disk_flush = 0; +static UINT ram_disk_flush_status = UX_SUCCESS; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + +static UX_TEST_SETUP _GetMaxLun = UX_TEST_SETUP_STORAGE_GetMaxLun; + +static UX_TEST_HCD_SIM_ACTION stall_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_TRANSFER_STALLED, + UX_TRANSFER_STALLED, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION length_error_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 2, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION replaced_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION fail_bulk_out[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_ERROR, + UX_ERROR, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION fail_2nd_bulk_out[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_SUCCESS, + UX_SUCCESS, UX_NULL, + UX_TRUE}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_ERROR, + UX_ERROR, UX_NULL}, +{ 0 } +}; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_storage_media_get_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_storage_media_get Test........................ "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 2; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_parameter); + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + // status = _ux_test_dcd_sim_slave_initialize(); + status = ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + // 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 #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_DEVICE *device; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_medias; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +INT media_index; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_medias = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + storage_media = &storage_medias[0]; + + /* Confirm media enum done (). */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + +#if defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_media_get(0) - SUCCESS\n"); + status = _ux_host_class_storage_media_get(storage, 0, &storage_media); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (storage_media != storage_medias) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_media_get(UX_MAX_HOST_LUN) - FAIL\n"); + status = _ux_host_class_storage_media_get(storage, UX_MAX_HOST_LUN, &storage_media); + if (status == UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + 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 +#else + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_media_get(0) - SUCCESS\n"); + storage_medias[0].ux_host_class_storage_media_storage = UX_NULL; + status = _ux_host_class_storage_media_get(storage, 0, &storage_media); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + storage_medias[0].ux_host_class_storage_media_storage = storage; +#endif +#else + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_media_get - no implement\n"); +#endif + + /* Wait a while so the thread goes. */ + _ux_utility_delay_ms(10); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + + if (lun > 1) + return UX_ERROR; + + ram_disk_read_sent = UX_TRUE; + + if (ram_disk_read_status != UX_SUCCESS) + { + if (media_status != UX_NULL) + *media_status = ram_disk_read_media_status; + + return ram_disk_read_status; + } + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)number_blocks; + (void)lba; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + 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_storage_media_mount_test.c b/test/regression/usbx_ux_host_class_storage_media_mount_test.c new file mode 100644 index 00000000..9bb19407 --- /dev/null +++ b/test/regression/usbx_ux_host_class_storage_media_mount_test.c @@ -0,0 +1,720 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static UINT ram_disk_read_status = UX_SUCCESS; +static ULONG ram_disk_read_media_status = 0; +static CHAR ram_disk_read_sent = 0; + +static CHAR ram_disk_flush = 0; +static UINT ram_disk_flush_status = UX_SUCCESS; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + +static UX_TEST_SETUP _GetMaxLun = UX_TEST_SETUP_STORAGE_GetMaxLun; + +static UX_TEST_HCD_SIM_ACTION stall_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_TRANSFER_STALLED, + UX_TRANSFER_STALLED, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION length_error_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 2, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION replaced_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION fail_bulk_out[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_ERROR, + UX_ERROR, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION fail_2nd_bulk_out[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_SUCCESS, + UX_SUCCESS, UX_NULL, + UX_TRUE}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_ERROR, + UX_ERROR, UX_NULL}, +{ 0 } +}; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_storage_media_mount_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_storage_media_mount Test...................... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 2; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_parameter); + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + // status = _ux_test_dcd_sim_slave_initialize(); + status = ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + // 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 #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +ULONG rfree, cfree; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done (). */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + configuration = device -> ux_device_first_configuration; + interface = configuration -> ux_configuration_first_interface; + + rfree = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + cfree = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available; + +#if defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + /* Invoke not supported media functions for coverage. */ + _ux_host_class_storage_media_mount(storage, 0); + _ux_host_class_storage_media_open(storage, 0); + _ux_host_class_storage_partition_read(storage, 0, 0); +#else + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_media_mount - unit_ready FAIL\n"); + ux_test_hcd_sim_host_set_actions(fail_bulk_out); + status = _ux_host_class_storage_media_mount(storage, 0); + if (status == UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (rfree != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available || + cfree != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available) + { + printf("ERROR #%d, memory leap!\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_media_mount - read FAIL\n"); + ux_test_hcd_sim_host_set_actions(fail_2nd_bulk_out); + ram_disk_status = UX_SUCCESS; + ram_disk_read_status = UX_ERROR; + ram_disk_read_media_status = 0x003A02; + status = _ux_host_class_storage_media_mount(storage, 0); + if (status == UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (rfree != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available || + cfree != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available) + { + printf("ERROR #%d, memory leap!\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_media_mount - read FAIL SENSE ERROR\n"); + ram_disk_status = UX_SUCCESS; + ram_disk_read_status = UX_ERROR; + ram_disk_read_media_status = 0x023A00; + status = _ux_host_class_storage_media_mount(storage, 0); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (rfree != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available || + cfree != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available) + { + printf("ERROR #%d, memory leap!\n", __LINE__); + test_control_return(1); + } +#endif + + /* Wait a while so the thread goes. */ + _ux_utility_delay_ms(10); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + + if (lun > 1) + return UX_ERROR; + + ram_disk_read_sent = UX_TRUE; + + if (ram_disk_read_status != UX_SUCCESS) + { + if (media_status != UX_NULL) + *media_status = ram_disk_read_media_status; + + return ram_disk_read_status; + } + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)number_blocks; + (void)lba; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + 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_storage_media_open_test.c b/test/regression/usbx_ux_host_class_storage_media_open_test.c new file mode 100644 index 00000000..879e4653 --- /dev/null +++ b/test/regression/usbx_ux_host_class_storage_media_open_test.c @@ -0,0 +1,712 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static UINT ram_disk_read_status = UX_SUCCESS; +static ULONG ram_disk_read_media_status = 0; +static CHAR ram_disk_read_sent = 0; + +static CHAR ram_disk_flush = 0; +static UINT ram_disk_flush_status = UX_SUCCESS; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + +static UX_TEST_SETUP _GetMaxLun = UX_TEST_SETUP_STORAGE_GetMaxLun; + +static UX_TEST_HCD_SIM_ACTION stall_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_TRANSFER_STALLED, + UX_TRANSFER_STALLED, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION length_error_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 2, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION replaced_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION fail_bulk_out[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_ERROR, + UX_ERROR, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION fail_2nd_bulk_out[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_SUCCESS, + UX_SUCCESS, UX_NULL, + UX_TRUE}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_ERROR, + UX_ERROR, UX_NULL}, +{ 0 } +}; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_storage_media_open_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_storage_media_open Test....................... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 2; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_parameter); + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + // status = _ux_test_dcd_sim_slave_initialize(); + status = ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + // 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 #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +ULONG rfree, cfree; +FX_MEDIA *media; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done (). */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + configuration = device -> ux_device_first_configuration; + interface = configuration -> ux_configuration_first_interface; + +#if !!defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + /* In this case, _media_open and _partition_read are called for coverage. */ + /* They are actually not supported. */ + _ux_host_class_storage_media_open(storage, 0); + _ux_host_class_storage_partition_read(storage, 0, 0); +#else + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_media_open - UX_HOST_CLASS_MEMORY_ERROR\n"); + rfree = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + cfree = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available; + status = _ux_host_class_storage_media_open(storage, 0); + if (status != UX_HOST_CLASS_MEMORY_ERROR) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (rfree != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available || + cfree != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available) + { + printf("ERROR #%d, memory leap!\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_media_open - UX_MEMORY_INSUFFICIENT\n"); + + /* Close a media for test. */ + media = &storage_media -> ux_host_class_storage_media; + fx_media_close(media); + media->fx_media_id = 0; + _ux_utility_memory_free(storage_media->ux_host_class_storage_media_memory); + + /* Open the media. */ + + rfree = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + cfree = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available; + + ux_test_utility_sim_mem_alloc_fail_all_start(); + status = _ux_host_class_storage_media_open(storage, 0); + ux_test_utility_sim_mem_alloc_fail_all_stop(); + if (status != UX_MEMORY_INSUFFICIENT) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (rfree != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available || + cfree != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available) + { + printf("ERROR #%d, memory leap!\n", __LINE__); + test_control_return(1); + } +#endif + + /* Wait a while so the thread goes. */ + _ux_utility_delay_ms(10); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + + if (lun > 1) + return UX_ERROR; + + ram_disk_read_sent = UX_TRUE; + + if (ram_disk_read_status != UX_SUCCESS) + { + if (media_status != UX_NULL) + *media_status = ram_disk_read_media_status; + + return ram_disk_read_status; + } + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)number_blocks; + (void)lba; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + 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_storage_media_protection_check_test.c b/test/regression/usbx_ux_host_class_storage_media_protection_check_test.c new file mode 100644 index 00000000..5d8ed670 --- /dev/null +++ b/test/regression/usbx_ux_host_class_storage_media_protection_check_test.c @@ -0,0 +1,891 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; +static UCHAR cbw_buffer[UX_SLAVE_CLASS_STORAGE_CBW_LENGTH]; +static UCHAR cbw_fail_sim = UX_FALSE; +static UCHAR csw_buffer[UX_SLAVE_CLASS_STORAGE_CSW_LENGTH]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static UINT ram_disk_read_status = UX_SUCCESS; +static ULONG ram_disk_read_media_status = 0; +static CHAR ram_disk_read_sent = 0; + +static UINT ram_disk_write_status = UX_SUCCESS; +static ULONG ram_disk_write_media_status = 0; +static CHAR ram_disk_write_sent = 0; + +static CHAR ram_disk_flush = 0; +static UINT ram_disk_flush_status = UX_SUCCESS; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + +struct mode_sense6_parameter_header { + + /* @0 The MODE DATA LENGTH field indicates the length in bytes of the following + data that is available to be transferred. The mode data length does not + include the number of bytes in the MODE DATA LENGTH field. */ + UCHAR mode_data_length; + UCHAR medium_type; + + /* @2 0x80 for write protect. */ + UCHAR wp_buffered_mode_speed; + UCHAR block_descriptor_length; +}; +static struct mode_sense6_parameter_header mode_sense_parameter6 = { + .mode_data_length = 3, + .medium_type = 0x00, + .wp_buffered_mode_speed = 0x00, + .block_descriptor_length = 0, +}; + +struct mode_sense10_parameter_header { + USHORT mode_data_length; + UCHAR medium_type; + + /* @3 0x80 for write protect. */ + UCHAR wp_buffered_mode_speed; + UCHAR reserved[2]; + USHORT block_descriptor_length; +}; +static struct mode_sense10_parameter_header mode_sense_parameter10 = { + .mode_data_length = 6, + .medium_type = 0x00, + .wp_buffered_mode_speed = 0x00, + .reserved = {0, 0}, + .block_descriptor_length = 0, +}; + +static UX_TEST_SETUP _GetMaxLun = UX_TEST_SETUP_STORAGE_GetMaxLun; + +static UX_TEST_HCD_SIM_ACTION stall_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_TRANSFER_STALLED, + UX_TRANSFER_STALLED, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION length_error_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 2, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION replaced_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION fail_bulk_out[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_ERROR, + UX_ERROR, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION fail_2nd_bulk_out[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_SUCCESS, + UX_SUCCESS, UX_NULL, + UX_TRUE}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_ERROR, + UX_ERROR, UX_NULL}, +{ 0 } +}; + +static VOID sending_cbw(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UCHAR *cbw = (UCHAR *)storage -> ux_host_class_storage_cbw; +UX_TRANSFER *transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + + + _ux_utility_memory_copy(cbw_buffer, cbw, 31); + + /* Prepare CSW. */ + _ux_utility_memory_copy(csw_buffer + 0, cbw_buffer + 0, 4); /* dCBWSignature -> dCSWSignature */ + _ux_utility_memory_copy(csw_buffer + 4, cbw_buffer + 4, 4); /* dCBWTag -> dCSWTag */ + _ux_utility_memory_set (csw_buffer + 8, 0x00, 4); /* dCSWDataResidue <= 0 */ + _ux_utility_memory_set (csw_buffer + 12, 0x00, 1); /* bCSWStatus <= 0 */ + + transfer_request->ux_transfer_request_completion_code = UX_SUCCESS; + + if (!cbw_fail_sim) + _ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); +} + +static VOID getting_data(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UCHAR *cbw = (UCHAR *)storage -> ux_host_class_storage_cbw; +UX_TRANSFER *transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; +UCHAR cmd = *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_MODE_SENSE_OPERATION); + + + if (cmd == UX_HOST_CLASS_STORAGE_SCSI_MODE_SENSE_SHORT) + { + _ux_utility_memory_copy(transfer_request->ux_transfer_request_data_pointer, &mode_sense_parameter6, sizeof(mode_sense_parameter6)); + transfer_request->ux_transfer_request_actual_length = sizeof(mode_sense_parameter6); + } + else + { + _ux_utility_memory_copy(transfer_request->ux_transfer_request_data_pointer, &mode_sense_parameter10, sizeof(mode_sense_parameter10)); + transfer_request->ux_transfer_request_actual_length = sizeof(mode_sense_parameter10); + } + transfer_request->ux_transfer_request_completion_code = UX_SUCCESS; + _ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); +} + +static VOID getting_csw(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UCHAR *csw = (UCHAR *)storage -> ux_host_class_storage_csw; +UX_TRANSFER *transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + + _ux_utility_memory_copy(csw, csw_buffer, 13); + _ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); +} + +static UX_TEST_HCD_SIM_ACTION replace_cbw_data_csw[] = { +/* 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, 31, UX_SUCCESS, + UX_SUCCESS, + .action_func = sending_cbw, + .no_return = UX_FALSE, + .do_after = UX_FALSE}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x81, UX_NULL, 0, UX_SUCCESS, + UX_SUCCESS, + .action_func = getting_data, + .no_return = UX_FALSE, + .do_after = UX_FALSE}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP | UX_TEST_SIM_REQ_ANSWER, 0x81, csw_buffer, 13, UX_SUCCESS, + UX_SUCCESS, + .action_func = getting_csw, + .no_return = UX_FALSE, + .do_after = UX_FALSE}, +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_storage_media_protection_check_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_storage_media_protection_check Test........... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 2; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_thread_media_flush; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read_only_flag = UX_FALSE; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_flush = demo_thread_media_flush; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read_only_flag = UX_FALSE; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_parameter); + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + // status = _ux_test_dcd_sim_slave_initialize(); + status = ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + // 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 #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +UX_SLAVE_DEVICE *slave_device; +UX_SLAVE_CLASS *slave_class; +UX_SLAVE_CLASS_STORAGE *slave_storage; +ULONG rfree, cfree; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done (). */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + configuration = device -> ux_device_first_configuration; + interface = configuration -> ux_configuration_first_interface; + + slave_device = &_ux_system_slave->ux_system_slave_device; + slave_class = _ux_system_slave->ux_system_slave_interface_class_array[0]; + slave_storage = (UX_SLAVE_CLASS_STORAGE *)slave_class->ux_slave_class_instance; + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_media_protection_check - UX_SUCCESS\n"); + status = _ux_host_class_storage_media_protection_check(storage); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (storage -> ux_host_class_storage_write_protected_media == UX_TRUE) + { + printf("ERROR #%d: expect unprotected\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_media_protection_check - WP\n"); + ux_test_hcd_sim_host_set_actions(replace_cbw_data_csw); + status = _ux_host_class_storage_media_protection_check(storage); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (storage -> ux_host_class_storage_write_protected_media == UX_TRUE) + { + printf("ERROR #%d: expect unprotected\n", __LINE__); + test_control_return(1); + } + + mode_sense_parameter6.wp_buffered_mode_speed = 0x80; + ux_test_hcd_sim_host_set_actions(replace_cbw_data_csw); + status = _ux_host_class_storage_media_protection_check(storage); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (storage -> ux_host_class_storage_write_protected_media == UX_FALSE) + { + printf("ERROR #%d: expect protected\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_media_protection_check - RBC\n"); + ux_test_hcd_sim_host_set_actions(replace_cbw_data_csw); + storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceSubClass = UX_HOST_CLASS_STORAGE_SUBCLASS_RBC; + status = _ux_host_class_storage_media_protection_check(storage); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (storage -> ux_host_class_storage_write_protected_media == UX_TRUE) + { + printf("ERROR #%d: expect unprotected\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_media_protection_check - UX_MEMORY_INSUFFICIENT\n"); + + ux_test_hcd_sim_host_set_actions(replace_cbw_data_csw); + + rfree = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + cfree = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available; + + ux_test_utility_sim_mem_alloc_fail_all_start(); + status = _ux_host_class_storage_media_protection_check(storage); + ux_test_utility_sim_mem_alloc_fail_all_stop(); + if (status != UX_MEMORY_INSUFFICIENT) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (rfree != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available || + cfree != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available) + { + printf("ERROR #%d, memory leap!\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_media_protection_check - transfer error\n"); + cbw_fail_sim = UX_TRUE; + ux_test_hcd_sim_host_set_actions(replace_cbw_data_csw); + status = _ux_host_class_storage_media_protection_check(storage); + if (status == UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + cbw_fail_sim = UX_FALSE; + + /* Wait a while so the thread goes. */ + _ux_utility_delay_ms(10); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + + if (lun > 1) + return UX_ERROR; + + ram_disk_read_sent = UX_TRUE; + if (ram_disk_read_status != UX_SUCCESS) + { + if (media_status != UX_NULL) + *media_status = ram_disk_read_media_status; + + return ram_disk_read_status; + } + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + + if (lun > 1) + return UX_ERROR; + + ram_disk_write_sent = UX_TRUE; + if (ram_disk_write_status != UX_SUCCESS) + { + if (media_status != UX_NULL) + *media_status = ram_disk_write_media_status; + + return ram_disk_write_status; + } + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)number_blocks; + (void)lba; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + 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_storage_media_read_test.c b/test/regression/usbx_ux_host_class_storage_media_read_test.c new file mode 100644 index 00000000..22f51a98 --- /dev/null +++ b/test/regression/usbx_ux_host_class_storage_media_read_test.c @@ -0,0 +1,738 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; +static UCHAR cbw_buffer[UX_SLAVE_CLASS_STORAGE_CBW_LENGTH]; +static UCHAR csw_buffer[UX_SLAVE_CLASS_STORAGE_CSW_LENGTH]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static UINT ram_disk_read_status = UX_SUCCESS; +static ULONG ram_disk_read_media_status = 0; +static CHAR ram_disk_read_sent = 0; + +static CHAR ram_disk_flush = 0; +static UINT ram_disk_flush_status = UX_SUCCESS; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + +static UX_TEST_SETUP _GetMaxLun = UX_TEST_SETUP_STORAGE_GetMaxLun; + +static UX_TEST_HCD_SIM_ACTION stall_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_TRANSFER_STALLED, + UX_TRANSFER_STALLED, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION length_error_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 2, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION replaced_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION fail_bulk_out[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_ERROR, + UX_ERROR, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION fail_2nd_bulk_out[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_SUCCESS, + UX_SUCCESS, UX_NULL, + UX_TRUE}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_ERROR, + UX_ERROR, UX_NULL}, +{ 0 } +}; + +static VOID sending_cbw(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UCHAR *cbw = (UCHAR *)storage -> ux_host_class_storage_cbw; +UX_TRANSFER *transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + + + _ux_utility_memory_copy(cbw_buffer, cbw, 31); + + /* Prepare CSW. */ + _ux_utility_memory_copy(csw_buffer + 0, cbw_buffer + 0, 4); /* dCBWSignature -> dCSWSignature */ + _ux_utility_memory_copy(csw_buffer + 4, cbw_buffer + 4, 4); /* dCBWTag -> dCSWTag */ + _ux_utility_memory_set (csw_buffer + 8, 0x00, 4); /* dCSWDataResidue <= 0 */ + _ux_utility_memory_set (csw_buffer + 12, 0x00, 1); /* bCSWStatus <= 0 */ + + _ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); +} + +static VOID getting_data(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TRANSFER *transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + + _ux_utility_long_put(csw_buffer + 8, 1); /* dCSWDataResidue <= 1 for error test */ + _ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); +} + +static VOID getting_csw(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UCHAR *csw = (UCHAR *)storage -> ux_host_class_storage_csw; +UX_TRANSFER *transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + + _ux_utility_memory_copy(csw, csw_buffer, 13); + _ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); +} + +static UX_TEST_HCD_SIM_ACTION replace_cbw_data_csw[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 31, UX_SUCCESS, + UX_SUCCESS, + .action_func = sending_cbw, + .no_return = UX_FALSE, + .do_after = UX_FALSE}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP | UX_TEST_SIM_REQ_ANSWER, 0x81, buffer, 63, UX_SUCCESS, + UX_SUCCESS, + .action_func = getting_data, + .no_return = UX_FALSE, + .do_after = UX_FALSE}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP | UX_TEST_SIM_REQ_ANSWER, 0x81, csw_buffer, 13, UX_SUCCESS, + UX_SUCCESS, + .action_func = getting_csw, + .no_return = UX_FALSE, + .do_after = UX_FALSE}, +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_storage_media_read_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_storage_media_read Test....................... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 2; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_parameter); + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + // status = _ux_test_dcd_sim_slave_initialize(); + status = ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + // 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 #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done (). */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + configuration = device -> ux_device_first_configuration; + interface = configuration -> ux_configuration_first_interface; + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_media_read - Data cut off\n"); + ux_test_hcd_sim_host_set_actions(replace_cbw_data_csw); + status = _ux_host_class_storage_media_read(storage, 0, 1, buffer); + if (status != UX_ERROR) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Wait a while so the thread goes. */ + _ux_utility_delay_ms(10); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + + if (lun > 1) + return UX_ERROR; + + ram_disk_read_sent = UX_TRUE; + + if (ram_disk_read_status != UX_SUCCESS) + { + if (media_status != UX_NULL) + *media_status = ram_disk_read_media_status; + + return ram_disk_read_status; + } + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)number_blocks; + (void)lba; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + 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_storage_media_recovery_sense_get_test.c b/test/regression/usbx_ux_host_class_storage_media_recovery_sense_get_test.c new file mode 100644 index 00000000..f477c423 --- /dev/null +++ b/test/regression/usbx_ux_host_class_storage_media_recovery_sense_get_test.c @@ -0,0 +1,853 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; +static UCHAR cbw_buffer[UX_SLAVE_CLASS_STORAGE_CBW_LENGTH]; +static UCHAR cbw_fail_sim = UX_FALSE; +static UCHAR csw_buffer[UX_SLAVE_CLASS_STORAGE_CSW_LENGTH]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static UINT ram_disk_read_status = UX_SUCCESS; +static ULONG ram_disk_read_media_status = 0; +static CHAR ram_disk_read_sent = 0; + +static UINT ram_disk_write_status = UX_SUCCESS; +static ULONG ram_disk_write_media_status = 0; +static CHAR ram_disk_write_sent = 0; + +static CHAR ram_disk_flush = 0; +static UINT ram_disk_flush_status = UX_SUCCESS; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + +struct mode_sense6_parameter_header { + + /* @0 The MODE DATA LENGTH field indicates the length in bytes of the following + data that is available to be transferred. The mode data length does not + include the number of bytes in the MODE DATA LENGTH field. */ + UCHAR mode_data_length; + UCHAR medium_type; + + /* @2 0x80 for write protect. */ + UCHAR wp_buffered_mode_speed; + UCHAR block_descriptor_length; +}; +static struct mode_sense6_parameter_header mode_sense_parameter6 = { + .mode_data_length = 3, + .medium_type = 0x00, + .wp_buffered_mode_speed = 0x00, + .block_descriptor_length = 0, +}; + +struct mode_sense10_parameter_header { + USHORT mode_data_length; + UCHAR medium_type; + + /* @3 0x80 for write protect. */ + UCHAR wp_buffered_mode_speed; + UCHAR reserved[2]; + USHORT block_descriptor_length; +}; +static struct mode_sense10_parameter_header mode_sense_parameter10 = { + .mode_data_length = 6, + .medium_type = 0x00, + .wp_buffered_mode_speed = 0x00, + .reserved = {0, 0}, + .block_descriptor_length = 0, +}; + +static UX_TEST_SETUP _GetMaxLun = UX_TEST_SETUP_STORAGE_GetMaxLun; + +static UX_TEST_HCD_SIM_ACTION stall_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_TRANSFER_STALLED, + UX_TRANSFER_STALLED, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION length_error_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 2, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION replaced_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION fail_bulk_out[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_ERROR, + UX_ERROR, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION fail_2nd_bulk_out[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_SUCCESS, + UX_SUCCESS, UX_NULL, + UX_TRUE}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_ERROR, + UX_ERROR, UX_NULL}, +{ 0 } +}; + +static VOID sending_cbw(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UCHAR *cbw = (UCHAR *)storage -> ux_host_class_storage_cbw; +UX_TRANSFER *transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + + + _ux_utility_memory_copy(cbw_buffer, cbw, 31); + + /* Prepare CSW. */ + _ux_utility_memory_copy(csw_buffer + 0, cbw_buffer + 0, 4); /* dCBWSignature -> dCSWSignature */ + _ux_utility_memory_copy(csw_buffer + 4, cbw_buffer + 4, 4); /* dCBWTag -> dCSWTag */ + _ux_utility_memory_set (csw_buffer + 8, 0x00, 4); /* dCSWDataResidue <= 0 */ + _ux_utility_memory_set (csw_buffer + 12, 0x00, 1); /* bCSWStatus <= 0 */ + + transfer_request->ux_transfer_request_completion_code = UX_SUCCESS; + + if (!cbw_fail_sim) + _ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); +} + +static VOID getting_data(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UCHAR *cbw = (UCHAR *)storage -> ux_host_class_storage_cbw; +UX_TRANSFER *transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; +UCHAR cmd = *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_MODE_SENSE_OPERATION); + + + if (cmd == UX_HOST_CLASS_STORAGE_SCSI_MODE_SENSE_SHORT) + { + _ux_utility_memory_copy(transfer_request->ux_transfer_request_data_pointer, &mode_sense_parameter6, sizeof(mode_sense_parameter6)); + transfer_request->ux_transfer_request_actual_length = sizeof(mode_sense_parameter6); + } + else + { + _ux_utility_memory_copy(transfer_request->ux_transfer_request_data_pointer, &mode_sense_parameter10, sizeof(mode_sense_parameter10)); + transfer_request->ux_transfer_request_actual_length = sizeof(mode_sense_parameter10); + } + transfer_request->ux_transfer_request_completion_code = UX_SUCCESS; + _ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); +} + +static VOID getting_csw(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UCHAR *csw = (UCHAR *)storage -> ux_host_class_storage_csw; +UX_TRANSFER *transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + + _ux_utility_memory_copy(csw, csw_buffer, 13); + _ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); +} + +static UX_TEST_HCD_SIM_ACTION replace_cbw_data_csw[] = { +/* 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, 31, UX_SUCCESS, + UX_SUCCESS, + .action_func = sending_cbw, + .no_return = UX_FALSE, + .do_after = UX_FALSE}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x81, UX_NULL, 0, UX_SUCCESS, + UX_SUCCESS, + .action_func = getting_data, + .no_return = UX_FALSE, + .do_after = UX_FALSE}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP | UX_TEST_SIM_REQ_ANSWER, 0x81, csw_buffer, 13, UX_SUCCESS, + UX_SUCCESS, + .action_func = getting_csw, + .no_return = UX_FALSE, + .do_after = UX_FALSE}, +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_storage_media_recovery_sense_get_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_storage_media_recovery_sense_get Test......... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 2; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_thread_media_flush; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read_only_flag = UX_FALSE; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_flush = demo_thread_media_flush; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read_only_flag = UX_FALSE; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_parameter); + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + // status = _ux_test_dcd_sim_slave_initialize(); + status = ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + // 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 #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +UX_SLAVE_DEVICE *slave_device; +UX_SLAVE_CLASS *slave_class; +UX_SLAVE_CLASS_STORAGE *slave_storage; +ULONG rfree, cfree; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done (). */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + configuration = device -> ux_device_first_configuration; + interface = configuration -> ux_configuration_first_interface; + + slave_device = &_ux_system_slave->ux_system_slave_device; + slave_class = _ux_system_slave->ux_system_slave_interface_class_array[0]; + slave_storage = (UX_SLAVE_CLASS_STORAGE *)slave_class->ux_slave_class_instance; + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_media_recovery_sense_get - UX_SUCCESS\n"); + status = _ux_host_class_storage_media_recovery_sense_get(storage); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_media_recovery_sense_get - RBC\n"); + ux_test_hcd_sim_host_set_actions(replace_cbw_data_csw); + storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceSubClass = UX_HOST_CLASS_STORAGE_SUBCLASS_RBC; + status = _ux_host_class_storage_media_recovery_sense_get(storage); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_media_recovery_sense_get - UX_MEMORY_INSUFFICIENT\n"); + + ux_test_hcd_sim_host_set_actions(replace_cbw_data_csw); + + rfree = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + cfree = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available; + + ux_test_utility_sim_mem_alloc_fail_all_start(); + status = _ux_host_class_storage_media_recovery_sense_get(storage); + ux_test_utility_sim_mem_alloc_fail_all_stop(); + if (status != UX_MEMORY_INSUFFICIENT) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (rfree != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available || + cfree != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available) + { + printf("ERROR #%d, memory leap!\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_media_recovery_sense_get - transfer error\n"); + cbw_fail_sim = UX_TRUE; + ux_test_hcd_sim_host_set_actions(replace_cbw_data_csw); + status = _ux_host_class_storage_media_recovery_sense_get(storage); + if (status == UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + cbw_fail_sim = UX_FALSE; + + /* Wait a while so the thread goes. */ + _ux_utility_delay_ms(10); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + + if (lun > 1) + return UX_ERROR; + + ram_disk_read_sent = UX_TRUE; + if (ram_disk_read_status != UX_SUCCESS) + { + if (media_status != UX_NULL) + *media_status = ram_disk_read_media_status; + + return ram_disk_read_status; + } + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + + if (lun > 1) + return UX_ERROR; + + ram_disk_write_sent = UX_TRUE; + if (ram_disk_write_status != UX_SUCCESS) + { + if (media_status != UX_NULL) + *media_status = ram_disk_write_media_status; + + return ram_disk_write_status; + } + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)number_blocks; + (void)lba; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + 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_storage_media_write_test.c b/test/regression/usbx_ux_host_class_storage_media_write_test.c new file mode 100644 index 00000000..0e1bd62b --- /dev/null +++ b/test/regression/usbx_ux_host_class_storage_media_write_test.c @@ -0,0 +1,750 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; +static UCHAR cbw_buffer[UX_SLAVE_CLASS_STORAGE_CBW_LENGTH]; +static UCHAR csw_buffer[UX_SLAVE_CLASS_STORAGE_CSW_LENGTH]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static UINT ram_disk_read_status = UX_SUCCESS; +static ULONG ram_disk_read_media_status = 0; +static CHAR ram_disk_read_sent = 0; + +static UINT ram_disk_write_status = UX_SUCCESS; +static ULONG ram_disk_write_media_status = 0; +static CHAR ram_disk_write_sent = 0; + +static CHAR ram_disk_flush = 0; +static UINT ram_disk_flush_status = UX_SUCCESS; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + +static UX_TEST_SETUP _GetMaxLun = UX_TEST_SETUP_STORAGE_GetMaxLun; + +static UX_TEST_HCD_SIM_ACTION stall_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_TRANSFER_STALLED, + UX_TRANSFER_STALLED, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION length_error_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 2, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION replaced_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION fail_bulk_out[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_ERROR, + UX_ERROR, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION fail_2nd_bulk_out[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_SUCCESS, + UX_SUCCESS, UX_NULL, + UX_TRUE}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_ERROR, + UX_ERROR, UX_NULL}, +{ 0 } +}; + +static VOID sending_cbw(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UCHAR *cbw = (UCHAR *)storage -> ux_host_class_storage_cbw; +UX_TRANSFER *transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + + + _ux_utility_memory_copy(cbw_buffer, cbw, 31); + + /* Prepare CSW. */ + _ux_utility_memory_copy(csw_buffer + 0, cbw_buffer + 0, 4); /* dCBWSignature -> dCSWSignature */ + _ux_utility_memory_copy(csw_buffer + 4, cbw_buffer + 4, 4); /* dCBWTag -> dCSWTag */ + _ux_utility_memory_set (csw_buffer + 8, 0x00, 4); /* dCSWDataResidue <= 0 */ + _ux_utility_memory_set (csw_buffer + 12, 0x00, 1); /* bCSWStatus <= 0 */ + + _ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); +} + +static VOID getting_data(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TRANSFER *transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + + _ux_utility_long_put(csw_buffer + 8, 1); /* dCSWDataResidue <= 1 for error test */ + _ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); +} + +static VOID getting_csw(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UCHAR *csw = (UCHAR *)storage -> ux_host_class_storage_csw; +UX_TRANSFER *transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + + _ux_utility_memory_copy(csw, csw_buffer, 13); + _ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); +} + +static UX_TEST_HCD_SIM_ACTION replace_cbw_data_csw[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 31, UX_SUCCESS, + UX_SUCCESS, + .action_func = sending_cbw, + .no_return = UX_FALSE, + .do_after = UX_FALSE}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP | UX_TEST_SIM_REQ_ANSWER, 0x81, buffer, 63, UX_SUCCESS, + UX_SUCCESS, + .action_func = getting_data, + .no_return = UX_FALSE, + .do_after = UX_FALSE}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP | UX_TEST_SIM_REQ_ANSWER, 0x81, csw_buffer, 13, UX_SUCCESS, + UX_SUCCESS, + .action_func = getting_csw, + .no_return = UX_FALSE, + .do_after = UX_FALSE}, +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_storage_media_write_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_storage_media_write Test...................... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 2; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_parameter); + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + // status = _ux_test_dcd_sim_slave_initialize(); + status = ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + // 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 #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done (). */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + configuration = device -> ux_device_first_configuration; + interface = configuration -> ux_configuration_first_interface; + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_media_write - SENSE ERROR\n"); + ram_disk_write_status = UX_ERROR; + ram_disk_write_media_status = 0x003A02; + status = _ux_host_class_storage_media_write(storage, 0, 1, buffer); + if (status != UX_HOST_CLASS_STORAGE_SENSE_ERROR) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Wait a while so the thread goes. */ + _ux_utility_delay_ms(10); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + + if (lun > 1) + return UX_ERROR; + + ram_disk_read_sent = UX_TRUE; + if (ram_disk_read_status != UX_SUCCESS) + { + if (media_status != UX_NULL) + *media_status = ram_disk_read_media_status; + + return ram_disk_read_status; + } + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + + if (lun > 1) + return UX_ERROR; + + ram_disk_write_sent = UX_TRUE; + if (ram_disk_write_status != UX_SUCCESS) + { + if (media_status != UX_NULL) + *media_status = ram_disk_write_media_status; + + return ram_disk_write_status; + } + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)number_blocks; + (void)lba; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + 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_storage_request_sense_test.c b/test/regression/usbx_ux_host_class_storage_request_sense_test.c new file mode 100644 index 00000000..468d373c --- /dev/null +++ b/test/regression/usbx_ux_host_class_storage_request_sense_test.c @@ -0,0 +1,587 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static CHAR ram_disk_flush = 0; +static UINT ram_disk_flush_status = UX_SUCCESS; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_storage_request_sense_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_storage_request_sense Test.................... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_parameter); + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + // status = _ux_test_dcd_sim_slave_initialize(); + status = ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + // 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 #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done. */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_request_sense - UX_SUCCESS\n"); + status = _ux_host_class_storage_request_sense(storage); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_request_sense - UX_MEMORY_INSUFFICIENT\n"); + ux_test_utility_sim_mem_alloc_fail_all_start(); + status = _ux_host_class_storage_request_sense(storage); + if (status != UX_MEMORY_INSUFFICIENT) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + ux_test_utility_sim_mem_alloc_fail_all_stop(); + + /* Wait a while so the thread goes. */ + _ux_utility_delay_ms(10); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)number_blocks; + (void)lba; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + 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_storage_start_stop_test.c b/test/regression/usbx_ux_host_class_storage_start_stop_test.c new file mode 100644 index 00000000..b216e638 --- /dev/null +++ b/test/regression/usbx_ux_host_class_storage_start_stop_test.c @@ -0,0 +1,869 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; +static UCHAR cbw_buffer[UX_SLAVE_CLASS_STORAGE_CBW_LENGTH]; +static UCHAR cbw_fail_sim = UX_FALSE; +static UCHAR csw_buffer[UX_SLAVE_CLASS_STORAGE_CSW_LENGTH]; +static ULONG csw_sense_sim = 0; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static UINT ram_disk_read_status = UX_SUCCESS; +static ULONG ram_disk_read_media_status = 0; +static CHAR ram_disk_read_sent = 0; + +static UINT ram_disk_write_status = UX_SUCCESS; +static ULONG ram_disk_write_media_status = 0; +static CHAR ram_disk_write_sent = 0; + +static CHAR ram_disk_flush = 0; +static UINT ram_disk_flush_status = UX_SUCCESS; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +static ULONG loop_try = 0; /* 0: no loop */ + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + +struct request_sense_response { + UCHAR valid_error_code; /* 0x70 */ + UCHAR reserved; + UCHAR sense_key; + UCHAR information[4]; + UCHAR additional_sense_length; + UCHAR reserved1[4]; + UCHAR additional_sense_code; + UCHAR additional_sense_code_qualifier; + UCHAR reserved2; + UCHAR reserved3[3]; +}; +static struct request_sense_response request_sense_data = { + .valid_error_code = 0x70, + .sense_key = 0, + .additional_sense_length = 10, + .additional_sense_code = 0, + .additional_sense_code_qualifier = 0 +}; + +static UX_TEST_SETUP _GetMaxLun = UX_TEST_SETUP_STORAGE_GetMaxLun; + +static UX_TEST_HCD_SIM_ACTION stall_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_TRANSFER_STALLED, + UX_TRANSFER_STALLED, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION length_error_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 2, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION replaced_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION fail_bulk_out[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_ERROR, + UX_ERROR, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION fail_2nd_bulk_out[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_SUCCESS, + UX_SUCCESS, UX_NULL, + UX_TRUE}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_ERROR, + UX_ERROR, UX_NULL}, +{ 0 } +}; + +static VOID cbw_general(UCHAR *cbw, UX_TRANSFER *transfer_request) +{ + _ux_utility_memory_copy(cbw_buffer, cbw, 31); + // printf("CBW >"); for(int i = 0; i < 31; i ++) printf(" %2x", cbw[i]); printf("\n"); + + /* Prepare CSW. */ + _ux_utility_memory_copy(csw_buffer + 0, cbw_buffer + 0, 4); /* dCBWSignature -> dCSWSignature */ + _ux_utility_memory_copy(csw_buffer + 4, cbw_buffer + 4, 4); /* dCBWTag -> dCSWTag */ + _ux_utility_memory_set (csw_buffer + 8, 0x00, 4); /* dCSWDataResidue <= 0 */ + // _ux_utility_memory_set (csw_buffer + 12, 0x00, 1); /* bCSWStatus <= 0 */ + + transfer_request->ux_transfer_request_completion_code = UX_SUCCESS; +} + +static VOID cbw_start_stop(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UCHAR *cbw = (UCHAR *)storage -> ux_host_class_storage_cbw; +UX_TRANSFER *transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + + + cbw_general(cbw, transfer_request); + _ux_utility_memory_set (csw_buffer + 12, 0x01, 1); /* bCSWStatus <= 1 */ + + if (!cbw_fail_sim) + _ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); +} +static VOID csw_start_stop(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UCHAR *csw = (UCHAR *)storage -> ux_host_class_storage_csw; +UX_TRANSFER *transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + + _ux_utility_memory_copy(csw, csw_buffer, 13); + // printf("CSW >"); for(int i = 0; i < 13; i ++) printf(" %2x", csw[i]); printf("\n"); + + _ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); +} + +static VOID cbw_request_sense(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UCHAR *cbw = (UCHAR *)storage -> ux_host_class_storage_cbw; +UX_TRANSFER *transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + + + cbw_general(cbw, transfer_request); + _ux_utility_memory_set (csw_buffer + 12, 0x00, 1); /* bCSWStatus <= 0 */ + _ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); +} +static VOID data_request_sense(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UCHAR *cbw = (UCHAR *)storage -> ux_host_class_storage_cbw; +UX_TRANSFER *transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; +UCHAR *sense_data = transfer_request->ux_transfer_request_data_pointer; + + + _ux_utility_memory_copy(sense_data, &request_sense_data, sizeof(request_sense_data)); + // printf("DTA >"); for(int i = 0; i < sizeof(request_sense_data); i ++) printf(" %2x", sense_data[i]); printf("\n"); + transfer_request->ux_transfer_request_actual_length = sizeof(request_sense_data); + transfer_request->ux_transfer_request_completion_code = UX_SUCCESS; + _ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); +} + +static VOID csw_request_sense(struct UX_TEST_ACTION_STRUCT *action, VOID *params); +static UX_TEST_HCD_SIM_ACTION replace_start_stop_sense_loop[] = { +/* 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, 31, UX_SUCCESS, + UX_SUCCESS, + .action_func = cbw_start_stop, + .no_return = UX_FALSE, + .do_after = UX_FALSE}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP | UX_TEST_SIM_REQ_ANSWER, 0x81, csw_buffer, 13, UX_SUCCESS, + UX_SUCCESS, + .action_func = csw_start_stop, + .no_return = UX_FALSE, + .do_after = UX_FALSE}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 31, UX_SUCCESS, + UX_SUCCESS, + .action_func = cbw_request_sense, + .no_return = UX_FALSE, + .do_after = UX_FALSE}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x81, UX_NULL, 0, UX_SUCCESS, + UX_SUCCESS, + .action_func = data_request_sense, + .no_return = UX_FALSE, + .do_after = UX_FALSE}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP | UX_TEST_SIM_REQ_ANSWER, 0x81, csw_buffer, 13, UX_SUCCESS, + UX_SUCCESS, + .action_func = csw_request_sense, + .no_return = UX_FALSE, + .do_after = UX_FALSE}, +{ 0 } +}; + + +static VOID csw_request_sense(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UCHAR *csw = (UCHAR *)storage -> ux_host_class_storage_csw; +UX_TRANSFER *transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + + _ux_utility_memory_copy(csw, csw_buffer, 13); + // printf("CSW1:"); for(int i = 0; i < 13; i ++) printf(" %2x", csw[i]); printf("\n"); + + if (loop_try) { + + ux_test_hcd_sim_host_set_actions(replace_start_stop_sense_loop); + + if (loop_try != 0xFFFFFFFF) + loop_try --; + } + + _ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); +} + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_storage_start_stop_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_storage_start_stop Test....................... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 2; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_thread_media_flush; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read_only_flag = UX_FALSE; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_flush = demo_thread_media_flush; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read_only_flag = UX_FALSE; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_parameter); + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + // status = _ux_test_dcd_sim_slave_initialize(); + status = ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + // 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 #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +UX_SLAVE_DEVICE *slave_device; +UX_SLAVE_CLASS *slave_class; +UX_SLAVE_CLASS_STORAGE *slave_storage; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done (). */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + configuration = device -> ux_device_first_configuration; + interface = configuration -> ux_configuration_first_interface; + + slave_device = &_ux_system_slave->ux_system_slave_device; + slave_class = _ux_system_slave->ux_system_slave_interface_class_array[0]; + slave_storage = (UX_SLAVE_CLASS_STORAGE *)slave_class->ux_slave_class_instance; + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_start_stop - UX_SUCCESS\n"); + status = _ux_host_class_storage_start_stop(storage, UX_SUCCESS); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_start_stop - transfer error\n"); + cbw_fail_sim = UX_TRUE; + ux_test_hcd_sim_host_set_actions(replace_start_stop_sense_loop); + status = _ux_host_class_storage_start_stop(storage, 0); + if (status == UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + cbw_fail_sim = UX_FALSE; + ux_test_hcd_sim_host_set_actions(UX_NULL); + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_start_stop - sense code error\n"); + loop_try = 60; + request_sense_data.sense_key = 0x2; + ux_test_hcd_sim_host_set_actions(replace_start_stop_sense_loop); + status = _ux_host_class_storage_start_stop(storage, 0); + if (status == UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + ux_test_hcd_sim_host_set_actions(UX_NULL); + + /* Wait a while so the thread goes. */ + _ux_utility_delay_ms(10); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + + if (lun > 1) + return UX_ERROR; + + ram_disk_read_sent = UX_TRUE; + if (ram_disk_read_status != UX_SUCCESS) + { + if (media_status != UX_NULL) + *media_status = ram_disk_read_media_status; + + return ram_disk_read_status; + } + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + + if (lun > 1) + return UX_ERROR; + + ram_disk_write_sent = UX_TRUE; + if (ram_disk_write_status != UX_SUCCESS) + { + if (media_status != UX_NULL) + *media_status = ram_disk_write_media_status; + + return ram_disk_write_status; + } + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)number_blocks; + (void)lba; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + 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_storage_thread_entry_test.c b/test/regression/usbx_ux_host_class_storage_thread_entry_test.c new file mode 100644 index 00000000..4adb8caa --- /dev/null +++ b/test/regression/usbx_ux_host_class_storage_thread_entry_test.c @@ -0,0 +1,882 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static ULONG ram_disk_status_loop = 0; +static ULONG ram_disk_status_sent = 0; + +static UINT ram_disk_read_status = UX_SUCCESS; +static ULONG ram_disk_read_media_status = 0; +static CHAR ram_disk_read_sent = 0; + +static CHAR ram_disk_flush = 0; +static UINT ram_disk_flush_status = UX_SUCCESS; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +static ULONG semaphore_error_start; +static ULONG semaphore_counter; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + +#if defined(UX_HOST_CLASS_STORAGE_NO_FILEX) +FX_MEDIA *_ux_host_class_storage_driver_media(INT i); +VOID _ux_host_class_storage_driver_entry(FX_MEDIA *media); +VOID _ux_host_class_storage_media_insert(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG format_open); +VOID _ux_host_class_storage_media_remove(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +FX_MEDIA *_ux_host_class_storage_media_fx_media(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); +UCHAR *_ux_host_class_storage_media_fx_media_memory(UX_HOST_CLASS_STORAGE_MEDIA *storage_media); + +static UINT ux_test_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + + switch(event) + { + + case UX_STORAGE_MEDIA_INSERTION: + _ux_host_class_storage_media_insert((UX_HOST_CLASS_STORAGE_MEDIA*)inst, 1); + break; + + case UX_STORAGE_MEDIA_REMOVAL: + _ux_host_class_storage_media_remove((UX_HOST_CLASS_STORAGE_MEDIA*)inst); + _ux_host_class_storage_media_fx_media((UX_HOST_CLASS_STORAGE_MEDIA*)inst) -> fx_media_id = 0;/* Testing code is checking ID to detect removal. */ + break; + + default: + break; + } + + return 0; +} +#else +#define ux_test_system_host_change_function UX_NULL +#endif + +static UX_TEST_SETUP _GetMaxLun = UX_TEST_SETUP_STORAGE_GetMaxLun; + +static UX_TEST_HCD_SIM_ACTION stall_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_TRANSFER_STALLED, + UX_TRANSFER_STALLED, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION length_error_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 2, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION replaced_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION fail_bulk_out[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_ERROR, + UX_ERROR, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION fail_2nd_bulk_out[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_SUCCESS, + UX_SUCCESS, UX_NULL, + UX_TRUE}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_ERROR, + UX_ERROR, UX_NULL}, +{ 0 } +}; + +static void ux_host_class_storage_semaphore_callback(UX_TEST_ACTION *action, VOID *params) +{ + +UX_TEST_OVERRIDE_TX_SEMAPHORE_GET_PARAMS *semaphore_get_param = params; + + // printf("semaphore_call:%p\n", semaphore_get_param->semaphore_ptr); + if (semaphore_error_start == 0xFFFFFFFF) + return; + + semaphore_counter ++; + if (semaphore_counter > semaphore_error_start) + { + // printf("!! Semaphore del: %p\n", semaphore_get_param->semaphore_ptr); + _ux_utility_semaphore_delete(semaphore_get_param->semaphore_ptr); + } +} + +static UX_TEST_ACTION ux_host_class_storage_semaphore_get_hook[] = +{ + { + .usbx_function = UX_TEST_OVERRIDE_TX_SEMAPHORE_GET, + .semaphore_ptr = UX_NULL, + .wait_option = TX_WAIT_FOREVER, + .do_after = UX_FALSE, + .action_func = ux_host_class_storage_semaphore_callback, + }, +{ 0 }, +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_storage_thread_entry_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_storage_thread_entry Test..................... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_flush = demo_thread_media_flush; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_parameter); + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + // status = _ux_test_dcd_sim_slave_initialize(); + status = ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(ux_test_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + // 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 #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +FX_MEDIA *media; +FX_MEDIA *media1; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +ULONG temp; +ULONG rfree, cfree; +TX_SEMAPHORE *semaphore_ptr; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done (). */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + media = &storage_media[0].ux_host_class_storage_media; + media1 = &storage_media[1].ux_host_class_storage_media; +#else + media = _ux_host_class_storage_driver_media(0); + media1 = _ux_host_class_storage_driver_media(1); +#endif + // printf("media: %lx, %lx\n", media->fx_media_id, media1->fx_media_id); + + /* Pause the class driver thread. */ + // _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + configuration = device -> ux_device_first_configuration; + interface = configuration -> ux_configuration_first_interface; + + rfree = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + cfree = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available; + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_thread_entry - ux_host_class_storage_semaphore FAIL\n"); + _ux_utility_semaphore_delete(&storage -> ux_host_class_storage_semaphore); + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_THREAD_SLEEP_TIME*2); + _ux_utility_semaphore_create(&storage -> ux_host_class_storage_semaphore, "ux_host_class_storage_semaphore", 1); + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_thread_entry - ux_host_class_storage_lun_types invalid\n"); + storage -> ux_host_class_storage_lun_types[0] = 0xEE; + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_THREAD_SLEEP_TIME*2); + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_thread_entry - ux_host_class_storage_lun_types UX_HOST_CLASS_STORAGE_MEDIA_OPTICAL_DISK\n"); + storage -> ux_host_class_storage_lun_types[0] = UX_HOST_CLASS_STORAGE_MEDIA_OPTICAL_DISK; + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_THREAD_SLEEP_TIME*2); + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_thread_entry - ux_host_class_storage_lun_types UX_HOST_CLASS_STORAGE_MEDIA_IOMEGA_CLICK\n"); + storage -> ux_host_class_storage_lun_types[0] = UX_HOST_CLASS_STORAGE_MEDIA_IOMEGA_CLICK; + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_THREAD_SLEEP_TIME*2); + + media->fx_media_driver_info = UX_NULL; + ram_disk_status = UX_ERROR; + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_thread_entry - _SENSE_KEY_NOT_READY - media driver info error\n"); + ram_disk_media_status = 0x003A02; + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_THREAD_SLEEP_TIME*4); + + // printf("media: %lx, %lx\n", media->fx_media_id, media1->fx_media_id); + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_thread_entry - _SENSE_KEY_UNIT_ATTENTION - media driver info error\n"); + ram_disk_status_sent = 0; + ram_disk_status_loop = 3; + ram_disk_media_status = UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8); + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_THREAD_SLEEP_TIME*6); + + media->fx_media_driver_info = (VOID *)storage; + + // if (media1->fx_media_id != 0) + // { + // printf("ERROR #%d\n", __LINE__); + // } + // printf("media: %lx, %lx\n", media->fx_media_id, media1->fx_media_id); + + // printf(">>>>>>>>>>>>>>> ux_host_class_storage_thread_entry - re-plug\n"); + // ux_test_hcd_sim_host_disconnect(); + // ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + // _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY*2); + + // printf("media: %lx, %lx\n", media->fx_media_id, media1->fx_media_id); + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_thread_entry - ux_host_class_storage_semaphore FAIL\n"); + semaphore_ptr = &storage -> ux_host_class_storage_semaphore; + // printf("storage:%p, semaphore: %p\n", storage, semaphore_ptr); + ux_host_class_storage_semaphore_get_hook[0].semaphore_ptr = semaphore_ptr; + ux_test_link_hooks_from_array(ux_host_class_storage_semaphore_get_hook); + + for(temp = 0; temp < 8; temp ++) + { + + + stepinfo("%ld --- ready0\n", temp); + /* Attention & ready */ + semaphore_error_start = 0xFFFFFFFF; + semaphore_counter = 0; + + ram_disk_status_sent = 0; + ram_disk_status_loop = 0xFFFFFFFF; + ram_disk_status = UX_ERROR; + ram_disk_media_status = UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8); + + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_THREAD_SLEEP_TIME*6); + + + stepinfo("%ld --- not ready\n", temp); + /* Not ready. */ + semaphore_error_start = temp; + semaphore_counter = 0; + + ram_disk_status_sent = 0; + ram_disk_status_loop = 0xFFFFFFFF; + ram_disk_status = UX_ERROR; + ram_disk_media_status = 0x003A02; + + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_THREAD_SLEEP_TIME*6); + if (semaphore_ptr->tx_semaphore_id != 0) + { + printf("ERROR #%d: semaphore not deleted\n", __LINE__); + test_control_return(1); + } + _ux_utility_semaphore_create(&storage -> ux_host_class_storage_semaphore, "ux_host_class_storage_semaphore", 1); + + + stepinfo("%ld --- ready1\n", temp); + /* Attention & ready */ + semaphore_error_start = 0xFFFFFFFF; + semaphore_counter = 0; + + ram_disk_status_sent = 0; + ram_disk_status_loop = 0xFFFFFFFF; + ram_disk_status = UX_ERROR; + ram_disk_media_status = UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8); + + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_THREAD_SLEEP_TIME*6); + + + stepinfo("%ld --- attention!\n", temp); + /* Attention! */ + semaphore_error_start = temp; + semaphore_counter = 0; + + ram_disk_status_sent = 0; + ram_disk_status_loop = 1; + ram_disk_status = UX_ERROR; + ram_disk_media_status = UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8); + + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_THREAD_SLEEP_TIME*6); + if (semaphore_ptr->tx_semaphore_id != 0) + { + printf("ERROR #%d: semaphore not deleted\n", __LINE__); + test_control_return(1); + } + _ux_utility_semaphore_create(&storage -> ux_host_class_storage_semaphore, "ux_host_class_storage_semaphore", 1); + + } + + ux_test_remove_hooks_from_array(ux_host_class_storage_semaphore_get_hook); + +#if defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_thread_entry - _SENSE_KEY_UNIT_ATTENTION - no host callback\n"); + _ux_system_host -> ux_system_host_change_function = UX_NULL; + ram_disk_status = UX_ERROR; + ram_disk_status_sent = 0; + ram_disk_status_loop = 2; + ram_disk_media_status = UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8); + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_THREAD_SLEEP_TIME*6); + _ux_system_host -> ux_system_host_change_function = ux_test_system_host_change_function; +#endif + + /* Wait a while so the thread goes. */ + _ux_utility_delay_ms(10); + + _ux_utility_thread_delete(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + ram_disk_status_sent ++; + + if (ram_disk_status_loop == 0xFFFFFFFF || ram_disk_status_sent >= ram_disk_status_loop) + { + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + } + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + + if (lun > 1) + return UX_ERROR; + + ram_disk_read_sent = UX_TRUE; + + if (ram_disk_read_status != UX_SUCCESS) + { + if (media_status != UX_NULL) + *media_status = ram_disk_read_media_status; + + return ram_disk_read_status; + } + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)number_blocks; + (void)lba; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + 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_storage_transport_bo_test.c b/test/regression/usbx_ux_host_class_storage_transport_bo_test.c new file mode 100644 index 00000000..2b3b0863 --- /dev/null +++ b/test/regression/usbx_ux_host_class_storage_transport_bo_test.c @@ -0,0 +1,1019 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_storage.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" +#include "ux_host_class_storage.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_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +/* Define local/extern function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +void _fx_ram_drive_format(ULONG disk_size, UINT sector_size, UINT sectors_per_cluster, + UINT fat_entries, UINT root_directory_entries); + +static void demo_thread_entry(ULONG); +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT demo_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status); + +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; +static UCHAR cbw_buffer[UX_SLAVE_CLASS_STORAGE_CBW_LENGTH]; +static UCHAR csw_buffer[UX_SLAVE_CLASS_STORAGE_CSW_LENGTH]; +static UCHAR csw_start_mem_error = 0; + +static ULONG error_counter; + +static TX_THREAD demo_thread; + +static UX_HOST_CLASS_STORAGE *storage; +static UX_SLAVE_CLASS_STORAGE_PARAMETER global_storage_parameter; + +static FX_MEDIA ram_disk_media1; +static FX_MEDIA ram_disk_media2; +static CHAR ram_disk_buffer1[512]; +static CHAR ram_disk_buffer2[512]; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static CHAR ram_disk_memory2[UX_RAM_DISK_SIZE]; +static CHAR *ram_disk_memory[] = +{ + ram_disk_memory1, ram_disk_memory2 +}; +static UINT ram_disk_status = UX_SUCCESS; +static ULONG ram_disk_media_status = 0; +static CHAR ram_disk_status_sent = 0; + +static UINT ram_disk_read_status = UX_SUCCESS; +static ULONG ram_disk_read_media_status = 0; +static CHAR ram_disk_read_sent = 0; + +static UINT ram_disk_write_status = UX_SUCCESS; +static ULONG ram_disk_write_media_status = 0; +static CHAR ram_disk_write_sent = 0; + +static CHAR ram_disk_flush = 0; +static UINT ram_disk_flush_status = UX_SUCCESS; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_alloc_count; + +static ULONG rsc_storage_sem_usage; +static ULONG rsc_storage_sem_get_count; +static ULONG rsc_storage_mutex_usage; +static ULONG rsc_storage_mem_alloc_count; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +static ULONG loop_try = 0; /* 0: no loop */ + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00, + + }; + + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, 0x0a, + 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69, + 0x73, 0x6b, + + /* 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 + }; + +struct request_sense_response { + UCHAR valid_error_code; /* 0x70 */ + UCHAR reserved; + UCHAR sense_key; + UCHAR information[4]; + UCHAR additional_sense_length; + UCHAR reserved1[4]; + UCHAR additional_sense_code; + UCHAR additional_sense_code_qualifier; + UCHAR reserved2; + UCHAR reserved3[3]; +}; +static struct request_sense_response request_sense_data = { + .valid_error_code = 0x70, + .sense_key = 0, + .additional_sense_length = 10, + .additional_sense_code = 0, + .additional_sense_code_qualifier = 0 +}; + +static VOID cbw_semaphore_success(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TRANSFER *transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + + + transfer_request->ux_transfer_request_actual_length = 31; + transfer_request->ux_transfer_request_completion_code = UX_SUCCESS; + _ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); +} + +static VOID cbw_semaphore_stall(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TRANSFER *transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + + + transfer_request->ux_transfer_request_completion_code = UX_TRANSFER_STALLED; + _ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); +} + +static VOID csw_semaphore_stall(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UX_TRANSFER *transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + + transfer_request->ux_transfer_request_completion_code = UX_TRANSFER_STALLED; + _ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); +} + +static UX_TEST_SETUP _GetMaxLun = UX_TEST_SETUP_STORAGE_GetMaxLun; + +static UX_TEST_HCD_SIM_ACTION stall_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_TRANSFER_STALLED, + UX_TRANSFER_STALLED, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION length_error_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 2, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION replaced_GetMaxLun[] = { +/* 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, &_GetMaxLun, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ | UX_TEST_SIM_REQ_ANSWER, 0, buffer, 1, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION fail_bulk_out[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_ERROR, + UX_ERROR, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION stall_bulk_out[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_TRANSFER_STALLED, + UX_SUCCESS, cbw_semaphore_stall}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION stall_bulk_out2[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_TRANSFER_STALLED, + UX_SUCCESS, cbw_semaphore_stall}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_TRANSFER_STALLED, + UX_SUCCESS, cbw_semaphore_stall}, +{ 0 } +}; + + +static UX_TEST_HCD_SIM_ACTION fail_data_request[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_SUCCESS, + UX_SUCCESS, cbw_semaphore_success}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x81, UX_NULL, 0, UX_ERROR, + UX_ERROR, UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION fail_data_wait[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_SUCCESS, + UX_SUCCESS, cbw_semaphore_success}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x81, UX_NULL, 0, UX_SUCCESS, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; +#define fail_csw_wait fail_data_wait + +static UX_TEST_HCD_SIM_ACTION stall_csw_wait2[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_SUCCESS, + UX_SUCCESS, cbw_semaphore_success}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x81, UX_NULL, 0, UX_SUCCESS, + UX_SUCCESS, csw_semaphore_stall}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x81, UX_NULL, 0, UX_SUCCESS, + UX_SUCCESS, csw_semaphore_stall}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION csw_transfer_fail[] = { +/* 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, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x02, UX_NULL, 0, UX_SUCCESS, + UX_SUCCESS, cbw_semaphore_success}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_MATCH_EP, 0x81, UX_NULL, 0, UX_SUCCESS, + UX_ERROR, UX_NULL, 0}, +{ 0 } +}; + +static VOID cbw_replace(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UCHAR *cbw = (UCHAR *)storage -> ux_host_class_storage_cbw; +UX_TRANSFER *transfer_request = &storage -> ux_host_class_storage_bulk_out_endpoint -> ux_endpoint_transfer_request; + + + _ux_utility_memory_copy(cbw_buffer, cbw, 31); + // printf("CBW >"); for(int i = 0; i < 31; i ++) printf(" %2x", cbw[i]); printf("\n"); + + /* Prepare CSW. */ + _ux_utility_memory_copy(csw_buffer + 0, cbw_buffer + 0, 4); /* dCBWSignature -> dCSWSignature */ + _ux_utility_memory_copy(csw_buffer + 4, cbw_buffer + 4, 4); /* dCBWTag -> dCSWTag */ + // _ux_utility_memory_set (csw_buffer + 8, 0x00, 4); /* dCSWDataResidue <= 0 */ + // _ux_utility_memory_set (csw_buffer + 12, 0x00, 1); /* bCSWStatus <= 0 */ + + transfer_request->ux_transfer_request_completion_code = UX_SUCCESS; + _ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); +} + +static VOID csw_replace(struct UX_TEST_ACTION_STRUCT *action, VOID *params) +{ + +UCHAR *csw = (UCHAR *)storage -> ux_host_class_storage_csw; +UX_TRANSFER *transfer_request = &storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request; + + + _ux_utility_memory_copy(csw, csw_buffer, 13); + // printf("CSW >"); for(int i = 0; i < 13; i ++) printf(" %2x", csw[i]); printf("\n"); + + if (csw_start_mem_error) + ux_test_utility_sim_mem_alloc_fail_all_start(); + + _ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore); +} + +static UX_TEST_HCD_SIM_ACTION replace_cbw_csw[] = { +/* 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, 31, UX_SUCCESS, + UX_SUCCESS, + .action_func = cbw_replace, + .no_return = UX_FALSE, + .do_after = UX_FALSE}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP | UX_TEST_SIM_REQ_ANSWER, 0x81, csw_buffer, 13, UX_SUCCESS, + UX_SUCCESS, + .action_func = csw_replace, + .no_return = UX_FALSE, + .do_after = UX_FALSE}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION replace_cbw_csw_ep0stall[] = { +/* 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, 31, UX_SUCCESS, + UX_SUCCESS, + .action_func = cbw_replace, + .no_return = UX_FALSE, + .do_after = UX_FALSE}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP | UX_TEST_SIM_REQ_ANSWER, 0x81, csw_buffer, 13, UX_SUCCESS, + UX_SUCCESS, + .action_func = csw_replace, + .no_return = UX_FALSE, + .do_after = UX_FALSE}, +{ UX_HCD_TRANSFER_REQUEST, UX_NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x00, UX_NULL, 0, UX_TRANSFER_STALLED, + UX_TRANSFER_STALLED, + .action_func = UX_NULL, + .no_return = UX_FALSE, + .do_after = UX_FALSE}, +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 host_storage_instance_get(ULONG timeout_x10ms) +{ + +UINT status; +UX_HOST_CLASS *class; + + + /* Find the main storage container */ + status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* Get storage instance, wait it to be live and media attached. */ + do + { + if (timeout_x10ms) + { + ux_utility_delay_ms(10); + if (timeout_x10ms != 0xFFFFFFFF) + timeout_x10ms --; + } + + status = ux_host_stack_class_instance_get(class, 0, (void **) &storage); + if (status == UX_SUCCESS) + { + if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE && + class -> ux_host_class_media != UX_NULL) + return(UX_SUCCESS); + } + + } while(timeout_x10ms > 0); + + return(UX_ERROR); +} + +static UINT sleep_break_on_error(VOID) +{ + + if (error_callback_counter >= 3) + return error_callback_counter; + + return UX_SUCCESS; +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_storage_transport_bo_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_class_storage_transport_bo Test..................... "); + stepinfo("\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + ux_utility_memory_set(ram_disk_memory2, 0, UX_RAM_DISK_SIZE); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Change the ram drive values. */ + fx_media_format(&ram_disk_media1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + fx_media_format(&ram_disk_media2, _fx_ram_driver, ram_disk_memory2, ram_disk_buffer2, 512, "RAM DISK2", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + 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); + } + + /* Store the number of LUN in this device storage instance. */ + global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 2; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = demo_thread_media_flush; + global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read_only_flag = UX_FALSE; + + /* Initialize the storage class parameters for reading/writing to the second Flash Disk. */ + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_block_length = 512; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_type = 0; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_removable_flag = 0x80; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read = demo_thread_media_read; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_write = demo_thread_media_write; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_status = demo_thread_media_status; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_flush = demo_thread_media_flush; + global_storage_parameter.ux_slave_class_storage_parameter_lun[1].ux_slave_class_storage_media_read_only_flag = UX_FALSE; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 0, (VOID *)&global_storage_parameter); + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + // status = _ux_test_dcd_sim_slave_initialize(); + status = ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register storage class. */ + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); + 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); + // 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 #%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 #%d\n", __LINE__); + test_control_return(1); + } + +} + +static UINT storage_media_status_wait(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG status, ULONG timeout) +{ + + while(1) + { +#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + if (storage_media->ux_host_class_storage_media_status == status) + return UX_SUCCESS; +#else + if ((status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED && + storage_media->ux_host_class_storage_media_storage != UX_NULL) || + (status == UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED && + storage_media->ux_host_class_storage_media_storage == UX_NULL)) + return(UX_SUCCESS); +#endif + if (timeout == 0) + break; + if (timeout != 0xFFFFFFFF) + timeout --; + _ux_utility_delay_ms(10); + } + return UX_ERROR; +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_STORAGE_MEDIA *storage_media; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +UX_SLAVE_DEVICE *slave_device; +UX_SLAVE_CLASS *slave_class; +UX_SLAVE_CLASS_STORAGE *slave_storage; + + + /* Find the storage class. */ + status = host_storage_instance_get(100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Wait enough time for media mounting. */ + _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY); + + class = storage->ux_host_class_storage_class; + storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *)class->ux_host_class_media; + + /* Confirm media enum done (). */ + status = storage_media_status_wait(storage_media, UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED, 100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Pause the class driver thread. */ + _ux_utility_thread_suspend(&((UX_HOST_CLASS_STORAGE_EXT*)class->ux_host_class_ext)->ux_host_class_thread); + + configuration = device -> ux_device_first_configuration; + interface = configuration -> ux_configuration_first_interface; + + slave_device = &_ux_system_slave->ux_system_slave_device; + slave_class = _ux_system_slave->ux_system_slave_interface_class_array[0]; + slave_storage = (UX_SLAVE_CLASS_STORAGE *)slave_class->ux_slave_class_instance; + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_transport_bo - CBW STALL retry (2)\n"); + ux_test_hcd_sim_host_set_actions(stall_bulk_out); + status = _ux_host_class_storage_unit_ready_test(storage); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + ux_test_hcd_sim_host_set_actions(stall_bulk_out2); + status = _ux_host_class_storage_unit_ready_test(storage); + if (status == UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_transport_bo - DATA request error\n"); + ux_test_hcd_sim_host_set_actions(fail_data_request); + status = _ux_host_class_storage_request_sense(storage); + if (status == UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_transport_bo - DATA timeout\n"); + ux_test_hcd_sim_host_set_actions(fail_data_wait); + status = _ux_host_class_storage_request_sense(storage); + if (status == UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_transport_bo - CSW timeout\n"); + ux_test_hcd_sim_host_set_actions(fail_csw_wait); + status = _ux_host_class_storage_unit_ready_test(storage); + if (status == UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_transport_bo - CSW status phase error 1st try\n"); + csw_buffer[UX_HOST_CLASS_STORAGE_CSW_STATUS] = UX_HOST_CLASS_STORAGE_CSW_PHASE_ERROR; + ux_test_hcd_sim_host_set_actions(replace_cbw_csw); + status = _ux_host_class_storage_unit_ready_test(storage); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_transport_bo - CSW status residue 1st try\n"); + csw_buffer[UX_HOST_CLASS_STORAGE_CSW_STATUS] = UX_HOST_CLASS_STORAGE_CSW_PASSED; + csw_buffer[UX_HOST_CLASS_STORAGE_CSW_DATA_RESIDUE] = 0x01; + ux_test_hcd_sim_host_set_actions(replace_cbw_csw); + status = _ux_host_class_storage_unit_ready_test(storage); + if (status != UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_transport_bo - RequestSense - UX_MEMORY_INSUFFICIENT\n"); + csw_start_mem_error = 1; + csw_buffer[UX_HOST_CLASS_STORAGE_CSW_STATUS] = UX_HOST_CLASS_STORAGE_CSW_PASSED; + csw_buffer[UX_HOST_CLASS_STORAGE_CSW_DATA_RESIDUE] = 0x01; + ux_test_hcd_sim_host_set_actions(replace_cbw_csw); + status = _ux_host_class_storage_unit_ready_test(storage); + if (status != UX_MEMORY_INSUFFICIENT) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + csw_start_mem_error = 0; + ux_test_utility_sim_mem_alloc_fail_all_stop(); + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_transport_bo - RequestSense - GetHalt request error\n"); + csw_buffer[UX_HOST_CLASS_STORAGE_CSW_STATUS] = UX_HOST_CLASS_STORAGE_CSW_PASSED; + csw_buffer[UX_HOST_CLASS_STORAGE_CSW_DATA_RESIDUE] = 0x01; + ux_test_hcd_sim_host_set_actions(replace_cbw_csw_ep0stall); + status = _ux_host_class_storage_unit_ready_test(storage); + if (status == UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + // stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_transport_bo - RequestSense - ClearHalt request error\n"); + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_transport_bo - CSW stall twice\n"); + ux_test_hcd_sim_host_set_actions(stall_csw_wait2); + status = _ux_host_class_storage_unit_ready_test(storage); + if (status == UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>> ux_host_class_storage_transport_bo - CSW transfer fails\n"); + ux_test_hcd_sim_host_set_actions(csw_transfer_fail); + status = _ux_host_class_storage_unit_ready_test(storage); + if (status == UX_SUCCESS) + { + printf("ERROR #%d, code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Wait a while so the thread goes. */ + _ux_utility_delay_ms(10); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_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_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +UINT status = ram_disk_status; + + + (void)storage; + (void)media_id; + + if (media_status) + *media_status = ram_disk_media_status; + + /* If there is attention, it must be changed to ready after reported. */ + if (ram_disk_media_status == (UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8))) + { + ram_disk_status = UX_SUCCESS; + ram_disk_media_status = 0; + } + else + ram_disk_status_sent = UX_TRUE; + + return status; +} + +static UINT demo_thread_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + + if (lun > 1) + return UX_ERROR; + + ram_disk_read_sent = UX_TRUE; + if (ram_disk_read_status != UX_SUCCESS) + { + if (media_status != UX_NULL) + *media_status = ram_disk_read_media_status; + + return ram_disk_read_status; + } + + ux_utility_memory_copy(data_pointer, &ram_disk_memory[lun][lba * 512], number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + + if (lun > 1) + return UX_ERROR; + + ram_disk_write_sent = UX_TRUE; + if (ram_disk_write_status != UX_SUCCESS) + { + if (media_status != UX_NULL) + *media_status = ram_disk_write_media_status; + + return ram_disk_write_status; + } + + ux_utility_memory_copy(&ram_disk_memory[lun][lba * 512], data_pointer, number_blocks * 512); + + return UX_SUCCESS; +} + +static UINT demo_thread_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + (void)storage; + (void)number_blocks; + (void)lba; + (void)media_status; + + if (lun > 1) + return UX_ERROR; + + 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_basic_tests.c b/test/regression/usbx_ux_host_class_video_basic_tests.c new file mode 100644 index 00000000..41578c75 --- /dev/null +++ b/test/regression/usbx_ux_host_class_video_basic_tests.c @@ -0,0 +1,1186 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_dummy.h" +#include "ux_device_stack.h" +#include "ux_host_class_video.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); + +static VOID ux_test_hcd_entry_should_not_be_called(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_disconnect(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +static VOID ux_test_system_host_enum_hub_function(VOID); + +/* Define global data structures. */ +UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +UX_HOST_CLASS_VIDEO *host_video = UX_NULL; + +ULONG enum_counter; + +ULONG error_counter; + +ULONG set_cfg_counter; + +ULONG rsc_mem_free_on_set_cfg; +ULONG rsc_sem_on_set_cfg; +ULONG rsc_sem_get_on_set_cfg; +ULONG rsc_mutex_on_set_cfg; + +ULONG rsc_enum_sem_usage; +ULONG rsc_enum_sem_get_count; +ULONG rsc_enum_mutex_usage; +ULONG rsc_enum_mem_usage; + +static UX_DEVICE_CLASS_DUMMY *device_dummy[2] = {UX_NULL, UX_NULL}; +static UX_DEVICE_CLASS_DUMMY_PARAMETER device_dummy_parameter; + +/* Define device framework. */ + +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0xEF bDeviceClass: Composite class code + 0x02 bDeviceSubclass: class sub code + 0x00 bDeviceProtocol: Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Configuration 1 descriptor 9 bytes @ 0x12 */ + 0x09, 0x02, + 0xE6, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor @ 0x12+0x09=27 */ + 0x08, 0x0b, 0x00, 0x02, 0x0E, 0x03, 0x00, 0x00, + + /* VideoControl Interface Descriptor Requirement @ 0x12+0x09+8=35 */ + 0x09, 0x04, + 0x00, 0x00, + 0x01, + 0x0E, 0x01, 0x01, + 0x00, + + /* VC_HEADER Descriptor @ 35+9=44 */ + 0x0D, 0x24, 0x01, + 0x50, 0x01, + 0x4D, 0x00, /* wTotalLength: */ + 0x00, 0x00, 0x00, 0x00, + 0x01, /* bInCollection */ + 0x01, /* baInterfaceNr(1) */ + + /* Input Terminal Descriptor (Camera) @ 44+0x0D=57 */ + 0x12, 0x24, 0x02, + 0x02, /* bTerminalID */ + 0x01, 0x02, /* wTerminalType ITT_CAMERA */ + 0x00, + 0x00, + 0x00, 0x00, /* wObjectiveFocalLengthMin */ + 0x00, 0x00, /* wObjectiveFocalLengthMax */ + 0x00, 0x00, /* wOcularFocalLength */ + 0x03, /* bControlSize */ + 0x00, 0x02, 0x00, /* bmControls */ + + /* Input Terminal Descriptor (Media Transport) @ 57+0x12=75 */ + 0x10, 0x24, 0x02, + 0x03, /* bTerminalID */ + 0x02, 0x02, /* wTerminalType ITT_MEDIA_TRANSPORT_INPUT */ + 0x00, + 0x00, + 0x01, /* bControlSize */ + 0x0D, /* bmControls */ + 0x05, /* bTransportModeSize */ + 0xAF, 0xFF, 0xFF, 0x7F, 0x00, /* bmTransportModes */ + + /* Selector Unit Descriptor @ 75+0x10=91 */ + 0x08, 0x24, 0x04, + 0x01, /* bUnitID */ + 0x02, /* bNrInPins */ + 0x02, /* baSourceID(1) */ + 0x03, /* baSourceID(2) */ + 0x00, + + /* Processing Unit Descriptor @ 91+8=99 */ + 13, 0x24, 0x05, + 0x05, /* bUnitID */ + 0x01, /* bSourceID */ + 0x00, 0x00, /* wMaxMultiplier */ + 0x03, /* bControlSize */ + 0x00, 0x00, 0x00, /* bmControls */ + 0x00, + 0x00, /* bmVideoStandards */ + + /* Output Terminal Descriptor @ 99+13=112 */ + 0x09, 0x24, 0x03, + 0x04, /* bTerminalID */ + 0x01, 0x01, /* wTerminalType TT_STREAMING */ + 0x00, + 0x05, /* bSourceID */ + 0x00, + + /* Interrupt Endpoint 0x83 descriptor @ 112+9=121 */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0x0A, + + /* CS_ENDPOINT @ 121+7=128 */ + 0x05, 0x25, 0x03, + 0x20, 0x00, /* wMaxTransferSize */ + + /* VideoStreaming Interface 1.0 @ 128+5=133 */ + 0x09, 0x04, + 0x01, 0x00, + 0x01, + 0x0E, 0x02, 0x00, + 0x00, + + /* VS_INPUT_HEADER @ 133+9=142 */ + 0x0E, 0x24, 0x01, + 0x01, /* bNumFormats */ + 0x4C, 0x00, /* wTotalLength */ + 0x85, /* bEndpointAddress */ + 0x00, + 0x04, /* bTerminalLink */ + 0x03, /* bStillCaptureMethod */ + 0x00, /* bTriggerSupport */ + 0x00, /* bTriggerUsage */ + 0x01, /* bControlSize */ + 0x00, /* bmaControls */ + + /* VS_FORMAT_MJPEG @ 142+0xE=156 */ + 0x0B, 0x24, 0x06, + 0x01, /* bFormatIndex */ + 0x01, /* bNumFrameDescriptors */ + 0x01, /* bmFlags */ + 0x01, /* bDefaultFrameIndex */ + 0x00, 0x00, + 0x02, /* bmInterlaceFlags */ + 0x00, /* bCopyProtect */ + + /* VS_FRAME_MJPEG @ 156+0x0b=167 */ + 0x1E, 0x24, 0x07, + 0x01, /* bFrameIndex */ + 0x02, /* bmCapabilities */ + 0xA0, 0x00, /* wWidth 160 */ + 0x78, 0x00, /* wHeight 120 */ + 0x00, 0x65, 0x04, 0x00, /* dwMinBitRate */ + 0x00, 0xA0, 0x0F, 0x00, /* dwMaxBitRate */ + 0x00, 0x08, 0x00, 0x00, /* dwMaxVideoFrameBufSize */ + 0x2A, 0x2C, 0x0A, 0x00, /* dwDefaultFrameInterval */ + 0x01, /* bFrameIntervalType */ + 0x2A, 0x2C, 0x0A, 0x00, /* dwFrameInterval(1) 666666 */ + + /* VS_STILL_FRAME @ 167+0x1e=197 */ + 0x0F, 0x24, 0x03, + 0x86, /* bEndpointAddress */ + 0x02, /* bNumImageSizePatterns */ + 0x20, 0x03, /* wWidth 800 */ + 0x58, 0x02, /* wHeight 600 */ + 0x20, 0x03, /* wWidth */ + 0x20, 0x03, /* wHeight */ + 0x01, /* bNumCompressionPtr */ + 0x64, /* bCompression 1:100 */ + + /* VS_COLORFORMAT @ 197+0xf=212 */ + 0x06, 0x24, 0x0D, + 0x00, 0x00, 0x00, + + /* Bulk endpoint 0x86 */ + 0x07, 0x05, + 0x86, + 0x02, + 0x40, 0x00, + 0x00, + + /* VideoStreaming Interface 1.1 */ + 0x09, 0x04, + 0x01, 0x01, + 0x02, + 0x0E, 0x02, 0x00, + 0x00, + + /* ISO Endpoint 0x85 */ + 0x07, 0x05, + 0x85, + 0x05, + 0x80, 0x00, /* 128 */ + 0x01, + + /* Bulk Endpoint 0x86 */ + 0x07, 0x05, + 0x86, + 0x02, + 0x40, 0x00, + 0x00, +}; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor 18 bytes + 0xEF bDeviceClass: Composite class code + 0x02 bDeviceSubclass: class sub code + 0x00 bDeviceProtocol: Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Configuration 1 descriptor 9 bytes @ 0x12 */ + 0x09, 0x02, + 0xE6, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor @ 0x12+0x09=27 */ + 0x08, 0x0b, 0x00, 0x02, 0x0E, 0x03, 0x00, 0x00, + + /* VideoControl Interface Descriptor Requirement @ 0x12+0x09+8=35 */ + 0x09, 0x04, + 0x00, 0x00, + 0x01, + 0x0E, 0x01, 0x01, + 0x00, + + /* VC_HEADER Descriptor @ 35+9=44 */ + 0x0D, 0x24, 0x01, + 0x50, 0x01, + 0x4D, 0x00, /* wTotalLength: */ + 0x00, 0x00, 0x00, 0x00, + 0x01, /* bInCollection */ + 0x01, /* baInterfaceNr(1) */ + + /* Input Terminal Descriptor (Camera) @ 44+0x0D=57 */ + 0x12, 0x24, 0x02, + 0x02, /* bTerminalID */ + 0x01, 0x02, /* wTerminalType ITT_CAMERA */ + 0x00, + 0x00, + 0x00, 0x00, /* wObjectiveFocalLengthMin */ + 0x00, 0x00, /* wObjectiveFocalLengthMax */ + 0x00, 0x00, /* wOcularFocalLength */ + 0x03, /* bControlSize */ + 0x00, 0x02, 0x00, /* bmControls */ + + /* Input Terminal Descriptor (Media Transport) @ 57+0x12=75 */ + 0x10, 0x24, 0x02, + 0x03, /* bTerminalID */ + 0x02, 0x02, /* wTerminalType ITT_MEDIA_TRANSPORT_INPUT */ + 0x00, + 0x00, + 0x01, /* bControlSize */ + 0x0D, /* bmControls */ + 0x05, /* bTransportModeSize */ + 0xAF, 0xFF, 0xFF, 0x7F, 0x00, /* bmTransportModes */ + + /* Selector Unit Descriptor @ 75+0x10=91 */ + 0x08, 0x24, 0x04, + 0x01, /* bUnitID */ + 0x02, /* bNrInPins */ + 0x02, /* baSourceID(1) */ + 0x03, /* baSourceID(2) */ + 0x00, + + /* Processing Unit Descriptor @ 91+8=99 */ + 13, 0x24, 0x05, + 0x05, /* bUnitID */ + 0x01, /* bSourceID */ + 0x00, 0x00, /* wMaxMultiplier */ + 0x03, /* bControlSize */ + 0x00, 0x00, 0x00, /* bmControls */ + 0x00, + 0x00, /* bmVideoStandards */ + + /* Output Terminal Descriptor @ 99+13=112 */ + 0x09, 0x24, 0x03, + 0x04, /* bTerminalID */ + 0x01, 0x01, /* wTerminalType TT_STREAMING */ + 0x00, + 0x05, /* bSourceID */ + 0x00, + + /* Interrupt Endpoint 0x83 descriptor @ 112+9=121 */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x08, + 0x01, + + /* CS_ENDPOINT @ 121+7=128 */ + 0x05, 0x25, 0x03, + 0x20, 0x00, /* wMaxTransferSize */ + + /* VideoStreaming Interface 1.0 @ 128+5=133 */ + 0x09, 0x04, + 0x01, 0x00, + 0x01, + 0x0E, 0x02, 0x00, + 0x00, + + /* VS_INPUT_HEADER @ 133+9=142 */ + 0x0E, 0x24, 0x01, + 0x01, /* bNumFormats */ + 0x4C, 0x00, /* wTotalLength */ + 0x85, /* bEndpointAddress */ + 0x00, + 0x04, /* bTerminalLink */ + 0x03, /* bStillCaptureMethod */ + 0x00, /* bTriggerSupport */ + 0x00, /* bTriggerUsage */ + 0x01, /* bControlSize */ + 0x00, /* bmaControls */ + + /* VS_FORMAT_MJPEG @ 142+0xE=156 */ + 0x0B, 0x24, 0x06, + 0x01, /* bFormatIndex */ + 0x01, /* bNumFrameDescriptors */ + 0x01, /* bmFlags */ + 0x01, /* bDefaultFrameIndex */ + 0x00, 0x00, + 0x02, /* bmInterlaceFlags */ + 0x00, /* bCopyProtect */ + + /* VS_FRAME_MJPEG @ 156+0x0b=167 */ + 0x1E, 0x24, 0x07, + 0x01, /* bFrameIndex */ + 0x02, /* bmCapabilities */ + 0xA0, 0x00, /* wWidth 160 */ + 0x78, 0x00, /* wHeight 120 */ + 0x00, 0x65, 0x04, 0x00, /* dwMinBitRate */ + 0x00, 0xA0, 0x0F, 0x00, /* dwMaxBitRate */ + 0x00, 0x08, 0x00, 0x00, /* dwMaxVideoFrameBufSize */ + 0x2A, 0x2C, 0x0A, 0x00, /* dwDefaultFrameInterval */ + 0x01, /* bFrameIntervalType */ + 0x2A, 0x2C, 0x0A, 0x00, /* dwFrameInterval(1) 666666 */ + + /* VS_STILL_FRAME @ 167+0x1e=197 */ + 0x0F, 0x24, 0x03, + 0x86, /* bEndpointAddress */ + 0x02, /* bNumImageSizePatterns */ + 0x20, 0x03, /* wWidth 800 */ + 0x58, 0x02, /* wHeight 600 */ + 0x20, 0x03, /* wWidth */ + 0x20, 0x03, /* wHeight */ + 0x01, /* bNumCompressionPtr */ + 0x64, /* bCompression 1:100 */ + + /* VS_COLORFORMAT @ 197+0xf=212 */ + 0x06, 0x24, 0x0D, + 0x00, 0x00, 0x00, + + /* Bulk endpoint 0x86 */ + 0x07, 0x05, + 0x86, + 0x02, + 0x40, 0x00, + 0x00, + + /* VideoStreaming Interface 1.1 */ + 0x09, 0x04, + 0x01, 0x01, + 0x02, + 0x0E, 0x02, 0x00, + 0x00, + + /* ISO Endpoint 0x85 */ + 0x07, 0x05, + 0x85, + 0x05, + 0x80, 0x08, /* 2 x 128 = 256 */ + 0x01, + + /* Bulk Endpoint 0x86 */ + 0x07, 0x05, + 0x86, + 0x02, + 0x40, 0x00, + 0x00, +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 + }; + +static UX_TEST_SETUP _SetAddress = UX_TEST_SETUP_SetAddress; +static UX_TEST_SETUP _GetDeviceDescriptor = UX_TEST_SETUP_GetDevDescr; +static UX_TEST_SETUP _GetConfigDescriptor = UX_TEST_SETUP_GetCfgDescr; +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +/* Test interactions */ + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION normal_enum_replace[] = { +/* 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, &_GetDeviceDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 0, 8, 0, + UX_SUCCESS, UX_NULL}, +{ UX_HCD_TRANSFER_REQUEST, &_GetDeviceDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 0, 18, 0, + UX_SUCCESS, UX_NULL}, +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 18, UX_CONFIGURATION_DESCRIPTOR_LENGTH, 0, + UX_SUCCESS, UX_NULL}, +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 18, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 18, 0, + UX_SUCCESS, UX_NULL}, +{ 0 } +} +; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT test_slave_change_function(ULONG change) +{ + return 0; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_VIDEO *video_inst = (UX_HOST_CLASS_VIDEO *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + host_video = video_inst; + break; + + case UX_DEVICE_REMOVAL: + host_video = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_dummy_instance_activate(VOID *dummy_instance) +{ + if (device_dummy[0] == UX_NULL) + { + device_dummy[0] = (UX_DEVICE_CLASS_DUMMY *)dummy_instance; + return; + } + if (device_dummy[1] == UX_NULL) + { + device_dummy[1] = (UX_DEVICE_CLASS_DUMMY *)dummy_instance; + return; + } +} +static VOID test_dummy_instance_deactivate(VOID *dummy_instance) +{ + if (device_dummy[0] == dummy_instance) + device_dummy[0] = UX_NULL; + if (device_dummy[1] == dummy_instance) + device_dummy[1] = UX_NULL; +} +static UX_SLAVE_TRANSFER _last_control_transfer; +static UCHAR _last_control_data[64]; +static VOID test_dummy_instance_control_request(UX_DEVICE_CLASS_DUMMY *dummy_instance, + UX_SLAVE_TRANSFER *transfer) +{ +USHORT req_length = _ux_utility_short_get(transfer->ux_slave_transfer_request_setup + 6); +#if 0 + printf("D_Video_Req %x: %x %x, %x %x %x; %d/%d\n", + transfer->ux_slave_transfer_request_phase, + transfer->ux_slave_transfer_request_setup[0], + transfer->ux_slave_transfer_request_setup[1], + _ux_utility_short_get(transfer->ux_slave_transfer_request_setup + 2), + _ux_utility_short_get(transfer->ux_slave_transfer_request_setup + 4), + _ux_utility_short_get(transfer->ux_slave_transfer_request_setup + 6), + transfer->ux_slave_transfer_request_actual_length, + transfer->ux_slave_transfer_request_requested_length); +#endif + _ux_utility_memory_copy(&_last_control_transfer, transfer, sizeof(UX_SLAVE_TRANSFER)); + if (transfer->ux_slave_transfer_request_setup[0] & 0x80) /* GET */ + { + _ux_utility_memory_copy(transfer->ux_slave_transfer_request_data_pointer, + _last_control_data, + req_length); + _ux_device_stack_transfer_request(transfer, req_length, req_length); + } + else /* SET */ + { + _ux_utility_memory_copy(_last_control_data, + transfer->ux_slave_transfer_request_data_pointer, + req_length); + } + // _ux_device_stack_endpoint_stall(transfer->ux_slave_transfer_request_endpoint); +} +static VOID test_dummy_instance_change(UX_DEVICE_CLASS_DUMMY *dummy_instance) +{ +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_enum_sem_get_count = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +static VOID ux_test_system_host_enum_hub_function(VOID) +{ + enum_counter ++; +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_host_class_video_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + printf("Running Host Class Video Basic Functionality Test................... "); +#if !(UX_TEST_MULTI_IFC_ON && UX_TEST_MULTI_ALT_ON) + printf("SKIP!\n"); + test_control_return(0); + return; +#endif + + /* 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(); + + /* 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 #1\n"); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + if (status != UX_SUCCESS) + { + + printf(" ERROR #2\n"); + test_control_return(1); + } + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_video_name, ux_host_class_video_entry); + if (status != UX_SUCCESS) + { + + printf(" ERROR #3\n"); + 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, + test_slave_change_function); + if(status!=UX_SUCCESS) + { + + printf(" ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a dummy device. */ + _ux_utility_memory_set(&device_dummy_parameter, 0, sizeof(device_dummy_parameter)); + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks. + ux_device_class_dummy_instance_activate = test_dummy_instance_activate; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks. + ux_device_class_dummy_instance_deactivate = test_dummy_instance_deactivate; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks. + ux_device_class_dummy_change = test_dummy_instance_change; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks. + ux_device_class_dummy_control_request = test_dummy_instance_control_request; + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, + _ux_device_class_dummy_entry, + 1, 0, &device_dummy_parameter); + status |= ux_device_stack_class_register(_ux_system_slave_class_dpump_name, + _ux_device_class_dummy_entry, + 1, 1, &device_dummy_parameter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if(status != UX_SUCCESS) + { + + printf(" ERROR #7\n"); + test_control_return(1); + } +#endif + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #8\n"); + 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 #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #9\n"); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #10\n"); + test_control_return(1); + } +} + +#define TX_TEST_VIDEO_PARSER_SIZE 32 +typedef struct TX_TEST_VIDEO_PARSER_STRUCT +{ + UCHAR *descriptor_base; + ULONG parsed_interface[TX_TEST_VIDEO_PARSER_SIZE]; + ULONG parsed_entity[TX_TEST_VIDEO_PARSER_SIZE]; + ULONG parsed_count; +} TX_TEST_VIDEO_PARSER; + +static const TX_TEST_VIDEO_PARSER parser_check = +{ + UX_NULL, + {17, 17, 17, 17, 17, 17, 17, 17, + 115, 115, 115, 115, 115}, + {26, 39, 57, 73, 81, 94, 103, 110, + 124, 138, 149, 179, 182}, + 13 +}; + +static UINT tx_test_video_descriptors_parser(VOID *arg, + UCHAR *packed_interface_descriptor, + UCHAR *packed_entity_descriptor) +{ +TX_TEST_VIDEO_PARSER *parser; + + parser = (TX_TEST_VIDEO_PARSER *)arg; + parser->parsed_interface[parser->parsed_count] = packed_interface_descriptor - parser->descriptor_base; + parser->parsed_entity [parser->parsed_count] = packed_entity_descriptor - parser->descriptor_base; + parser->parsed_count ++; +} + + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +ULONG mem_free; +ULONG loop; +TX_TEST_VIDEO_PARSER parser; +ULONG parameter_u32[64/4]; +USHORT *parameter_u16 = (USHORT*)parameter_u32; +UCHAR *parameter_u8 = (UCHAR*)parameter_u32; +UX_ENDPOINT *iso_ep; +UX_ENDPOINT *int_ep; + + + stepinfo("\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Find the video class and wait for the link to be up. */ + for (loop = 0; loop < 100; loop ++) + if (host_video != UX_NULL) + break; + if (host_video == UX_NULL) + { + printf("ERROR #%d: enum fail", __LINE__); + test_control_return(1); + } + if (host_video->ux_host_class_video_feature_unit_id != 5) + { + printf("ERROR #%d: wrong feature bUnitID 0x%lx\n", __LINE__, host_video->ux_host_class_video_feature_unit_id); + test_control_return(1); + } + if (host_video->ux_host_class_video_terminal_id != 2) + { + printf("ERROR #%d: wrong input bTerminalID 0x%lx\n", __LINE__, host_video->ux_host_class_video_terminal_id); + test_control_return(1); + } + if (host_video->ux_host_class_video_number_formats != 1) + { + printf("ERROR #%d: wrong VS_HEADER bNumFormats %ld\n", __LINE__, host_video->ux_host_class_video_number_formats); + test_control_return(1); + } + if (host_video->ux_host_class_video_length_formats != 0x004C) + { + printf("ERROR #%d: wrong VS_HEADER wTotalLength 0x%lx\n", __LINE__, host_video->ux_host_class_video_length_formats); + test_control_return(1); + } + if (host_video->ux_host_class_video_format_address != + (host_video->ux_host_class_video_configuration_descriptor + 124)) + { + printf("ERROR #%d: wrong VS_HEADER addr %p <> %p\n", __LINE__, + host_video->ux_host_class_video_format_address, + (host_video->ux_host_class_video_configuration_descriptor + 124)); + test_control_return(1); + } + int_ep = host_video->ux_host_class_video_device-> + ux_device_current_configuration-> + ux_configuration_first_interface-> + ux_interface_first_endpoint; + if (int_ep->ux_endpoint_transfer_request.ux_transfer_request_packet_length != 8) + { + printf("ERROR #%d: wrong INT max packet length %ld\n", __LINE__, iso_ep->ux_endpoint_transfer_request.ux_transfer_request_packet_length); + test_control_return(1); + } + iso_ep = host_video->ux_host_class_video_device-> + ux_device_current_configuration-> + ux_configuration_first_interface-> + ux_interface_next_interface-> + ux_interface_next_interface->ux_interface_first_endpoint; + if (iso_ep->ux_endpoint_transfer_request.ux_transfer_request_packet_length != 128) + { + printf("ERROR #%d: wrong ISO max packet length %ld\n", __LINE__, iso_ep->ux_endpoint_transfer_request.ux_transfer_request_packet_length); + test_control_return(1); + } + + /* Re-connect with high speed. */ + ux_test_hcd_sim_host_disconnect(); + ux_test_dcd_sim_slave_disconnect(); + + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + /* Find the video class and wait for the link to be up. */ + for (loop = 0; loop < 100; loop ++) + if (host_video != UX_NULL) + break; + if (host_video == UX_NULL) + { + printf("ERROR #%d: enum fail", __LINE__); + test_control_return(1); + } + if (host_video->ux_host_class_video_feature_unit_id != 5) + { + printf("ERROR #%d: wrong feature bUnitID 0x%lx\n", __LINE__, host_video->ux_host_class_video_feature_unit_id); + test_control_return(1); + } + if (host_video->ux_host_class_video_terminal_id != 2) + { + printf("ERROR #%d: wrong input bTerminalID 0x%lx\n", __LINE__, host_video->ux_host_class_video_terminal_id); + test_control_return(1); + } + if (host_video->ux_host_class_video_number_formats != 1) + { + printf("ERROR #%d: wrong VS_HEADER bNumFormats %ld\n", __LINE__, host_video->ux_host_class_video_number_formats); + test_control_return(1); + } + if (host_video->ux_host_class_video_length_formats != 0x004C) + { + printf("ERROR #%d: wrong VS_HEADER wTotalLength 0x%lx\n", __LINE__, host_video->ux_host_class_video_length_formats); + test_control_return(1); + } + if (host_video->ux_host_class_video_format_address != + (host_video->ux_host_class_video_configuration_descriptor + 124)) + { + printf("ERROR #%d: wrong VS_HEADER addr %p <> %p\n", __LINE__, + host_video->ux_host_class_video_format_address, + (host_video->ux_host_class_video_configuration_descriptor + 124)); + test_control_return(1); + } + int_ep = host_video->ux_host_class_video_device-> + ux_device_current_configuration-> + ux_configuration_first_interface-> + ux_interface_first_endpoint; + if (int_ep->ux_endpoint_transfer_request.ux_transfer_request_packet_length != 8*2) + { + printf("ERROR #%d: wrong INT max packet length %ld\n", __LINE__, iso_ep->ux_endpoint_transfer_request.ux_transfer_request_packet_length); + test_control_return(1); + } + iso_ep = host_video->ux_host_class_video_device-> + ux_device_current_configuration-> + ux_configuration_first_interface-> + ux_interface_next_interface-> + ux_interface_next_interface->ux_interface_first_endpoint; + if (iso_ep->ux_endpoint_transfer_request.ux_transfer_request_packet_length != 128*2) + { + printf("ERROR #%d: wrong ISO max packet length %ld\n", __LINE__, iso_ep->ux_endpoint_transfer_request.ux_transfer_request_packet_length); + test_control_return(1); + } + + /* Test entities parse. */ + ux_utility_memory_set(&parser, 0, sizeof(parser)); + parser.descriptor_base = host_video->ux_host_class_video_configuration_descriptor; + status = _ux_host_class_video_entities_parse(host_video, tx_test_video_descriptors_parser, &parser); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: parse error 0x%x\n", __LINE__, status); + test_control_return(1); + } + for(loop = 0; loop < parser.parsed_count; loop++) + { + if (parser.parsed_interface[loop] != parser_check.parsed_interface[loop]) + { + printf("ERROR #%d: wrong interface: %ld <> %ld\n", __LINE__, + parser.parsed_interface[loop], parser_check.parsed_interface[loop]); + test_control_return(1); + } + if (parser.parsed_entity[loop] != parser_check.parsed_entity[loop]) + { + printf("ERROR #%d: wrong entity descriptor: %ld <> %ld\n", __LINE__, + parser.parsed_entity[loop], parser_check.parsed_entity[loop]); + test_control_return(1); + } + } + + /* Test control request. */ + + /* UX_HOST_CLASS_VIDEO_SET_CUR :: UX_HOST_CLASS_VIDEO_TCS_PU_BRIGHTNESS_CONTROL */ + _ux_utility_memory_set(_last_control_data, 0, 2); + parameter_u8[0] = '0'; + parameter_u8[1] = '1'; + status = _ux_host_class_video_control_request(host_video, + UX_HOST_CLASS_VIDEO_SET_CUR, 0, + host_video -> ux_host_class_video_feature_unit_id, + UX_HOST_CLASS_VIDEO_TCS_PU_BRIGHTNESS_CONTROL, + parameter_u8, 2); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: request error 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (_last_control_transfer.ux_slave_transfer_request_setup[0] != 0x21 || + _last_control_transfer.ux_slave_transfer_request_setup[1] != UX_HOST_CLASS_VIDEO_SET_CUR || + _last_control_transfer.ux_slave_transfer_request_setup[3] != UX_HOST_CLASS_VIDEO_TCS_PU_BRIGHTNESS_CONTROL || + _last_control_transfer.ux_slave_transfer_request_setup[4] != 0 /* interface number */ || + _last_control_transfer.ux_slave_transfer_request_setup[5] != 5 /* entity id */ + ) + { + printf("ERROR #%d: setup incorrect\n", __LINE__); + printf(" %x %x", + _last_control_transfer.ux_slave_transfer_request_setup[0], + _last_control_transfer.ux_slave_transfer_request_setup[1]); + printf(" %x %x %x", + _last_control_transfer.ux_slave_transfer_request_setup[3], + _last_control_transfer.ux_slave_transfer_request_setup[4], + _last_control_transfer.ux_slave_transfer_request_setup[5]); + test_control_return(1); + } + if (_last_control_data[0] != '0' || _last_control_data[1] != '1') + { + printf("ERROR #%d: control data not sent\n", __LINE__); + test_control_return(1); + } + + /* UX_HOST_CLASS_VIDEO_GET_CUR :: UX_HOST_CLASS_VIDEO_TCS_PU_BRIGHTNESS_CONTROL */ + _ux_utility_memory_set(parameter_u8, 0, sizeof(parameter_u32)); + status = _ux_host_class_video_control_request(host_video, + UX_HOST_CLASS_VIDEO_GET_CUR, 0, + host_video -> ux_host_class_video_feature_unit_id, + UX_HOST_CLASS_VIDEO_TCS_PU_BRIGHTNESS_CONTROL, + parameter_u8, 2); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: request error 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (_last_control_transfer.ux_slave_transfer_request_setup[0] != 0xA1 || + _last_control_transfer.ux_slave_transfer_request_setup[1] != UX_HOST_CLASS_VIDEO_GET_CUR || + _last_control_transfer.ux_slave_transfer_request_setup[3] != UX_HOST_CLASS_VIDEO_TCS_PU_BRIGHTNESS_CONTROL || + _last_control_transfer.ux_slave_transfer_request_setup[4] != 0 /* interface number */ || + _last_control_transfer.ux_slave_transfer_request_setup[5] != 5 /* entity id */ + ) + { + printf("ERROR #%d: setup incorrect\n", __LINE__); + printf(" %x %x", + _last_control_transfer.ux_slave_transfer_request_setup[0], + _last_control_transfer.ux_slave_transfer_request_setup[1]); + printf(" %x %x %x", + _last_control_transfer.ux_slave_transfer_request_setup[3], + _last_control_transfer.ux_slave_transfer_request_setup[4], + _last_control_transfer.ux_slave_transfer_request_setup[5]); + test_control_return(1); + } + if (parameter_u8[0] != '0' || parameter_u8[1] != '1') + { + printf("ERROR #%d: control data not sent\n", __LINE__); + test_control_return(1); + } + + /* UX_HOST_CLASS_VIDEO_SET_CUR :: UX_HOST_CLASS_VIDEO_TCS_VS_PROBE_CONTROL */ + _ux_utility_memory_set(_last_control_data, 0, 34); + for(loop = 0; loop < 34; loop++) parameter_u8[loop] = loop; + status = _ux_host_class_video_control_request(host_video, + UX_HOST_CLASS_VIDEO_SET_CUR, 1, + 0, + UX_HOST_CLASS_VIDEO_TCS_VS_PROBE_CONTROL, + parameter_u8, 34); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: request error 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (_last_control_transfer.ux_slave_transfer_request_setup[0] != 0x21 || + _last_control_transfer.ux_slave_transfer_request_setup[1] != UX_HOST_CLASS_VIDEO_SET_CUR || + _last_control_transfer.ux_slave_transfer_request_setup[3] != UX_HOST_CLASS_VIDEO_TCS_VS_PROBE_CONTROL || + _last_control_transfer.ux_slave_transfer_request_setup[4] != 1 /* interface number */ || + _last_control_transfer.ux_slave_transfer_request_setup[5] != 0 /* entity id */ + ) + { + printf("ERROR #%d: setup incorrect\n", __LINE__); + printf(" %x %x", + _last_control_transfer.ux_slave_transfer_request_setup[0], + _last_control_transfer.ux_slave_transfer_request_setup[1]); + printf(" %x %x %x", + _last_control_transfer.ux_slave_transfer_request_setup[3], + _last_control_transfer.ux_slave_transfer_request_setup[4], + _last_control_transfer.ux_slave_transfer_request_setup[5]); + test_control_return(1); + } + for (loop = 0; loop < 34; loop ++) + { + if (_last_control_data[loop] != loop) + { + printf("ERROR #%d: control data not correct\n", __LINE__); + test_control_return(1); + } + } + + /* UX_HOST_CLASS_VIDEO_GET_CUR :: UX_HOST_CLASS_VIDEO_TCS_VS_PROBE_CONTROL */ + _ux_utility_memory_set(parameter_u8, 0, sizeof(parameter_u32)); + status = _ux_host_class_video_control_request(host_video, + UX_HOST_CLASS_VIDEO_GET_CUR, 1, + 0, + UX_HOST_CLASS_VIDEO_TCS_VS_PROBE_CONTROL, + parameter_u8, 34); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: request error 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (_last_control_transfer.ux_slave_transfer_request_setup[0] != 0xA1 || + _last_control_transfer.ux_slave_transfer_request_setup[1] != UX_HOST_CLASS_VIDEO_GET_CUR || + _last_control_transfer.ux_slave_transfer_request_setup[3] != UX_HOST_CLASS_VIDEO_TCS_VS_PROBE_CONTROL || + _last_control_transfer.ux_slave_transfer_request_setup[4] != 1 /* interface number */ || + _last_control_transfer.ux_slave_transfer_request_setup[5] != 0 /* entity id */ + ) + { + printf("ERROR #%d: setup incorrect\n", __LINE__); + printf(" %x %x", + _last_control_transfer.ux_slave_transfer_request_setup[0], + _last_control_transfer.ux_slave_transfer_request_setup[1]); + printf(" %x %x %x", + _last_control_transfer.ux_slave_transfer_request_setup[3], + _last_control_transfer.ux_slave_transfer_request_setup[4], + _last_control_transfer.ux_slave_transfer_request_setup[5]); + test_control_return(1); + } + for (loop = 0; loop < 34; loop ++) + { + if (parameter_u8[loop] != loop) + { + printf("ERROR #%d: control data not correct\n", __LINE__); + test_control_return(1); + } + } + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + if (host_video != UX_NULL) + { + + printf("ERROR #13: instance not removed when disconnect"); + test_control_return(1); + } + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_dpump_name, _ux_device_class_dummy_entry); + status |= ux_device_stack_class_unregister(_ux_system_slave_class_dpump_name, _ux_device_class_dummy_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); + } +} diff --git a/test/regression/usbx_ux_host_class_video_dwMaxPayloadTransferSize_test.c b/test/regression/usbx_ux_host_class_video_dwMaxPayloadTransferSize_test.c new file mode 100644 index 00000000..9732e2b6 --- /dev/null +++ b/test/regression/usbx_ux_host_class_video_dwMaxPayloadTransferSize_test.c @@ -0,0 +1,789 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_dummy.h" +#include "ux_device_stack.h" +#include "ux_host_class_video.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); + +static VOID ux_test_hcd_entry_should_not_be_called(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_disconnect(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +static VOID ux_test_system_host_enum_hub_function(VOID); + +/* Define global data structures. */ +UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +UX_HOST_CLASS_VIDEO *host_video = UX_NULL; + +ULONG enum_counter; + +ULONG error_counter; + +ULONG set_cfg_counter; + +ULONG rsc_mem_free_on_set_cfg; +ULONG rsc_sem_on_set_cfg; +ULONG rsc_sem_get_on_set_cfg; +ULONG rsc_mutex_on_set_cfg; + +ULONG rsc_enum_sem_usage; +ULONG rsc_enum_sem_get_count; +ULONG rsc_enum_mutex_usage; +ULONG rsc_enum_mem_usage; + +static UX_DEVICE_CLASS_DUMMY *device_dummy[2] = {UX_NULL, UX_NULL}; +static UX_DEVICE_CLASS_DUMMY_PARAMETER device_dummy_parameter; + +/* Define device framework. */ + +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0xEF bDeviceClass: Composite class code + 0x02 bDeviceSubclass: class sub code + 0x00 bDeviceProtocol: Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Configuration 1 descriptor 9 bytes @ 0x12 */ + 0x09, 0x02, + 0xE6, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor @ 0x12+0x09=27 */ + 0x08, 0x0b, 0x00, 0x02, 0x0E, 0x03, 0x00, 0x00, + + /* VideoControl Interface Descriptor Requirement @ 0x12+0x09+8=35 */ + 0x09, 0x04, + 0x00, 0x00, + 0x01, + 0x0E, 0x01, 0x01, + 0x00, + + /* VC_HEADER Descriptor @ 35+9=44 */ + 0x0D, 0x24, 0x01, + 0x50, 0x01, + 0x4D, 0x00, /* wTotalLength: */ + 0x00, 0x00, 0x00, 0x00, + 0x01, /* bInCollection */ + 0x01, /* baInterfaceNr(1) */ + + /* Input Terminal Descriptor (Camera) @ 44+0x0D=57 */ + 0x12, 0x24, 0x02, + 0x02, /* bTerminalID */ + 0x01, 0x02, /* wTerminalType ITT_CAMERA */ + 0x00, + 0x00, + 0x00, 0x00, /* wObjectiveFocalLengthMin */ + 0x00, 0x00, /* wObjectiveFocalLengthMax */ + 0x00, 0x00, /* wOcularFocalLength */ + 0x03, /* bControlSize */ + 0x00, 0x02, 0x00, /* bmControls */ + + /* Input Terminal Descriptor (Media Transport) @ 57+0x12=75 */ + 0x10, 0x24, 0x02, + 0x03, /* bTerminalID */ + 0x02, 0x02, /* wTerminalType ITT_MEDIA_TRANSPORT_INPUT */ + 0x00, + 0x00, + 0x01, /* bControlSize */ + 0x0D, /* bmControls */ + 0x05, /* bTransportModeSize */ + 0xAF, 0xFF, 0xFF, 0x7F, 0x00, /* bmTransportModes */ + + /* Selector Unit Descriptor @ 75+0x10=91 */ + 0x08, 0x24, 0x04, + 0x01, /* bUnitID */ + 0x02, /* bNrInPins */ + 0x02, /* baSourceID(1) */ + 0x03, /* baSourceID(2) */ + 0x00, + + /* Processing Unit Descriptor @ 91+8=99 */ + 13, 0x24, 0x05, + 0x05, /* bUnitID */ + 0x01, /* bSourceID */ + 0x00, 0x00, /* wMaxMultiplier */ + 0x03, /* bControlSize */ + 0x00, 0x00, 0x00, /* bmControls */ + 0x00, + 0x00, /* bmVideoStandards */ + + /* Output Terminal Descriptor @ 99+13=112 */ + 0x09, 0x24, 0x03, + 0x04, /* bTerminalID */ + 0x01, 0x01, /* wTerminalType TT_STREAMING */ + 0x00, + 0x05, /* bSourceID */ + 0x00, + + /* Interrupt Endpoint 0x83 descriptor @ 112+9=121 */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0x0A, + + /* CS_ENDPOINT @ 121+7=128 */ + 0x05, 0x25, 0x03, + 0x20, 0x00, /* wMaxTransferSize */ + + /* VideoStreaming Interface 1.0 @ 128+5=133 */ + 0x09, 0x04, + 0x01, 0x00, + 0x01, + 0x0E, 0x02, 0x00, + 0x00, + + /* VS_INPUT_HEADER @ 133+9=142 */ + 0x0E, 0x24, 0x01, + 0x01, /* bNumFormats */ + 0x4C, 0x00, /* wTotalLength */ + 0x85, /* bEndpointAddress */ + 0x00, + 0x04, /* bTerminalLink */ + 0x03, /* bStillCaptureMethod */ + 0x00, /* bTriggerSupport */ + 0x00, /* bTriggerUsage */ + 0x01, /* bControlSize */ + 0x00, /* bmaControls */ + + /* VS_FORMAT_MJPEG @ 142+0xE=156 */ + 0x0B, 0x24, 0x06, + 0x01, /* bFormatIndex */ + 0x01, /* bNumFrameDescriptors */ + 0x01, /* bmFlags */ + 0x01, /* bDefaultFrameIndex */ + 0x00, 0x00, + 0x02, /* bmInterlaceFlags */ + 0x00, /* bCopyProtect */ + + /* VS_FRAME_MJPEG @ 156+0x0b=167 */ + 0x1E, 0x24, 0x07, + 0x01, /* bFrameIndex */ + 0x02, /* bmCapabilities */ + 0xA0, 0x00, /* wWidth */ + 0x78, 0x00, /* wHeight */ + 0x00, 0x65, 0x04, 0x00, /* dwMinBitRate */ + 0x00, 0xA0, 0x0F, 0x00, /* dwMaxBitRate */ + 0x00, 0x08, 0x00, 0x00, /* dwMaxVideoFrameBufSize */ + 0x2A, 0x2C, 0x0A, 0x00, /* dwDefaultFrameInterval */ + 0x01, /* bFrameIntervalType */ + 0x2A, 0x2C, 0x0A, 0x00, /* dwFrameInterval(1) */ + + /* VS_STILL_FRAME @ 167+0x1e=197 */ + 0x0F, 0x24, 0x03, + 0x86, /* bEndpointAddress */ + 0x02, /* bNumImageSizePatterns */ + 0x20, 0x03, /* wWidth 800 */ + 0x58, 0x02, /* wHeight 600 */ + 0x20, 0x03, /* wWidth */ + 0x20, 0x03, /* wHeight */ + 0x01, /* bNumCompressionPtr */ + 0x64, /* bCompression 1:100 */ + + /* VS_COLORFORMAT @ 197+0xf=212 */ + 0x06, 0x24, 0x0D, + 0x00, 0x00, 0x00, + + /* Bulk endpoint 0x86 */ + 0x07, 0x05, + 0x86, + 0x02, + 0x40, 0x00, + 0x00, + + /* VideoStreaming Interface 1.1 */ + 0x09, 0x04, + 0x01, 0x01, + 0x02, + 0x0E, 0x02, 0x00, + 0x00, + + /* ISO Endpoint 0x85 */ + 0x07, 0x05, + 0x85, + 0x05, + 0x00, 0x02, + 0x01, + + /* Bulk Endpoint 0x86 */ + 0x07, 0x05, + 0x86, + 0x02, + 0x40, 0x00, + 0x00, +}; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_full_speed) +#define device_framework_high_speed device_framework_full_speed + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 + }; + +static UX_TEST_SETUP _SetAddress = UX_TEST_SETUP_SetAddress; +static UX_TEST_SETUP _GetDeviceDescriptor = UX_TEST_SETUP_GetDevDescr; +static UX_TEST_SETUP _GetConfigDescriptor = UX_TEST_SETUP_GetCfgDescr; +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +/* Test interactions */ + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION normal_enum_replace[] = { +/* 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, &_GetDeviceDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 0, 8, 0, + UX_SUCCESS, UX_NULL}, +{ UX_HCD_TRANSFER_REQUEST, &_GetDeviceDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 0, 18, 0, + UX_SUCCESS, UX_NULL}, +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 18, UX_CONFIGURATION_DESCRIPTOR_LENGTH, 0, + UX_SUCCESS, UX_NULL}, +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 18, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 18, 0, + UX_SUCCESS, UX_NULL}, +{ 0 } +} +; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT test_slave_change_function(ULONG change) +{ + return 0; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_VIDEO *video_inst = (UX_HOST_CLASS_VIDEO *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + host_video = video_inst; + break; + + case UX_DEVICE_REMOVAL: + host_video = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_dummy_instance_activate(VOID *dummy_instance) +{ + if (device_dummy[0] == UX_NULL) + { + device_dummy[0] = (UX_DEVICE_CLASS_DUMMY *)dummy_instance; + return; + } + if (device_dummy[1] == UX_NULL) + { + device_dummy[1] = (UX_DEVICE_CLASS_DUMMY *)dummy_instance; + return; + } +} +static VOID test_dummy_instance_deactivate(VOID *dummy_instance) +{ + if (device_dummy[0] == dummy_instance) + device_dummy[0] = UX_NULL; + if (device_dummy[1] == dummy_instance) + device_dummy[1] = UX_NULL; +} +static UX_SLAVE_TRANSFER _last_control_transfer; +static UCHAR _last_control_data[64]; +static UCHAR _probe_control_data[UX_HOST_CLASS_VIDEO_PROBE_COMMIT_LENGTH] = +{ + 0, 0, /* bmHint */ + 1, /* bFormatIndex */ + 1, /* bFrameIndex */ + UX_DW0(666666),UX_DW1(666666),UX_DW2(666666),UX_DW3(666666), /* dwFrameInterval */ + UX_W0(0), UX_W1(0), /* wKeyFrameRate */ + UX_W0(0), UX_W1(0), /* wPFrameRate */ + UX_W0(0), UX_W1(0), /* wCompQuality */ + UX_W0(0), UX_W1(0), /* wCompQuality */ + UX_W0(0), UX_W1(0), /* wDelay */ + UX_DW0(460800),UX_DW1(460800),UX_DW2(460800),UX_DW3(460800), /* dwMaxVideoFrameSize @ 18 */ + UX_DW0(256),UX_DW1(256),UX_DW2(256),UX_DW3(256), /* dwMaxPayloadTransferSize @ 22 */ + UX_DW0(6000000),UX_DW1(6000000),UX_DW2(6000000),UX_DW3(6000000), /* dwClockFrequency */ + 0, /* bmFramingInfo */ + 0, /* bPreferedVersion */ + 0, /* bMinVersion */ + 0, /* bMaxVersion */ +}; +static VOID test_dummy_instance_control_request(UX_DEVICE_CLASS_DUMMY *dummy_instance, + UX_SLAVE_TRANSFER *transfer) +{ +USHORT req_length = _ux_utility_short_get(transfer->ux_slave_transfer_request_setup + 6); +UCHAR cs = *(transfer->ux_slave_transfer_request_setup + 4); +#if 0 + printf("D_Video_Req %lx: %x %x, %lx %lx %lx; %ld/%ld\n", + transfer->ux_slave_transfer_request_phase, + transfer->ux_slave_transfer_request_setup[0], + transfer->ux_slave_transfer_request_setup[1], + _ux_utility_short_get(transfer->ux_slave_transfer_request_setup + 2), + _ux_utility_short_get(transfer->ux_slave_transfer_request_setup + 4), + _ux_utility_short_get(transfer->ux_slave_transfer_request_setup + 6), + transfer->ux_slave_transfer_request_actual_length, + transfer->ux_slave_transfer_request_requested_length); +#endif + _ux_utility_memory_copy(&_last_control_transfer, transfer, sizeof(UX_SLAVE_TRANSFER)); + if (transfer->ux_slave_transfer_request_setup[0] & 0x80) /* GET */ + { + switch(cs) + { + case UX_HOST_CLASS_VIDEO_VS_PROBE_CONTROL: + _ux_utility_memory_copy(transfer->ux_slave_transfer_request_data_pointer, + _probe_control_data, + UX_MIN(req_length, sizeof(_probe_control_data))); + _ux_device_stack_transfer_request(transfer, sizeof(_probe_control_data), req_length); + break; + case UX_HOST_CLASS_VIDEO_VS_COMMIT_CONTROL: + default: + _ux_utility_memory_copy(transfer->ux_slave_transfer_request_data_pointer, + _last_control_data, + req_length); + _ux_device_stack_transfer_request(transfer, req_length, req_length); + } + } + else /* SET */ + { + _ux_utility_memory_copy(_last_control_data, + transfer->ux_slave_transfer_request_data_pointer, + req_length); + /* Nothing to SET. */ + } +} +static VOID test_dummy_instance_change(UX_DEVICE_CLASS_DUMMY *dummy_instance) +{ +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_enum_sem_get_count = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +static VOID ux_test_system_host_enum_hub_function(VOID) +{ + enum_counter ++; +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_host_class_video_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + printf("Running ux_host_class_video dwMaxPayloadTransferSize Test........... "); +#if !(UX_TEST_MULTI_IFC_ON && UX_TEST_MULTI_ALT_ON) + printf("SKIP!\n"); + test_control_return(0); + return; +#endif + + /* 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(); + + /* 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 #1\n"); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + if (status != UX_SUCCESS) + { + + printf(" ERROR #2\n"); + test_control_return(1); + } + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_video_name, ux_host_class_video_entry); + if (status != UX_SUCCESS) + { + + printf(" ERROR #3\n"); + 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, + test_slave_change_function); + if(status!=UX_SUCCESS) + { + + printf(" ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a dummy device. */ + _ux_utility_memory_set(&device_dummy_parameter, 0, sizeof(device_dummy_parameter)); + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks. + ux_device_class_dummy_instance_activate = test_dummy_instance_activate; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks. + ux_device_class_dummy_instance_deactivate = test_dummy_instance_deactivate; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks. + ux_device_class_dummy_change = test_dummy_instance_change; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks. + ux_device_class_dummy_control_request = test_dummy_instance_control_request; + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, + _ux_device_class_dummy_entry, + 1, 0, &device_dummy_parameter); + status |= ux_device_stack_class_register(_ux_system_slave_class_dpump_name, + _ux_device_class_dummy_entry, + 1, 1, &device_dummy_parameter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if(status != UX_SUCCESS) + { + + printf(" ERROR #7\n"); + test_control_return(1); + } +#endif + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #8\n"); + 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 #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #9\n"); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #10\n"); + test_control_return(1); + } +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +ULONG mem_free; +ULONG loop; +ULONG parameter_u32[64/4]; +USHORT *parameter_u16 = (USHORT*)parameter_u32; +UCHAR *parameter_u8 = (UCHAR*)parameter_u32; + + + stepinfo("\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Find the video class and wait for the link to be up. */ + for (loop = 0; loop < 100; loop ++) + if (host_video != UX_NULL) + break; + if (host_video == UX_NULL) + { + printf("ERROR #%d: enum fail", __LINE__); + test_control_return(1); + } + if (host_video->ux_host_class_video_feature_unit_id != 5) + { + printf("ERROR #%d: wrong feature bUnitID 0x%lx\n", __LINE__, host_video->ux_host_class_video_feature_unit_id); + test_control_return(1); + } + if (host_video->ux_host_class_video_terminal_id != 2) + { + printf("ERROR #%d: wrong input bTerminalID 0x%lx\n", __LINE__, host_video->ux_host_class_video_terminal_id); + test_control_return(1); + } + if (host_video->ux_host_class_video_number_formats != 1) + { + printf("ERROR #%d: wrong VS_HEADER bNumFormats %ld\n", __LINE__, host_video->ux_host_class_video_number_formats); + test_control_return(1); + } + if (host_video->ux_host_class_video_length_formats != 0x004C) + { + printf("ERROR #%d: wrong VS_HEADER wTotalLength 0x%lx\n", __LINE__, host_video->ux_host_class_video_length_formats); + test_control_return(1); + } + if (host_video->ux_host_class_video_format_address != + (host_video->ux_host_class_video_configuration_descriptor + 124)) + { + printf("ERROR #%d: wrong VS_HEADER addr %p <> %p\n", __LINE__, + host_video->ux_host_class_video_format_address, + (host_video->ux_host_class_video_configuration_descriptor + 124)); + test_control_return(1); + } + + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + /* Test _ux_host_class_video_frame_parameters_set. */ + status = _ux_host_class_video_frame_parameters_set(host_video, + UX_HOST_CLASS_VIDEO_VS_FORMAT_MJPEG, 160, 120, 666666); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: set parameters fail 0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_utility_long_put(_probe_control_data + 22, 0); + status = _ux_host_class_video_frame_parameters_set(host_video, + UX_HOST_CLASS_VIDEO_VS_FORMAT_MJPEG, 160, 120, 666666); + if (status == UX_SUCCESS) + { + printf("ERROR #%d: set parameters should fail\n", __LINE__); + test_control_return(1); + } + _ux_utility_long_put(_probe_control_data + 22, 1024 * 3 + 1); + status = _ux_host_class_video_frame_parameters_set(host_video, + UX_HOST_CLASS_VIDEO_VS_FORMAT_MJPEG, 160, 120, 666666); + if (status == UX_SUCCESS) + { + printf("ERROR #%d: set parameters should fail\n", __LINE__); + test_control_return(1); + } + + UX_TEST_ASSERT(mem_free == _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + + /* Restore. */ + _ux_utility_long_put(_probe_control_data + 22, 3072); + + /* Test video start (failed due to bandwidth 512 limit, see endpoint wMaxPacketSize). */ + status = ux_host_class_video_start(host_video); + if (status == UX_SUCCESS) + { + printf("ERROR #%d: start should fail", __LINE__); + test_control_return(1); + } + UX_TEST_ASSERT(mem_free == _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + + /* Test video start (success). */ + _ux_utility_long_put(_probe_control_data + 22, 512); + status = ux_host_class_video_start(host_video); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: start fail 0x%x", __LINE__, status); + test_control_return(1); + } + UX_TEST_ASSERT(mem_free == _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + if (host_video != UX_NULL) + { + + printf("ERROR #13: instance not removed when disconnect"); + test_control_return(1); + } + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_dpump_name, _ux_device_class_dummy_entry); + status |= ux_device_stack_class_unregister(_ux_system_slave_class_dpump_name, _ux_device_class_dummy_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); + } +} diff --git a/test/regression/usbx_ux_host_class_video_format_frame_based_test.c b/test/regression/usbx_ux_host_class_video_format_frame_based_test.c new file mode 100644 index 00000000..f55ed4eb --- /dev/null +++ b/test/regression/usbx_ux_host_class_video_format_frame_based_test.c @@ -0,0 +1,933 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_dummy.h" +#include "ux_device_stack.h" +#include "ux_host_class_video.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); + +static VOID ux_test_hcd_entry_should_not_be_called(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_disconnect(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +static VOID ux_test_system_host_enum_hub_function(VOID); + +/* Define global data structures. */ +UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +UX_HOST_CLASS_VIDEO *host_video_1 = UX_NULL; +UX_HOST_CLASS_VIDEO *host_video_2 = UX_NULL; + +ULONG enum_counter; + +ULONG error_counter; + +ULONG set_cfg_counter; + +ULONG rsc_mem_free_on_set_cfg; +ULONG rsc_sem_on_set_cfg; +ULONG rsc_sem_get_on_set_cfg; +ULONG rsc_mutex_on_set_cfg; + +ULONG rsc_enum_sem_usage; +ULONG rsc_enum_sem_get_count; +ULONG rsc_enum_mutex_usage; +ULONG rsc_enum_mem_usage; + +static UX_DEVICE_CLASS_DUMMY *device_dummy[2] = {UX_NULL, UX_NULL}; +static UX_DEVICE_CLASS_DUMMY_PARAMETER device_dummy_parameter; + +/* Define device framework. */ + +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0xEF bDeviceClass: Composite class code + 0x02 bDeviceSubclass: class sub code + 0x00 bDeviceProtocol: Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 18, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Configuration 1 descriptor 9 bytes @ 0 */ + 0x09, 0x02, + 0x57, 0x01, /* wTotalLength 9+8+108+92+23+87+16=343 */ + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor @ 9 */ + 0x08, 0x0b, 0x00, 0x03, 0x0E, 0x03, 0x00, 0x00, + + /* VideoControl Interface Descriptor Requirement @ 17; 9+87+7+5=108 */ + 0x09, 0x04, + 0x00, 0x00, + 0x01, + 0x0E, 0x01, 0x01, + 0x00, + + /* VC_HEADER Descriptor @ 26 */ + 14, 0x24, 0x01, + 0x50, 0x01, + 87, 0x00, /* wTotalLength: 14+18+16+8+13+9+9=87 */ + 0x00, 0x00, 0x00, 0x00, + 0x02, /* bInCollection */ + 0x01, /* baInterfaceNr(1) */ + 0x02, /* baInterfaceNr(2) */ + + /* Input Terminal Descriptor (Camera) @ 40 */ + 18, 0x24, 0x02, + 0x02, /* bTerminalID */ + 0x01, 0x02, /* wTerminalType ITT_CAMERA */ + 0x00, + 0x00, + 0x00, 0x00, /* wObjectiveFocalLengthMin */ + 0x00, 0x00, /* wObjectiveFocalLengthMax */ + 0x00, 0x00, /* wOcularFocalLength */ + 0x03, /* bControlSize */ + 0x00, 0x02, 0x00, /* bmControls */ + + /* Input Terminal Descriptor (Media Transport) @ 58 */ + 16, 0x24, 0x02, + 0x03, /* bTerminalID */ + 0x02, 0x02, /* wTerminalType ITT_MEDIA_TRANSPORT_INPUT */ + 0x00, + 0x00, + 0x01, /* bControlSize */ + 0x0D, /* bmControls */ + 0x05, /* bTransportModeSize */ + 0xAF, 0xFF, 0xFF, 0x7F, 0x00, /* bmTransportModes */ + + /* Selector Unit Descriptor @ 74 */ + 0x08, 0x24, 0x04, + 0x01, /* bUnitID */ + 0x02, /* bNrInPins */ + 0x02, /* baSourceID(1) */ + 0x03, /* baSourceID(2) */ + 0x00, + + /* Processing Unit Descriptor @ 82 */ + 13, 0x24, 0x05, + 0x05, /* bUnitID */ + 0x01, /* bSourceID */ + 0x00, 0x00, /* wMaxMultiplier */ + 0x03, /* bControlSize */ + 0x00, 0x00, 0x00, /* bmControls */ + 0x00, + 0x00, /* bmVideoStandards */ + + /* Output Terminal Descriptor @ 95 */ + 0x09, 0x24, 0x03, + 0x04, /* bTerminalID */ + 0x01, 0x01, /* wTerminalType TT_STREAMING */ + 0x00, + 0x05, /* bSourceID */ + 0x00, + + /* Output Terminal Descriptor @ 104 */ + 0x09, 0x24, 0x03, + 0x06, /* bTerminalID */ + 0x01, 0x01, /* wTerminalType TT_STREAMING */ + 0x00, + 0x05, /* bSourceID */ + 0x00, + + /* Interrupt Endpoint 0x83 descriptor @ 113 */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0x0A, + + /* CS_ENDPOINT @ 120 */ + 0x05, 0x25, 0x03, + 0x20, 0x00, /* wMaxTransferSize */ + + /* VideoStreaming Interface 1.0 @ 125; 9+76+7=92 */ + 0x09, 0x04, + 0x01, 0x00, + 0x01, + 0x0E, 0x02, 0x00, + 0x00, + + /* VS_INPUT_HEADER @ 134 */ + 14, 0x24, 0x01, + 0x01, /* bNumFormats */ + 76, 0x00, /* wTotalLength 14+11+30+15+6=76(0x4C) */ + 0x85, /* bEndpointAddress */ + 0x00, + 0x04, /* bTerminalLink */ + 0x03, /* bStillCaptureMethod */ + 0x00, /* bTriggerSupport */ + 0x00, /* bTriggerUsage */ + 0x01, /* bControlSize */ + 0x00, /* bmaControls */ + + /* VS_FORMAT_MJPEG @ 134+14=148 */ + 11, 0x24, 0x06, + 0x01, /* bFormatIndex */ + 0x01, /* bNumFrameDescriptors */ + 0x01, /* bmFlags */ + 0x01, /* bDefaultFrameIndex */ + 0x00, 0x00, + 0x02, /* bmInterlaceFlags */ + 0x00, /* bCopyProtect */ + + /* VS_FRAME_MJPEG @ 148+11=159 */ + 30, 0x24, 0x07, + 0x01, /* bFrameIndex */ + 0x02, /* bmCapabilities */ + 0xA0, 0x00, /* wWidth */ + 0x78, 0x00, /* wHeight */ + 0x00, 0x65, 0x04, 0x00, /* dwMinBitRate */ + 0x00, 0xA0, 0x0F, 0x00, /* dwMaxBitRate */ + 0x00, 0x08, 0x00, 0x00, /* dwMaxVideoFrameBufSize */ + 0x2A, 0x2C, 0x0A, 0x00, /* dwDefaultFrameInterval */ + 0x01, /* bFrameIntervalType */ + 0x2A, 0x2C, 0x0A, 0x00, /* dwFrameInterval(1) */ + + /* VS_STILL_FRAME @ 159+30=189 */ + 15, 0x24, 0x03, + 0x86, /* bEndpointAddress */ + 0x02, /* bNumImageSizePatterns */ + 0x20, 0x03, /* wWidth 800 */ + 0x58, 0x02, /* wHeight 600 */ + 0x20, 0x03, /* wWidth */ + 0x20, 0x03, /* wHeight */ + 0x01, /* bNumCompressionPtr */ + 0x64, /* bCompression 1:100 */ + + /* VS_COLORFORMAT @ 189+15=204 */ + 0x06, 0x24, 0x0D, + 0x00, 0x00, 0x00, + + /* Bulk endpoint 0x86 @ 204+6=210 */ + 0x07, 0x05, + 0x86, + 0x02, + 0x40, 0x00, + 0x00, + + /* VideoStreaming Interface 1.1 @ 210+7=217; 9+7+7=23 */ + 0x09, 0x04, + 0x01, 0x01, + 0x02, + 0x0E, 0x02, 0x00, + 0x00, + + /* ISO Endpoint 0x85 @ 217+9=226 */ + 0x07, 0x05, + 0x85, + 0x05, + 0x00, 0x02, + 0x01, + + /* Bulk Endpoint 0x86 @ 226+7=233 */ + 0x07, 0x05, + 0x86, + 0x02, + 0x40, 0x00, + 0x00, + + /* VideoStreaming Interface 2.0 @ 233+7=240; 9+78=87 */ + 0x09, 0x04, + 0x02, 0x00, + 0x00, + 0x0E, 0x02, 0x00, + 0x00, + + /* VS_INPUT_HEADER @ 240+9=249 */ + 14, 0x24, 0x01, + 0x01, /* bNumFormats */ + 78, 0x00, /* wTotalLength 14+28+30+6=78(0x4E) */ + 0x87, /* bEndpointAddress */ + 0x00, + 0x06, /* bTerminalLink */ + 0x00, /* bStillCaptureMethod */ + 0x00, /* bTriggerSupport */ + 0x00, /* bTriggerUsage */ + 0x01, /* bControlSize */ + 0x00, /* bmaControls */ + + /* VS_FORMAT_FRAME_BASED @ 156+0xE=170 */ + 28, 0x24, 0x10, + 0x01, /* bFormatIndex */ + 0x01, /* bNumFrameDescriptors */ + 'H','2','6','4', + 0x00,0x00, + 0x10,0x00, + 0x80,0x00, + 0x00,0xAA,0x00,0x38,0x9B,0x71,/* guidFormat */ + 16, /* bBitsPerPixel */ + 0x01, /* bDefaultFrameIndex */ + 0x00, 0x00, /* bAspectRatioX, bAspectRatioY */ + 0x02, /* bmInterlaceFlags */ + 0x00, /* bCopyProtect */ + 0x00, /* bVariableSize */ + + /* VS_FRAME_H264 */ + 30, 0x24, 0x5/*0x11*/, + 0x01, /* bFrameIndex */ + 0x02, /* bmCapabilities */ + 0xA0, 0x00, /* wWidth */ + 0x78, 0x00, /* wHeight */ + 0x00, 0x65, 0x04, 0x00, /* dwMinBitRate */ + 0x00, 0xA0, 0x0F, 0x00, /* dwMaxBitRate */ + 0x00, 0x08, 0x00, 0x00, /* dwMaxVideoFrameBufSize */ + 0x2A, 0x2C, 0x0A, 0x00, /* dwDefaultFrameInterval */ + 0x01, /* bFrameIntervalType */ + 0x2A, 0x2C, 0x0A, 0x00, /* dwFrameInterval(1) */ + + /* VS_COLORFORMAT */ + 6, 0x24, 0x0D, + 0x00, 0x00, 0x00, + + /* VideoStreaming Interface 2.1: 9+7=16 */ + 0x09, 0x04, + 0x02, 0x01, + 0x01, + 0x0E, 0x02, 0x00, + 0x00, + + /* ISO Endpoint 0x87 */ + 0x07, 0x05, + 0x87, + 0x05, + 0x00, 0x02, + 0x01, +}; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_full_speed) +#define device_framework_high_speed device_framework_full_speed + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 + }; + +static UX_TEST_SETUP _SetAddress = UX_TEST_SETUP_SetAddress; +static UX_TEST_SETUP _GetDeviceDescriptor = UX_TEST_SETUP_GetDevDescr; +static UX_TEST_SETUP _GetConfigDescriptor = UX_TEST_SETUP_GetCfgDescr; +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +/* Test interactions */ + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION normal_enum_replace[] = { +/* 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, &_GetDeviceDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 0, 8, 0, + UX_SUCCESS, UX_NULL}, +{ UX_HCD_TRANSFER_REQUEST, &_GetDeviceDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 0, 18, 0, + UX_SUCCESS, UX_NULL}, +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 18, UX_CONFIGURATION_DESCRIPTOR_LENGTH, 0, + UX_SUCCESS, UX_NULL}, +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 18, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 18, 0, + UX_SUCCESS, UX_NULL}, +{ 0 } +} +; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT test_slave_change_function(ULONG change) +{ + return 0; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_VIDEO *video_inst = (UX_HOST_CLASS_VIDEO *) inst; +UX_INTERFACE *interface_inst = video_inst -> ux_host_class_video_streaming_interface; + stepinfo("H_Video_Change %lx: %p %p\n", event, (void*)cls, inst); + switch(event) + { + + case UX_DEVICE_INSERTION: + if (interface_inst -> ux_interface_descriptor.bInterfaceNumber == 1) + host_video_1 = video_inst; + if (interface_inst -> ux_interface_descriptor.bInterfaceNumber == 2) + host_video_2 = video_inst; + break; + + case UX_DEVICE_REMOVAL: + if (host_video_1 == video_inst) + host_video_1 = UX_NULL; + if (host_video_2 == video_inst) + host_video_2 = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_dummy_instance_activate(VOID *dummy_instance) +{ + if (device_dummy[0] == UX_NULL) + { + device_dummy[0] = (UX_DEVICE_CLASS_DUMMY *)dummy_instance; + return; + } + if (device_dummy[1] == UX_NULL) + { + device_dummy[1] = (UX_DEVICE_CLASS_DUMMY *)dummy_instance; + return; + } +} +static VOID test_dummy_instance_deactivate(VOID *dummy_instance) +{ + if (device_dummy[0] == dummy_instance) + device_dummy[0] = UX_NULL; + if (device_dummy[1] == dummy_instance) + device_dummy[1] = UX_NULL; +} +static UX_SLAVE_TRANSFER _last_control_transfer; +static UCHAR _last_control_data[64]; +static UCHAR _probe_control_data[UX_HOST_CLASS_VIDEO_PROBE_COMMIT_LENGTH] = +{ + 0, 0, /* bmHint */ + 1, /* bFormatIndex */ + 1, /* bFrameIndex */ + UX_DW0(666666),UX_DW1(666666),UX_DW2(666666),UX_DW3(666666), /* dwFrameInterval */ + UX_W0(0), UX_W1(0), /* wKeyFrameRate */ + UX_W0(0), UX_W1(0), /* wPFrameRate */ + UX_W0(0), UX_W1(0), /* wCompQuality */ + UX_W0(0), UX_W1(0), /* wCompQuality */ + UX_W0(0), UX_W1(0), /* wDelay */ + UX_DW0(460800),UX_DW1(460800),UX_DW2(460800),UX_DW3(460800), /* dwMaxVideoFrameSize @ 18 */ + UX_DW0(256),UX_DW1(256),UX_DW2(256),UX_DW3(256), /* dwMaxPayloadTransferSize @ 22 */ + UX_DW0(6000000),UX_DW1(6000000),UX_DW2(6000000),UX_DW3(6000000), /* dwClockFrequency */ + 0, /* bmFramingInfo */ + 0, /* bPreferedVersion */ + 0, /* bMinVersion */ + 0, /* bMaxVersion */ +}; +static VOID test_dummy_instance_control_request(UX_DEVICE_CLASS_DUMMY *dummy_instance, + UX_SLAVE_TRANSFER *transfer) +{ +USHORT req_length = _ux_utility_short_get(transfer->ux_slave_transfer_request_setup + 6); +UCHAR cs = *(transfer->ux_slave_transfer_request_setup + 4); +#if 0 + printf("D_Video_Req %lx: %x %x, %lx %lx %lx; %ld/%ld\n", + transfer->ux_slave_transfer_request_phase, + transfer->ux_slave_transfer_request_setup[0], + transfer->ux_slave_transfer_request_setup[1], + _ux_utility_short_get(transfer->ux_slave_transfer_request_setup + 2), + _ux_utility_short_get(transfer->ux_slave_transfer_request_setup + 4), + _ux_utility_short_get(transfer->ux_slave_transfer_request_setup + 6), + transfer->ux_slave_transfer_request_actual_length, + transfer->ux_slave_transfer_request_requested_length); +#endif + _ux_utility_memory_copy(&_last_control_transfer, transfer, sizeof(UX_SLAVE_TRANSFER)); + if (transfer->ux_slave_transfer_request_setup[0] & 0x80) /* GET */ + { + switch(cs) + { + case UX_HOST_CLASS_VIDEO_VS_PROBE_CONTROL: + _ux_utility_memory_copy(transfer->ux_slave_transfer_request_data_pointer, + _probe_control_data, + UX_MIN(req_length, sizeof(_probe_control_data))); + _ux_device_stack_transfer_request(transfer, sizeof(_probe_control_data), req_length); + break; + case UX_HOST_CLASS_VIDEO_VS_COMMIT_CONTROL: + default: + _ux_utility_memory_copy(transfer->ux_slave_transfer_request_data_pointer, + _probe_control_data/*_last_control_data*/, + req_length); + _ux_device_stack_transfer_request(transfer, req_length, req_length); + } + } + else /* SET */ + { + _ux_utility_memory_copy(_last_control_data, + transfer->ux_slave_transfer_request_data_pointer, + req_length); + /* Nothing to SET. */ + } +} +static VOID test_dummy_instance_change(UX_DEVICE_CLASS_DUMMY *dummy_instance) +{ +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = ux_test_regular_memory_free(); + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_enum_sem_get_count = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +static VOID ux_test_system_host_enum_hub_function(VOID) +{ + enum_counter ++; +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_host_class_video_format_frame_based_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + printf("Running ux_host_class_video VS_FORMAT_FRAME_BASED Test.............. "); +#if !(UX_TEST_MULTI_IFC_OVER(3) && UX_TEST_MULTI_ALT_ON) + printf("SKIP!\n"); + test_control_return(0); + return; +#endif + if (UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH < DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED) + { + printf("SKIP (D REQ BUF insufficient)!\n"); + test_control_return(0); + return; + } + + /* 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(); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + if (status != UX_SUCCESS) + { + + printf(" ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_video_name, ux_host_class_video_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, + test_slave_change_function); + if(status!=UX_SUCCESS) + { + + printf(" ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a dummy device. */ + _ux_utility_memory_set(&device_dummy_parameter, 0, sizeof(device_dummy_parameter)); + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks. + ux_device_class_dummy_instance_activate = test_dummy_instance_activate; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks. + ux_device_class_dummy_instance_deactivate = test_dummy_instance_deactivate; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks. + ux_device_class_dummy_change = test_dummy_instance_change; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks. + ux_device_class_dummy_control_request = test_dummy_instance_control_request; + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, + _ux_device_class_dummy_entry, + 1, 0, &device_dummy_parameter); + status |= ux_device_stack_class_register(_ux_system_slave_class_dpump_name, + _ux_device_class_dummy_entry, + 1, 1, &device_dummy_parameter); + status |= ux_device_stack_class_register(_ux_system_slave_class_dpump_name, + _ux_device_class_dummy_entry, + 1, 2, &device_dummy_parameter); + if(status != UX_SUCCESS) + { + + printf(" ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_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(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +ULONG mem_free; +ULONG loop; +ULONG parameter_u32[64/4]; +USHORT *parameter_u16 = (USHORT*)parameter_u32; +UCHAR *parameter_u8 = (UCHAR*)parameter_u32; +UX_HOST_CLASS_VIDEO_PARAMETER_FORMAT_DATA format_data; +UX_HOST_CLASS_VIDEO_PARAMETER_FRAME_DATA frame_data; + + + stepinfo("\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Find the video class and wait for the link to be up. */ + for (loop = 0; loop < 100; loop ++) + if (host_video_1 != UX_NULL && host_video_2 != UX_NULL) + break; + if (host_video_1 == UX_NULL || host_video_2 == UX_NULL) + { + printf("ERROR #%d: enum fail", __LINE__); + test_control_return(1); + } + if (host_video_1->ux_host_class_video_feature_unit_id != 5) + { + printf("ERROR #%d: wrong feature bUnitID 0x%lx\n", __LINE__, host_video_1->ux_host_class_video_feature_unit_id); + test_control_return(1); + } + if (host_video_1->ux_host_class_video_terminal_id != 2) + { + printf("ERROR #%d: wrong input bTerminalID 0x%lx\n", __LINE__, host_video_1->ux_host_class_video_terminal_id); + test_control_return(1); + } + if (host_video_1->ux_host_class_video_number_formats != 1) + { + printf("ERROR #%d: wrong VS_HEADER bNumFormats %ld\n", __LINE__, host_video_1->ux_host_class_video_number_formats); + test_control_return(1); + } + if (host_video_1->ux_host_class_video_length_formats != 0x004C) + { + printf("ERROR #%d: wrong VS_HEADER wTotalLength 0x%lx\n", __LINE__, host_video_1->ux_host_class_video_length_formats); + test_control_return(1); + } + if (host_video_1->ux_host_class_video_format_address != + (host_video_1->ux_host_class_video_configuration_descriptor + 134)) + { + printf("ERROR #%d: wrong VS_HEADER addr %p <> %p\n", __LINE__, + host_video_1->ux_host_class_video_format_address, + (host_video_1->ux_host_class_video_configuration_descriptor + 134)); + test_control_return(1); + } + + if (host_video_2->ux_host_class_video_feature_unit_id != 5) + { + printf("ERROR #%d: wrong feature bUnitID 0x%lx\n", __LINE__, host_video_2->ux_host_class_video_feature_unit_id); + test_control_return(1); + } + if (host_video_2->ux_host_class_video_terminal_id != 2) + { + printf("ERROR #%d: wrong input bTerminalID 0x%lx\n", __LINE__, host_video_2->ux_host_class_video_terminal_id); + test_control_return(1); + } + if (host_video_2->ux_host_class_video_number_formats != 1) + { + printf("ERROR #%d: wrong VS_HEADER bNumFormats %ld\n", __LINE__, host_video_2->ux_host_class_video_number_formats); + test_control_return(1); + } + if (host_video_2->ux_host_class_video_length_formats != 78) + { + printf("ERROR #%d: wrong VS_HEADER wTotalLength 0x%lx\n", __LINE__, host_video_2->ux_host_class_video_length_formats); + test_control_return(1); + } + if (host_video_2->ux_host_class_video_format_address != + (host_video_2->ux_host_class_video_configuration_descriptor + 249)) + { + printf("ERROR #%d: wrong VS_HEADER addr %p <> %p\n", __LINE__, + host_video_2->ux_host_class_video_format_address, + (host_video_2->ux_host_class_video_configuration_descriptor + 249)); + test_control_return(1); + } + + mem_free = ux_test_regular_memory_free(); + + /* Test ioctl(UX_HOST_CLASS_VIDEO_IOCTL_GET_FORMAT_DATA) */ + format_data.ux_host_class_video_parameter_format_requested = 0; + status = ux_host_class_video_ioctl(host_video_1, UX_HOST_CLASS_VIDEO_IOCTL_GET_FORMAT_DATA, &format_data); + UX_TEST_ASSERT(status == UX_HOST_CLASS_VIDEO_WRONG_TYPE); + format_data.ux_host_class_video_parameter_format_requested = 1; + status = ux_host_class_video_ioctl(host_video_1, UX_HOST_CLASS_VIDEO_IOCTL_GET_FORMAT_DATA, &format_data); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(format_data.ux_host_class_video_parameter_format_subtype == UX_HOST_CLASS_VIDEO_VS_FORMAT_MJPEG); + UX_TEST_ASSERT(format_data.ux_host_class_video_parameter_format_guid == UX_NULL); + UX_TEST_ASSERT(format_data.ux_host_class_video_parameter_number_frame_descriptors == 1); + format_data.ux_host_class_video_parameter_format_requested = 1; + status = ux_host_class_video_ioctl(host_video_2, UX_HOST_CLASS_VIDEO_IOCTL_GET_FORMAT_DATA, &format_data); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(format_data.ux_host_class_video_parameter_format_subtype == UX_HOST_CLASS_VIDEO_VS_FORMAT_FRAME_BASED); + UX_TEST_ASSERT(format_data.ux_host_class_video_parameter_format_guid != UX_NULL); + UX_TEST_ASSERT(format_data.ux_host_class_video_parameter_format_guid[0] == 'H'); + UX_TEST_ASSERT(format_data.ux_host_class_video_parameter_format_guid[1] == '2'); + UX_TEST_ASSERT(format_data.ux_host_class_video_parameter_format_guid[2] == '6'); + UX_TEST_ASSERT(format_data.ux_host_class_video_parameter_format_guid[3] == '4'); + UX_TEST_ASSERT(format_data.ux_host_class_video_parameter_number_frame_descriptors == 1); + + /* Test _ux_host_class_video_frame_parameters_set. */ + status = _ux_host_class_video_frame_parameters_set(host_video_1, + UX_HOST_CLASS_VIDEO_VS_FORMAT_MJPEG, 160, 120, 666666); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ERROR #%d: set parameters fail 0x%x\n", __LINE__, status); + _ux_utility_long_put(_probe_control_data + 22, 0); + status = _ux_host_class_video_frame_parameters_set(host_video_1, + UX_HOST_CLASS_VIDEO_VS_FORMAT_MJPEG, 160, 120, 666666); + UX_TEST_ASSERT_MESSAGE(status != UX_SUCCESS, "ERROR #%d: set parameters should fail\n", __LINE__); + _ux_utility_long_put(_probe_control_data + 22, 1024 * 3 + 1); + status = _ux_host_class_video_frame_parameters_set(host_video_1, + UX_HOST_CLASS_VIDEO_VS_FORMAT_MJPEG, 160, 120, 666666); + UX_TEST_ASSERT_MESSAGE(status != UX_SUCCESS, "ERROR #%d: set parameters should fail\n", __LINE__); + UX_TEST_ASSERT(mem_free == ux_test_regular_memory_free()); + + _ux_utility_long_put(_probe_control_data + 22, 256); + status = _ux_host_class_video_frame_parameters_set(host_video_2, + UX_HOST_CLASS_VIDEO_VS_FORMAT_FRAME_BASED, 160, 120, 666666); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ERROR #%d: set parameters fail 0x%x\n", __LINE__, status); + _ux_utility_long_put(_probe_control_data + 22, 0); + status = _ux_host_class_video_frame_parameters_set(host_video_2, + UX_HOST_CLASS_VIDEO_VS_FORMAT_FRAME_BASED, 160, 120, 666666); + UX_TEST_ASSERT_MESSAGE(status != UX_SUCCESS, "ERROR #%d: set parameters should fail\n", __LINE__); + _ux_utility_long_put(_probe_control_data + 22, 1024 * 3 + 1); + status = _ux_host_class_video_frame_parameters_set(host_video_2, + UX_HOST_CLASS_VIDEO_VS_FORMAT_FRAME_BASED, 160, 120, 666666); + UX_TEST_ASSERT_MESSAGE(status != UX_SUCCESS, "ERROR #%d: set parameters should fail\n", __LINE__); + + UX_TEST_ASSERT(mem_free == ux_test_regular_memory_free()); + + /* Test video start (failed due to bandwidth 512 limit, see endpoint wMaxPacketSize). */ + _ux_utility_long_put(_probe_control_data + 22, 3072); + status = ux_host_class_video_start(host_video_1); + UX_TEST_ASSERT_MESSAGE(status != UX_SUCCESS, "ERROR #%d: start should fail\n", __LINE__); + UX_TEST_ASSERT(mem_free == ux_test_regular_memory_free()); + status = ux_host_class_video_start(host_video_2); + UX_TEST_ASSERT_MESSAGE(status != UX_SUCCESS, "ERROR #%d: start should fail\n", __LINE__); + UX_TEST_ASSERT(mem_free == ux_test_regular_memory_free()); + + /* Test video start (success). */ + _ux_utility_long_put(_probe_control_data + 22, 512); + status = ux_host_class_video_start(host_video_1); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ERROR #%d: start fail 0x%x", __LINE__, status); + UX_TEST_ASSERT(mem_free == ux_test_regular_memory_free()); + status = ux_host_class_video_stop(host_video_1); + UX_TEST_ASSERT(status == UX_SUCCESS); + status = ux_host_class_video_start(host_video_2); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ERROR #%d: start fail 0x%x", __LINE__, status); + UX_TEST_ASSERT(mem_free == ux_test_regular_memory_free()); + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + if (host_video_1 != UX_NULL) + { + + printf("ERROR #13: instance not removed when disconnect"); + test_control_return(1); + } + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_dpump_name, _ux_device_class_dummy_entry); + status |= ux_device_stack_class_unregister(_ux_system_slave_class_dpump_name, _ux_device_class_dummy_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); + } +} diff --git a/test/regression/usbx_ux_host_class_video_format_h264_test.c b/test/regression/usbx_ux_host_class_video_format_h264_test.c new file mode 100644 index 00000000..263599f7 --- /dev/null +++ b/test/regression/usbx_ux_host_class_video_format_h264_test.c @@ -0,0 +1,952 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_dummy.h" +#include "ux_device_stack.h" +#include "ux_host_class_video.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); + +static VOID ux_test_hcd_entry_should_not_be_called(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_disconnect(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +static VOID ux_test_system_host_enum_hub_function(VOID); + +/* Define global data structures. */ +UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +UX_HOST_CLASS_VIDEO *host_video_1 = UX_NULL; +UX_HOST_CLASS_VIDEO *host_video_2 = UX_NULL; + +ULONG enum_counter; + +ULONG error_counter; + +ULONG set_cfg_counter; + +ULONG rsc_mem_free_on_set_cfg; +ULONG rsc_sem_on_set_cfg; +ULONG rsc_sem_get_on_set_cfg; +ULONG rsc_mutex_on_set_cfg; + +ULONG rsc_enum_sem_usage; +ULONG rsc_enum_sem_get_count; +ULONG rsc_enum_mutex_usage; +ULONG rsc_enum_mem_usage; + +static UX_DEVICE_CLASS_DUMMY *device_dummy[2] = {UX_NULL, UX_NULL}; +static UX_DEVICE_CLASS_DUMMY_PARAMETER device_dummy_parameter; + +/* Define device framework. */ + +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0xEF bDeviceClass: Composite class code + 0x02 bDeviceSubclass: class sub code + 0x00 bDeviceProtocol: Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 18, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Configuration 1 descriptor 9 bytes @ 0 */ + 0x09, 0x02, + 0x81, 0x01, /* wTotalLength 9+8+108+92+23+129+16=385(0x181) */ + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor @ 9 */ + 0x08, 0x0b, 0x00, 0x03, 0x0E, 0x03, 0x00, 0x00, + + /* VideoControl Interface Descriptor Requirement @ 17; 9+87+7+5=108 */ + 0x09, 0x04, + 0x00, 0x00, + 0x01, + 0x0E, 0x01, 0x01, + 0x00, + + /* VC_HEADER Descriptor @ 26 */ + 14, 0x24, 0x01, + 0x50, 0x01, + 87, 0x00, /* wTotalLength: 14+18+16+8+13+9+9=87 */ + 0x00, 0x00, 0x00, 0x00, + 0x02, /* bInCollection */ + 0x01, /* baInterfaceNr(1) */ + 0x02, /* baInterfaceNr(2) */ + + /* Input Terminal Descriptor (Camera) @ 40 */ + 18, 0x24, 0x02, + 0x02, /* bTerminalID */ + 0x01, 0x02, /* wTerminalType ITT_CAMERA */ + 0x00, + 0x00, + 0x00, 0x00, /* wObjectiveFocalLengthMin */ + 0x00, 0x00, /* wObjectiveFocalLengthMax */ + 0x00, 0x00, /* wOcularFocalLength */ + 0x03, /* bControlSize */ + 0x00, 0x02, 0x00, /* bmControls */ + + /* Input Terminal Descriptor (Media Transport) @ 58 */ + 16, 0x24, 0x02, + 0x03, /* bTerminalID */ + 0x02, 0x02, /* wTerminalType ITT_MEDIA_TRANSPORT_INPUT */ + 0x00, + 0x00, + 0x01, /* bControlSize */ + 0x0D, /* bmControls */ + 0x05, /* bTransportModeSize */ + 0xAF, 0xFF, 0xFF, 0x7F, 0x00, /* bmTransportModes */ + + /* Selector Unit Descriptor @ 74 */ + 0x08, 0x24, 0x04, + 0x01, /* bUnitID */ + 0x02, /* bNrInPins */ + 0x02, /* baSourceID(1) */ + 0x03, /* baSourceID(2) */ + 0x00, + + /* Processing Unit Descriptor @ 82 */ + 13, 0x24, 0x05, + 0x05, /* bUnitID */ + 0x01, /* bSourceID */ + 0x00, 0x00, /* wMaxMultiplier */ + 0x03, /* bControlSize */ + 0x00, 0x00, 0x00, /* bmControls */ + 0x00, + 0x00, /* bmVideoStandards */ + + /* Output Terminal Descriptor @ 95 */ + 0x09, 0x24, 0x03, + 0x04, /* bTerminalID */ + 0x01, 0x01, /* wTerminalType TT_STREAMING */ + 0x00, + 0x05, /* bSourceID */ + 0x00, + + /* Output Terminal Descriptor @ 104 */ + 0x09, 0x24, 0x03, + 0x06, /* bTerminalID */ + 0x01, 0x01, /* wTerminalType TT_STREAMING */ + 0x00, + 0x05, /* bSourceID */ + 0x00, + + /* Interrupt Endpoint 0x83 descriptor @ 113 */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0x0A, + + /* CS_ENDPOINT @ 120 */ + 0x05, 0x25, 0x03, + 0x20, 0x00, /* wMaxTransferSize */ + + /* VideoStreaming Interface 1.0 @ 125; 9+76+7=92 */ + 0x09, 0x04, + 0x01, 0x00, + 0x01, + 0x0E, 0x02, 0x00, + 0x00, + + /* VS_INPUT_HEADER @ 134 */ + 14, 0x24, 0x01, + 0x01, /* bNumFormats */ + 76, 0x00, /* wTotalLength 14+11+30+15+6=76(0x4C) */ + 0x85, /* bEndpointAddress */ + 0x00, + 0x04, /* bTerminalLink */ + 0x03, /* bStillCaptureMethod */ + 0x00, /* bTriggerSupport */ + 0x00, /* bTriggerUsage */ + 0x01, /* bControlSize */ + 0x00, /* bmaControls */ + + /* VS_FORMAT_MJPEG @ 134+14=148 */ + 11, 0x24, 0x06, + 0x01, /* bFormatIndex */ + 0x01, /* bNumFrameDescriptors */ + 0x01, /* bmFlags */ + 0x01, /* bDefaultFrameIndex */ + 0x00, 0x00, + 0x02, /* bmInterlaceFlags */ + 0x00, /* bCopyProtect */ + + /* VS_FRAME_MJPEG @ 148+11=159 */ + 30, 0x24, 0x07, + 0x01, /* bFrameIndex */ + 0x02, /* bmCapabilities */ + 0xA0, 0x00, /* wWidth */ + 0x78, 0x00, /* wHeight */ + 0x00, 0x65, 0x04, 0x00, /* dwMinBitRate */ + 0x00, 0xA0, 0x0F, 0x00, /* dwMaxBitRate */ + 0x00, 0x08, 0x00, 0x00, /* dwMaxVideoFrameBufSize */ + 0x2A, 0x2C, 0x0A, 0x00, /* dwDefaultFrameInterval */ + 0x01, /* bFrameIntervalType */ + 0x2A, 0x2C, 0x0A, 0x00, /* dwFrameInterval(1) */ + + /* VS_STILL_FRAME @ 159+30=189 */ + 15, 0x24, 0x03, + 0x86, /* bEndpointAddress */ + 0x02, /* bNumImageSizePatterns */ + 0x20, 0x03, /* wWidth 800 */ + 0x58, 0x02, /* wHeight 600 */ + 0x20, 0x03, /* wWidth */ + 0x20, 0x03, /* wHeight */ + 0x01, /* bNumCompressionPtr */ + 0x64, /* bCompression 1:100 */ + + /* VS_COLORFORMAT @ 189+15=204 */ + 0x06, 0x24, 0x0D, + 0x00, 0x00, 0x00, + + /* Bulk endpoint 0x86 @ 204+6=210 */ + 0x07, 0x05, + 0x86, + 0x02, + 0x40, 0x00, + 0x00, + + /* VideoStreaming Interface 1.1 @ 210+7=217; 9+7+7=23 */ + 0x09, 0x04, + 0x01, 0x01, + 0x02, + 0x0E, 0x02, 0x00, + 0x00, + + /* ISO Endpoint 0x85 @ 217+9=226 */ + 0x07, 0x05, + 0x85, + 0x05, + 0x00, 0x02, + 0x01, + + /* Bulk Endpoint 0x86 @ 226+7=233 */ + 0x07, 0x05, + 0x86, + 0x02, + 0x40, 0x00, + 0x00, + + /* VideoStreaming Interface 2.0 @ 233+7=240; 9+120=129 */ + 0x09, 0x04, + 0x02, 0x00, + 0x00, + 0x0E, 0x02, 0x00, + 0x00, + + /* VS_INPUT_HEADER @ 240+9=249 */ + 14, 0x24, 0x01, + 0x01, /* bNumFormats */ + 120, 0x00, /* wTotalLength 14+52+48+6=120(0x78) */ + 0x87, /* bEndpointAddress */ + 0x00, + 0x06, /* bTerminalLink */ + 0x00, /* bStillCaptureMethod */ + 0x00, /* bTriggerSupport */ + 0x00, /* bTriggerUsage */ + 0x01, /* bControlSize */ + 0x00, /* bmaControls */ + + /* VS_FORMAT_H264 @ 249+14=263 */ + 52, 0x24, 0x13, + 0x01, /* bFormatIndex */ + 0x01, /* bNumFrameDescriptors */ + 0x01, /* bDefaultFrameIndex */ + 0x00, /* bMaxCodecConfigDelay */ + 0x00, /* bmSupportedSliceModes */ + 0x00, /* bmSupportedSyncFrameTypes */ + 0x00, /* bResolutionScaling */ + 0x00, /* Reserved */ + 0x00, /* bmSupportedRateControlModes */ + 0x01, 0x00, /* wMaxMBperSecOneResolutionNoScalability */ + 0x00, 0x00, /* wMaxMBperSecTwoResolutionsNoScalability */ + 0x00, 0x00, /* wMaxMBperSecThreeResolutionsNoScalability */ + 0x00, 0x00, /* wMaxMBperSecFourResolutionsNoScalability */ + 0x00, 0x00, /* wMaxMBperSecOneResolutionTemporalScalability */ + 0x00, 0x00, /* wMaxMBperSecTwoResolutionsTemporalScalability */ + 0x00, 0x00, /* wMaxMBperSecThreeResolutionsTemporalScalability */ + 0x00, 0x00, /* wMaxMBperSecFourResolutionsTemporalScalability */ + 0x00, 0x00, /* wMaxMBperSecOneResolutionTemporalQualityScalability */ + 0x00, 0x00, /* wMaxMBperSecTwoResolutionsTemporalQualityScalability */ + 0x00, 0x00, /* wMaxMBperSecThreeResolutionsTemporalQualityScalability */ + 0x00, 0x00, /* wMaxMBperSecFourResolutionsTemporalQualityScalability */ + 0x00, 0x00, /* wMaxMBperSecOneResolutionTemporalSpatialScalability */ + 0x00, 0x00, /* wMaxMBperSecTwoResolutionsTemporalSpatialScalability */ + 0x00, 0x00, /* wMaxMBperSecThreeResolutionsTemporalSpatialScalability */ + 0x00, 0x00, /* wMaxMBperSecFourResolutionsTemporalSpatialScalability */ + 0x00, 0x00, /* wMaxMBperSecOneResolutionFullScalability */ + 0x00, 0x00, /* wMaxMBperSecTwoResolutionsFullScalability */ + 0x00, 0x00, /* wMaxMBperSecThreeResolutionsFullScalability */ + 0x00, 0x00, /* wMaxMBperSecFourResolutionsFullScalability */ + + /* VS_FRAME_H264 */ + 48, 0x24, 0x14, + 0x01, /* bFrameIndex */ + 0xA0, 0x00, /* wWidth */ + 0x78, 0x00, /* wHeight */ + 0x00, 0x00, /* wSARwidth */ + 0x00, 0x00, /* wSARheight */ + 0x00, 0x00, /* wProfile */ + 0x1F, /* bLevelIDC */ + 0x00, 0x00, /* wConstrainedToolset */ + 0x00, 0x00, 0x00, 0x00, /* bmSupportedUsages */ + 0x00, 0x00, /* bmCapabilities */ + 0x00, 0x00, 0x00, 0x00, /* bmSVCCapabilities */ + 0x00, 0x00, 0x00, 0x00, /* bmMVCCapabilities */ + 0x00, 0x65, 0x04, 0x00, /* dwMinBitRate */ + 0x00, 0xA0, 0x0F, 0x00, /* dwMaxBitRate */ + 0x2A, 0x2C, 0x0A, 0x00, /* dwDefaultFrameInterval */ + 0x01, /* bNumFrameIntervals */ + 0x2A, 0x2C, 0x0A, 0x00, /* dwFrameInterval(1) */ + + /* VS_COLORFORMAT */ + 6, 0x24, 0x0D, + 0x00, 0x00, 0x00, + + /* VideoStreaming Interface 2.1: 9+7=16 */ + 0x09, 0x04, + 0x02, 0x01, + 0x01, + 0x0E, 0x02, 0x00, + 0x00, + + /* ISO Endpoint 0x87 */ + 0x07, 0x05, + 0x87, + 0x05, + 0x00, 0x02, + 0x01, +}; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_full_speed) +#define device_framework_high_speed device_framework_full_speed + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 + }; + +static UX_TEST_SETUP _SetAddress = UX_TEST_SETUP_SetAddress; +static UX_TEST_SETUP _GetDeviceDescriptor = UX_TEST_SETUP_GetDevDescr; +static UX_TEST_SETUP _GetConfigDescriptor = UX_TEST_SETUP_GetCfgDescr; +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +/* Test interactions */ + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION normal_enum_replace[] = { +/* 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, &_GetDeviceDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 0, 8, 0, + UX_SUCCESS, UX_NULL}, +{ UX_HCD_TRANSFER_REQUEST, &_GetDeviceDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 0, 18, 0, + UX_SUCCESS, UX_NULL}, +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 18, UX_CONFIGURATION_DESCRIPTOR_LENGTH, 0, + UX_SUCCESS, UX_NULL}, +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 18, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 18, 0, + UX_SUCCESS, UX_NULL}, +{ 0 } +} +; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT test_slave_change_function(ULONG change) +{ + return 0; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_VIDEO *video_inst = (UX_HOST_CLASS_VIDEO *) inst; +UX_INTERFACE *interface_inst = video_inst -> ux_host_class_video_streaming_interface; + stepinfo("H_Video_Change %lx: %p %p\n", event, (void*)cls, inst); + switch(event) + { + + case UX_DEVICE_INSERTION: + if (interface_inst -> ux_interface_descriptor.bInterfaceNumber == 1) + host_video_1 = video_inst; + if (interface_inst -> ux_interface_descriptor.bInterfaceNumber == 2) + host_video_2 = video_inst; + break; + + case UX_DEVICE_REMOVAL: + if (host_video_1 == video_inst) + host_video_1 = UX_NULL; + if (host_video_2 == video_inst) + host_video_2 = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_dummy_instance_activate(VOID *dummy_instance) +{ + if (device_dummy[0] == UX_NULL) + { + device_dummy[0] = (UX_DEVICE_CLASS_DUMMY *)dummy_instance; + return; + } + if (device_dummy[1] == UX_NULL) + { + device_dummy[1] = (UX_DEVICE_CLASS_DUMMY *)dummy_instance; + return; + } +} +static VOID test_dummy_instance_deactivate(VOID *dummy_instance) +{ + if (device_dummy[0] == dummy_instance) + device_dummy[0] = UX_NULL; + if (device_dummy[1] == dummy_instance) + device_dummy[1] = UX_NULL; +} +static UX_SLAVE_TRANSFER _last_control_transfer; +static UCHAR _last_control_data[64]; +static UCHAR _probe_control_data[UX_HOST_CLASS_VIDEO_PROBE_COMMIT_LENGTH] = +{ + 0, 0, /* bmHint */ + 1, /* bFormatIndex */ + 1, /* bFrameIndex */ + UX_DW0(666666),UX_DW1(666666),UX_DW2(666666),UX_DW3(666666), /* dwFrameInterval */ + UX_W0(0), UX_W1(0), /* wKeyFrameRate */ + UX_W0(0), UX_W1(0), /* wPFrameRate */ + UX_W0(0), UX_W1(0), /* wCompQuality */ + UX_W0(0), UX_W1(0), /* wCompQuality */ + UX_W0(0), UX_W1(0), /* wDelay */ + UX_DW0(460800),UX_DW1(460800),UX_DW2(460800),UX_DW3(460800), /* dwMaxVideoFrameSize @ 18 */ + UX_DW0(256),UX_DW1(256),UX_DW2(256),UX_DW3(256), /* dwMaxPayloadTransferSize @ 22 */ + UX_DW0(6000000),UX_DW1(6000000),UX_DW2(6000000),UX_DW3(6000000), /* dwClockFrequency */ + 0, /* bmFramingInfo */ + 0, /* bPreferedVersion */ + 0, /* bMinVersion */ + 0, /* bMaxVersion */ +}; +static VOID test_dummy_instance_control_request(UX_DEVICE_CLASS_DUMMY *dummy_instance, + UX_SLAVE_TRANSFER *transfer) +{ +USHORT req_length = _ux_utility_short_get(transfer->ux_slave_transfer_request_setup + 6); +UCHAR cs = *(transfer->ux_slave_transfer_request_setup + 4); +#if 0 + printf("D_Video_Req %lx: %x %x, %lx %lx %lx; %ld/%ld\n", + transfer->ux_slave_transfer_request_phase, + transfer->ux_slave_transfer_request_setup[0], + transfer->ux_slave_transfer_request_setup[1], + _ux_utility_short_get(transfer->ux_slave_transfer_request_setup + 2), + _ux_utility_short_get(transfer->ux_slave_transfer_request_setup + 4), + _ux_utility_short_get(transfer->ux_slave_transfer_request_setup + 6), + transfer->ux_slave_transfer_request_actual_length, + transfer->ux_slave_transfer_request_requested_length); +#endif + _ux_utility_memory_copy(&_last_control_transfer, transfer, sizeof(UX_SLAVE_TRANSFER)); + if (transfer->ux_slave_transfer_request_setup[0] & 0x80) /* GET */ + { + switch(cs) + { + case UX_HOST_CLASS_VIDEO_VS_PROBE_CONTROL: + _ux_utility_memory_copy(transfer->ux_slave_transfer_request_data_pointer, + _probe_control_data, + UX_MIN(req_length, sizeof(_probe_control_data))); + _ux_device_stack_transfer_request(transfer, sizeof(_probe_control_data), req_length); + break; + case UX_HOST_CLASS_VIDEO_VS_COMMIT_CONTROL: + default: + _ux_utility_memory_copy(transfer->ux_slave_transfer_request_data_pointer, + _probe_control_data/*_last_control_data*/, + req_length); + _ux_device_stack_transfer_request(transfer, req_length, req_length); + } + } + else /* SET */ + { + _ux_utility_memory_copy(_last_control_data, + transfer->ux_slave_transfer_request_data_pointer, + req_length); + /* Nothing to SET. */ + } +} +static VOID test_dummy_instance_change(UX_DEVICE_CLASS_DUMMY *dummy_instance) +{ +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = ux_test_regular_memory_free(); + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_enum_sem_get_count = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +static VOID ux_test_system_host_enum_hub_function(VOID) +{ + enum_counter ++; +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_host_class_video_format_h264_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + printf("Running ux_host_class_video VS_FORMAT_H264 Test..................... "); +#if !(UX_TEST_MULTI_IFC_OVER(3) && UX_TEST_MULTI_ALT_ON) + printf("SKIP!\n"); + test_control_return(0); + return; +#endif + if (UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH < DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED) + { + printf("SKIP (D REQ BUF insufficient)!\n"); + test_control_return(0); + return; + } + + /* 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(); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + if (status != UX_SUCCESS) + { + + printf(" ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_video_name, ux_host_class_video_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, + test_slave_change_function); + if(status!=UX_SUCCESS) + { + + printf(" ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a dummy device. */ + _ux_utility_memory_set(&device_dummy_parameter, 0, sizeof(device_dummy_parameter)); + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks. + ux_device_class_dummy_instance_activate = test_dummy_instance_activate; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks. + ux_device_class_dummy_instance_deactivate = test_dummy_instance_deactivate; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks. + ux_device_class_dummy_change = test_dummy_instance_change; + device_dummy_parameter.ux_device_class_dummy_parameter_callbacks. + ux_device_class_dummy_control_request = test_dummy_instance_control_request; + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, + _ux_device_class_dummy_entry, + 1, 0, &device_dummy_parameter); + status |= ux_device_stack_class_register(_ux_system_slave_class_dpump_name, + _ux_device_class_dummy_entry, + 1, 1, &device_dummy_parameter); + status |= ux_device_stack_class_register(_ux_system_slave_class_dpump_name, + _ux_device_class_dummy_entry, + 1, 2, &device_dummy_parameter); + if(status != UX_SUCCESS) + { + + printf(" ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_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(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +ULONG mem_free; +ULONG loop; +ULONG parameter_u32[64/4]; +USHORT *parameter_u16 = (USHORT*)parameter_u32; +UCHAR *parameter_u8 = (UCHAR*)parameter_u32; +UX_HOST_CLASS_VIDEO_PARAMETER_FORMAT_DATA format_data; +UX_HOST_CLASS_VIDEO_PARAMETER_FRAME_DATA frame_data; + + + stepinfo("\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Find the video class and wait for the link to be up. */ + for (loop = 0; loop < 100; loop ++) + if (host_video_1 != UX_NULL && host_video_2 != UX_NULL) + break; + if (host_video_1 == UX_NULL || host_video_2 == UX_NULL) + { + printf("ERROR #%d: enum fail", __LINE__); + test_control_return(1); + } + if (host_video_1->ux_host_class_video_feature_unit_id != 5) + { + printf("ERROR #%d: wrong feature bUnitID 0x%lx\n", __LINE__, host_video_1->ux_host_class_video_feature_unit_id); + test_control_return(1); + } + if (host_video_1->ux_host_class_video_terminal_id != 2) + { + printf("ERROR #%d: wrong input bTerminalID 0x%lx\n", __LINE__, host_video_1->ux_host_class_video_terminal_id); + test_control_return(1); + } + if (host_video_1->ux_host_class_video_number_formats != 1) + { + printf("ERROR #%d: wrong VS_HEADER bNumFormats %ld\n", __LINE__, host_video_1->ux_host_class_video_number_formats); + test_control_return(1); + } + if (host_video_1->ux_host_class_video_length_formats != 0x004C) + { + printf("ERROR #%d: wrong VS_HEADER wTotalLength 0x%lx\n", __LINE__, host_video_1->ux_host_class_video_length_formats); + test_control_return(1); + } + if (host_video_1->ux_host_class_video_format_address != + (host_video_1->ux_host_class_video_configuration_descriptor + 134)) + { + printf("ERROR #%d: wrong VS_HEADER addr %p <> %p\n", __LINE__, + host_video_1->ux_host_class_video_format_address, + (host_video_1->ux_host_class_video_configuration_descriptor + 134)); + test_control_return(1); + } + + if (host_video_2->ux_host_class_video_feature_unit_id != 5) + { + printf("ERROR #%d: wrong feature bUnitID 0x%lx\n", __LINE__, host_video_2->ux_host_class_video_feature_unit_id); + test_control_return(1); + } + if (host_video_2->ux_host_class_video_terminal_id != 2) + { + printf("ERROR #%d: wrong input bTerminalID 0x%lx\n", __LINE__, host_video_2->ux_host_class_video_terminal_id); + test_control_return(1); + } + if (host_video_2->ux_host_class_video_number_formats != 1) + { + printf("ERROR #%d: wrong VS_HEADER bNumFormats %ld\n", __LINE__, host_video_2->ux_host_class_video_number_formats); + test_control_return(1); + } + if (host_video_2->ux_host_class_video_length_formats != 120) + { + printf("ERROR #%d: wrong VS_HEADER wTotalLength 0x%lx\n", __LINE__, host_video_2->ux_host_class_video_length_formats); + test_control_return(1); + } + if (host_video_2->ux_host_class_video_format_address != + (host_video_2->ux_host_class_video_configuration_descriptor + 249)) + { + printf("ERROR #%d: wrong VS_HEADER addr %p <> %p\n", __LINE__, + host_video_2->ux_host_class_video_format_address, + (host_video_2->ux_host_class_video_configuration_descriptor + 249)); + test_control_return(1); + } + + mem_free = ux_test_regular_memory_free(); + + /* Test ioctl(UX_HOST_CLASS_VIDEO_IOCTL_GET_FORMAT_DATA) */ + format_data.ux_host_class_video_parameter_format_requested = 0; + status = ux_host_class_video_ioctl(host_video_1, UX_HOST_CLASS_VIDEO_IOCTL_GET_FORMAT_DATA, &format_data); + UX_TEST_ASSERT(status == UX_HOST_CLASS_VIDEO_WRONG_TYPE); + format_data.ux_host_class_video_parameter_format_requested = 1; + status = ux_host_class_video_ioctl(host_video_1, UX_HOST_CLASS_VIDEO_IOCTL_GET_FORMAT_DATA, &format_data); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(format_data.ux_host_class_video_parameter_format_subtype == UX_HOST_CLASS_VIDEO_VS_FORMAT_MJPEG); + UX_TEST_ASSERT(format_data.ux_host_class_video_parameter_format_guid == UX_NULL); + UX_TEST_ASSERT(format_data.ux_host_class_video_parameter_number_frame_descriptors == 1); + format_data.ux_host_class_video_parameter_format_requested = 1; + status = ux_host_class_video_ioctl(host_video_2, UX_HOST_CLASS_VIDEO_IOCTL_GET_FORMAT_DATA, &format_data); + UX_TEST_ASSERT(status == UX_SUCCESS); + UX_TEST_ASSERT(format_data.ux_host_class_video_parameter_format_subtype == UX_HOST_CLASS_VIDEO_VS_FORMAT_H264); + UX_TEST_ASSERT(format_data.ux_host_class_video_parameter_format_guid == UX_NULL); + UX_TEST_ASSERT(format_data.ux_host_class_video_parameter_number_frame_descriptors == 1); + + /* Test _ux_host_class_video_frame_parameters_set. */ + status = _ux_host_class_video_frame_parameters_set(host_video_1, + UX_HOST_CLASS_VIDEO_VS_FORMAT_MJPEG, 160, 120, 666666); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ERROR #%d: set parameters fail 0x%x\n", __LINE__, status); + _ux_utility_long_put(_probe_control_data + 22, 0); + status = _ux_host_class_video_frame_parameters_set(host_video_1, + UX_HOST_CLASS_VIDEO_VS_FORMAT_MJPEG, 160, 120, 666666); + UX_TEST_ASSERT_MESSAGE(status != UX_SUCCESS, "ERROR #%d: set parameters should fail\n", __LINE__); + _ux_utility_long_put(_probe_control_data + 22, 1024 * 3 + 1); + status = _ux_host_class_video_frame_parameters_set(host_video_1, + UX_HOST_CLASS_VIDEO_VS_FORMAT_MJPEG, 160, 120, 666666); + UX_TEST_ASSERT_MESSAGE(status != UX_SUCCESS, "ERROR #%d: set parameters should fail\n", __LINE__); + UX_TEST_ASSERT(mem_free == ux_test_regular_memory_free()); + + _ux_utility_long_put(_probe_control_data + 22, 256); + status = _ux_host_class_video_frame_parameters_set(host_video_2, + UX_HOST_CLASS_VIDEO_VS_FORMAT_H264, 160, 120, 666666); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ERROR #%d: set parameters fail 0x%x\n", __LINE__, status); + _ux_utility_long_put(_probe_control_data + 22, 0); + status = _ux_host_class_video_frame_parameters_set(host_video_2, + UX_HOST_CLASS_VIDEO_VS_FORMAT_H264, 160, 120, 666666); + UX_TEST_ASSERT_MESSAGE(status != UX_SUCCESS, "ERROR #%d: set parameters should fail\n", __LINE__); + _ux_utility_long_put(_probe_control_data + 22, 1024 * 3 + 1); + status = _ux_host_class_video_frame_parameters_set(host_video_2, + UX_HOST_CLASS_VIDEO_VS_FORMAT_H264, 160, 120, 666666); + UX_TEST_ASSERT_MESSAGE(status != UX_SUCCESS, "ERROR #%d: set parameters should fail\n", __LINE__); + + UX_TEST_ASSERT(mem_free == ux_test_regular_memory_free()); + + /* Test video start (failed due to bandwidth 512 limit, see endpoint wMaxPacketSize). */ + _ux_utility_long_put(_probe_control_data + 22, 3072); + status = ux_host_class_video_start(host_video_1); + UX_TEST_ASSERT_MESSAGE(status != UX_SUCCESS, "ERROR #%d: start should fail\n", __LINE__); + UX_TEST_ASSERT(mem_free == ux_test_regular_memory_free()); + status = ux_host_class_video_start(host_video_2); + UX_TEST_ASSERT_MESSAGE(status != UX_SUCCESS, "ERROR #%d: start should fail\n", __LINE__); + UX_TEST_ASSERT(mem_free == ux_test_regular_memory_free()); + + /* Test video start (success). */ + _ux_utility_long_put(_probe_control_data + 22, 512); + status = ux_host_class_video_start(host_video_1); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ERROR #%d: start fail 0x%x", __LINE__, status); + UX_TEST_ASSERT(mem_free == ux_test_regular_memory_free()); + status = ux_host_class_video_stop(host_video_1); + UX_TEST_ASSERT(status == UX_SUCCESS); + status = ux_host_class_video_start(host_video_2); + UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "ERROR #%d: start fail 0x%x", __LINE__, status); + UX_TEST_ASSERT(mem_free == ux_test_regular_memory_free()); + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + if (host_video_1 != UX_NULL) + { + + printf("ERROR #13: instance not removed when disconnect"); + test_control_return(1); + } + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_dpump_name, _ux_device_class_dummy_entry); + status |= ux_device_stack_class_unregister(_ux_system_slave_class_dpump_name, _ux_device_class_dummy_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); + } +} diff --git a/test/regression/usbx_ux_host_device_basic_memory_tests.c b/test/regression/usbx_ux_host_device_basic_memory_tests.c new file mode 100644 index 00000000..ec1b8e31 --- /dev/null +++ b/test/regression/usbx_ux_host_device_basic_memory_tests.c @@ -0,0 +1,1020 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_test.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +static VOID ux_test_hcd_entry_should_not_be_called(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_disconnect(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +static UCHAR cdc_acm_slave_change; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; + +static ULONG error_counter; + +static ULONG set_cfg_counter; + +static ULONG rsc_mem_alloc_cnt_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_mem_alloc_count; +static ULONG rsc_enum_sem_usage; +static ULONG rsc_enum_sem_get_count; +static ULONG rsc_enum_mutex_usage; + +/* Define device framework. */ + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 93 +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 103 +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Configuration 1 descriptor 9 bytes */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Endpoint 0x83 descriptor 7 bytes */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, /* @ 93 - 14 + 2 = 81 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, /* @ 93 - 7 + 2 = 88 */ + 0x02, + 0x40, 0x00, + 0x00, + +}; + +#define DEVICE_FRAMEWORK_EPA_POS_1_FS (DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 14 + 2) +#define DEVICE_FRAMEWORK_EPA_POS_2_FS (DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 7 + 2) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor */ + 0x05, 0x24, 0x06, + 0x00, + 0x01, + + /* Call Management Functional Descriptor */ + 0x05, 0x24, 0x01, + 0x00, + 0x01, + + /* Endpoint 0x83 descriptor */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor */ + 0x07, 0x05, 0x81, /* @ 103 - 14 + 2 = 91 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor */ + 0x07, 0x05, 0x02, /* @ 103 - 7 + 2 = 98 */ + 0x02, + 0x40, 0x00, + 0x00, + +}; + +#define DEVICE_FRAMEWORK_EPA_POS_1_HS (DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 14 + 2) +#define DEVICE_FRAMEWORK_EPA_POS_2_HS (DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 7 + 2) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 + }; + +static UX_TEST_SETUP _SetAddress = UX_TEST_SETUP_SetAddress; +static UX_TEST_SETUP _GetDeviceDescriptor = UX_TEST_SETUP_GetDevDescr; +static UX_TEST_SETUP _GetConfigDescriptor = UX_TEST_SETUP_GetCfgDescr; +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +/* Test interactions */ + +/* Disconnect on RESET: + * Host still create the EP0 and expects first SETUP request failure. + */ + +static UX_TEST_HCD_SIM_ACTION disconnect_on_reset[] = { +/* 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_RESET_PORT, NULL, + UX_TRUE , UX_TEST_PORT_STATUS_DISC, + 0 , 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_disconnect}, +#if 0 +{ UX_HCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , ux_test_hcd_entry_should_not_be_called}, +#endif +{ UX_HCD_TRANSFER_REQUEST, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, /* Request just fail on disconnect */ +{ UX_HCD_TRANSFER_REQUEST, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ UX_HCD_TRANSFER_REQUEST, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION endpoint0_create_fail[] = { +/* 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_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR}, +{ UX_HCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR}, +{ UX_HCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR}, +{ UX_HCD_TRANSFER_REQUEST, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , ux_test_hcd_entry_should_not_be_called}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION disconnect_on_SetAddress[] = { +/* 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, &_SetAddress, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_ERROR}, +{ UX_HCD_TRANSFER_REQUEST, &_SetAddress, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_ERROR}, +{ UX_HCD_TRANSFER_REQUEST, &_SetAddress, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_ERROR}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION disconnect_on_GetDevDescr[] = { +/* 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, &_GetDeviceDescriptor, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ_V, 0, UX_NULL, 0, 0, + UX_ERROR}, +{ UX_HCD_TRANSFER_REQUEST, &_GetDeviceDescriptor, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ_V, 0, UX_NULL, 0, 0, + UX_ERROR}, +{ UX_HCD_TRANSFER_REQUEST, &_GetDeviceDescriptor, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ_V, 0, UX_NULL, 0, 0, + 0, UX_NULL, + UX_TRUE}, +{ UX_HCD_TRANSFER_REQUEST, &_GetDeviceDescriptor, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ_V, 0, UX_NULL, 0, 0, + UX_ERROR}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION disconnect_on_GetCfgDescr[] = { +/* 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, &_GetConfigDescriptor, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ_V, 0, UX_NULL, 0, 0, + UX_ERROR}, /* First try */ +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ_V, 0, UX_NULL, 0, 0, + UX_ERROR}, /* Second try */ +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ_V, 0, UX_NULL, 0, 0, + UX_SUCCESS, UX_NULL, + UX_TRUE}, /* Last try first run */ +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ_V, 0, UX_NULL, 0, 0, + UX_ERROR}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION disconnect_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_ERROR}, /* First try */ +{ UX_HCD_TRANSFER_REQUEST, &_SetConfigure, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_ERROR}, /* Second try */ +{ UX_HCD_TRANSFER_REQUEST, &_SetConfigure, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_ERROR}, /* Last try */ +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION normal_enum_replace[] = { +/* 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, &_GetDeviceDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 0, 8, 0, + UX_SUCCESS, UX_NULL}, +{ UX_HCD_TRANSFER_REQUEST, &_GetDeviceDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 0, 18, 0, + UX_SUCCESS, UX_NULL}, +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 18, UX_CONFIGURATION_DESCRIPTOR_LENGTH, 0, + UX_SUCCESS, UX_NULL}, +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 18, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 18, 0, + UX_SUCCESS, UX_NULL}, +{ 0 } +} +; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static UINT test_class_cdc_acm_get(void) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_CDC_ACM *cdc_acm_host; + + + /* Find the main cdc_acm container */ + status = ux_host_stack_class_get(_ux_system_host_class_cdc_acm_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* We get the first instance of the cdc_acm device */ + do + { + + status = ux_host_stack_class_instance_get(class, 0, (void **) &cdc_acm_host); + tx_thread_sleep(10); + } while (status != UX_SUCCESS); + + /* We still need to wait for the cdc_acm status to be live */ + while (cdc_acm_host -> ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + tx_thread_sleep(10); + + /* Isolate both the control and data interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_DATA_CLASS) + { + /* This is the data interface. */ + cdc_acm_host_data = cdc_acm_host; + + /* In that case, the second one should be the control interface. */ + status = ux_host_stack_class_instance_get(class, 1, (void **) &cdc_acm_host); + + /* Check error. */ + if (status != UX_SUCCESS) + return(status); + + /* Check for the control interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + + /* This is the control interface. */ + cdc_acm_host_control = cdc_acm_host; + + return(UX_SUCCESS); + + } + } + else + { + /* Check for the control interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + + /* This is the control interface. */ + cdc_acm_host_control = cdc_acm_host; + + /* In that case, the second one should be the data interface. */ + status = ux_host_stack_class_instance_get(class, 1, (void **) &cdc_acm_host); + + /* Check error. */ + if (status != UX_SUCCESS) + return(status); + + /* Check for the data interface. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_DATA_CLASS) + { + + /* This is the data interface. */ + cdc_acm_host_data = cdc_acm_host; + + return(UX_SUCCESS); + + } + } + } + + /* Return ERROR. */ + return(UX_ERROR); +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; +} + +static VOID test_swap_framework_bulk_ep_descriptors(VOID) +{ +UCHAR tmp; + + tmp = device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_1_FS]; + device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_1_FS] = device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_2_FS]; + device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_2_FS] = tmp; + + tmp = device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_1_HS]; + device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_1_HS] = device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_2_HS]; + device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_2_HS] = tmp; +} + + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} + +static VOID ux_test_hcd_entry_should_not_be_called(UX_TEST_ACTION *action, VOID *params) +{ + + error_counter ++; +} + +static VOID ux_test_hcd_entry_disconnect(UX_TEST_ACTION *action, VOID *params) +{ + + ux_test_dcd_sim_slave_disconnect(); +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count(); + + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_enum_sem_get_count = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_host_device_basic_memory_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + printf("Running Host & Device Basic Memory Test............................. "); + + stepinfo("\n"); + + /* Reset testing counts. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + ux_test_utility_sim_mem_alloc_count_reset(); + 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_mem_alloc_error_generation_stop(); + 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(); + + /* 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 #1\n"); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + stepinfo(">>>>>>>>>>>>>>>> ux_host_stack_initialize\n"); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + if (status != UX_SUCCESS) + { + + printf(" ERROR #2\n"); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> ux_host_stack_class_register(cdc_acm)\n"); + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_entry); + if (status != UX_SUCCESS) + { + + printf(" ERROR #3\n"); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> ux_device_stack_initialize\n"); + + /* 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 #5\n"); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> ux_device_stack_class_register(cdc_acm)\n"); + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + + if(status!=UX_SUCCESS) + { + + printf(" ERROR #7\n"); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> _ux_dcd_sim_slave_initialize\n"); + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #8\n"); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> ux_host_stack_hcd_register(sim)\n"); + + /* 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 #4\n"); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> tx_thread_create(tx_test_thread_host_simulation)\n"); + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #9\n"); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> tx_thread_create(tx_test_thread_slave_simulation)\n"); + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #10\n"); + test_control_return(1); + } +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ +UINT status; +ULONG test_n; +ULONG mem_free; +ULONG retry; +UX_HCD *hcd; + + + hcd = &_ux_system_host->ux_system_host_hcd_array[0]; + + /* Find the cdc_acm class and wait for the link to be up. */ + status = test_class_cdc_acm_get(); + if (status != UX_SUCCESS) + { + + /* DPUMP basic test error. */ + printf("ERROR #11: class not found\n"); + test_control_return(1); + } + if (!cdc_acm_host_control && !cdc_acm_host_data) + { + + printf("ERROR #12: instance not detected\n"); + test_control_return(1); + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + if (cdc_acm_host_control || cdc_acm_host_data) + { + + printf("ERROR #13: instance not removed when disconnect"); + test_control_return(1); + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + + /* Reset testing counts. */ + stepinfo(">>>>>>>>>>>>>>>> Test connect & connection resource\n"); + + ux_test_utility_sim_mem_alloc_count_reset(); + ux_test_utility_sim_mutex_create_count_reset(); + ux_test_utility_sim_sem_create_count_reset(); + ux_test_utility_sim_sem_get_count_reset(); + + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + test_n = 10; + while((!cdc_acm_host_control || !cdc_acm_host_data) && test_n --) + tx_thread_sleep(10); + /* Log create counts when SetConfigure for further tests. */ + rsc_enum_mutex_usage = rsc_mutex_on_set_cfg; + rsc_enum_sem_usage = rsc_sem_on_set_cfg; + rsc_enum_sem_get_count = rsc_sem_get_on_set_cfg; + rsc_enum_mem_alloc_count = rsc_mem_alloc_cnt_on_set_cfg; + + /* Lock memory allocate logs for tests. */ + ux_test_utility_sim_mem_alloc_log_lock(); + + stepinfo("enum mem alloc count: %ld\n", rsc_enum_mem_alloc_count); + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + + /* Simulate detach and attach for FS enumeration, + and check if there is memory error in normal enumeration. + */ + stepinfo(">>>>>>>>>>>>>>>> Enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < 3; test_n++) + { + stepinfo("%4ld / 2\n", test_n); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check number of devices. */ + if (hcd->ux_hcd_nb_devices != 0) + { + printf("ERROR #%d.%ld: number of devices (%d) must be 0\n", __LINE__, test_n, hcd->ux_hcd_nb_devices); + error_counter ++; + } + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #14.%ld: Memory level different after re-enumerations %ld <> %ld\n", test_n, mem_free, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + test_control_return(1); + } + + /* Connect. */ + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait */ + for (retry = 0; (retry < 10) && (cdc_acm_host_control == UX_NULL || cdc_acm_host_data == UX_NULL); retry ++) + tx_thread_sleep(10); + + /* Check */ + if (!cdc_acm_host_control || !cdc_acm_host_data) + { + + printf("ERROR #15.%ld: Enumeration fail\n", test_n); + test_control_return(1); + } + } + + /* Simulate detach and attach for FS enumeration, + and test possible memory allocation error handlings. + */ + if (rsc_enum_mem_alloc_count) stepinfo(">>>>>>>>>>>>>>>> Memory errors enumeration test\n"); + mem_free = (~0); + for (test_n = 0; test_n < rsc_enum_mem_alloc_count; test_n ++) + { + + stepinfo("%4ld / %4ld\n", test_n, rsc_enum_mem_alloc_count - 1); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Check number of devices. */ + if (hcd->ux_hcd_nb_devices != 0) + { + printf("ERROR #%d.%ld: number of devices (%d) must be 0\n", __LINE__, test_n, hcd->ux_hcd_nb_devices); + error_counter ++; + } + + /* Update memory free level (disconnect) */ + if (mem_free == (~0)) + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + /* Check memory level */ + else if (mem_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #16.%ld: Memory level different after re-enumerations\n", test_n); + test_control_return(1); + } + + /* Set memory error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n); + + /* Count SetConfigure */ + set_cfg_counter = 0; + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + + /* Connect. */ + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Check error */ + if (set_cfg_counter) + { + + printf("ERROR #17.%ld: device detected when there is memory error\n", test_n); + test_control_return(1); + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + } + ux_test_utility_sim_mem_alloc_error_generation_stop(); + if (rsc_enum_mem_alloc_count) stepinfo("\n"); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); + } +} diff --git a/test/regression/usbx_ux_host_device_basic_tests.c b/test/regression/usbx_ux_host_device_basic_tests.c new file mode 100644 index 00000000..703c883c --- /dev/null +++ b/test/regression/usbx_ux_host_device_basic_tests.c @@ -0,0 +1,1137 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" +#include "ux_host_class_cdc_acm.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_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (64*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +static UINT test_slave_change_function(ULONG change); + +static VOID ux_test_hcd_entry_should_not_be_called(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_disconnect(UX_TEST_ACTION *action, VOID *params); +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params); + +static VOID ux_test_system_host_enum_hub_function(VOID); + +/* Define global data structures. */ +UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +UX_HOST_CLASS *class_driver; +UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; +ULONG command_received_count; +UCHAR cdc_acm_reception_buffer[UX_DEMO_RECEPTION_BUFFER_SIZE]; +UCHAR cdc_acm_xmit_buffer[UX_DEMO_XMIT_BUFFER_SIZE]; +UX_HOST_CLASS_CDC_ACM_RECEPTION cdc_acm_reception; +UCHAR *global_reception_buffer; +ULONG global_reception_size; + +UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +UCHAR cdc_acm_slave_change; +UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; +UCHAR buffer[UX_DEMO_BUFFER_SIZE]; +ULONG echo_mode; + +ULONG enum_counter; + +ULONG error_counter; + +ULONG set_cfg_counter; + +ULONG rsc_mem_free_on_set_cfg; +ULONG rsc_sem_on_set_cfg; +ULONG rsc_sem_get_on_set_cfg; +ULONG rsc_mutex_on_set_cfg; + +ULONG rsc_enum_sem_usage; +ULONG rsc_enum_sem_get_count; +ULONG rsc_enum_mutex_usage; +ULONG rsc_enum_mem_usage; + +/* Define device framework. */ + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 93 +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 103 +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Configuration 1 descriptor 9 bytes */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Endpoint 0x83 descriptor 7 bytes */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, /* @ 93 - 14 + 2 = 81 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, /* @ 93 - 7 + 2 = 88 */ + 0x02, + 0x40, 0x00, + 0x00, + +}; + +#define DEVICE_FRAMEWORK_EPA_POS_1_FS (DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 14 + 2) +#define DEVICE_FRAMEWORK_EPA_POS_2_FS (DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 7 + 2) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor */ + 0x05, 0x24, 0x06, + 0x00, + 0x01, + + /* Call Management Functional Descriptor */ + 0x05, 0x24, 0x01, + 0x00, + 0x01, + + /* Endpoint 0x83 descriptor */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor */ + 0x07, 0x05, 0x81, /* @ 103 - 14 + 2 = 91 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor */ + 0x07, 0x05, 0x02, /* @ 103 - 7 + 2 = 98 */ + 0x02, + 0x40, 0x00, + 0x00, + +}; + +#define DEVICE_FRAMEWORK_EPA_POS_1_HS (DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 14 + 2) +#define DEVICE_FRAMEWORK_EPA_POS_2_HS (DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 7 + 2) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 + }; + +static UX_TEST_SETUP _SetAddress = UX_TEST_SETUP_SetAddress; +static UX_TEST_SETUP _GetDeviceDescriptor = UX_TEST_SETUP_GetDevDescr; +static UX_TEST_SETUP _GetConfigDescriptor = UX_TEST_SETUP_GetCfgDescr; +static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure; + +/* Test interactions */ + +/* Disconnect on RESET: + * Host still create the EP0 and expects first SETUP request failure. + */ + +static UX_TEST_HCD_SIM_ACTION disconnect_on_reset[] = { +/* 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_RESET_PORT, NULL, + UX_TRUE , UX_TEST_PORT_STATUS_DISC, + 0 , 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_disconnect}, +#if 0 +{ UX_HCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , ux_test_hcd_entry_should_not_be_called}, +#endif +{ UX_HCD_TRANSFER_REQUEST, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, /* Request just fail on disconnect */ +{ UX_HCD_TRANSFER_REQUEST, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ UX_HCD_TRANSFER_REQUEST, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION endpoint0_create_fail[] = { +/* 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_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR}, +{ UX_HCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR}, +{ UX_HCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR}, +{ UX_HCD_TRANSFER_REQUEST, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , ux_test_hcd_entry_should_not_be_called}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION disconnect_on_SetAddress[] = { +/* 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, &_SetAddress, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_ERROR}, +{ UX_HCD_TRANSFER_REQUEST, &_SetAddress, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_ERROR}, +{ UX_HCD_TRANSFER_REQUEST, &_SetAddress, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_ERROR}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION disconnect_on_GetDevDescr[] = { +/* 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, &_GetDeviceDescriptor, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ_V, 0, UX_NULL, 0, 0, + UX_ERROR}, +{ UX_HCD_TRANSFER_REQUEST, &_GetDeviceDescriptor, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ_V, 0, UX_NULL, 0, 0, + UX_ERROR}, +{ UX_HCD_TRANSFER_REQUEST, &_GetDeviceDescriptor, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ_V, 0, UX_NULL, 0, 0, + 0, UX_NULL, + UX_TRUE}, +{ UX_HCD_TRANSFER_REQUEST, &_GetDeviceDescriptor, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ_V, 0, UX_NULL, 0, 0, + UX_ERROR}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION disconnect_on_GetCfgDescr[] = { +/* 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, &_GetConfigDescriptor, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ_V, 0, UX_NULL, 0, 0, + UX_ERROR}, /* First try */ +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ_V, 0, UX_NULL, 0, 0, + UX_ERROR}, /* Second try */ +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ_V, 0, UX_NULL, 0, 0, + UX_SUCCESS, UX_NULL, + UX_TRUE}, /* Last try first run */ +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ_V, 0, UX_NULL, 0, 0, + UX_ERROR}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION disconnect_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_ERROR}, /* First try */ +{ UX_HCD_TRANSFER_REQUEST, &_SetConfigure, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_ERROR}, /* Second try */ +{ UX_HCD_TRANSFER_REQUEST, &_SetConfigure, + UX_TRUE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_ERROR}, /* Last try */ +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = { +/* 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, &_SetConfigure, + UX_FALSE, UX_TEST_PORT_STATUS_DISC, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_SUCCESS, ux_test_hcd_entry_set_cfg, + UX_TRUE}, /* Invoke callback & continue */ +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION normal_enum_replace[] = { +/* 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, &_GetDeviceDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 0, 8, 0, + UX_SUCCESS, UX_NULL}, +{ UX_HCD_TRANSFER_REQUEST, &_GetDeviceDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 0, 18, 0, + UX_SUCCESS, UX_NULL}, +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 18, UX_CONFIGURATION_DESCRIPTOR_LENGTH, 0, + UX_SUCCESS, UX_NULL}, +{ UX_HCD_TRANSFER_REQUEST, &_GetConfigDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 18, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 18, 0, + UX_SUCCESS, UX_NULL}, +{ 0 } +} +; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static UINT test_class_cdc_acm_get(void) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_HOST_CLASS_CDC_ACM *cdc_acm_host; + + + /* Find the main cdc_acm container */ + status = ux_host_stack_class_get(_ux_system_host_class_cdc_acm_name, &class); + if (status != UX_SUCCESS) + return(status); + + /* We get the first instance of the cdc_acm device */ + do + { + + status = ux_host_stack_class_instance_get(class, 0, (void **) &cdc_acm_host); + tx_thread_sleep(10); + } while (status != UX_SUCCESS); + + /* We still need to wait for the cdc_acm status to be live */ + while (cdc_acm_host -> ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + tx_thread_sleep(10); + + /* Isolate both the control and data interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_DATA_CLASS) + { + /* This is the data interface. */ + cdc_acm_host_data = cdc_acm_host; + + /* In that case, the second one should be the control interface. */ + status = ux_host_stack_class_instance_get(class, 1, (void **) &cdc_acm_host); + + /* Check error. */ + if (status != UX_SUCCESS) + return(status); + + /* Check for the control interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + + /* This is the control interface. */ + cdc_acm_host_control = cdc_acm_host; + + return(UX_SUCCESS); + + } + } + else + { + /* Check for the control interfaces. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + + /* This is the control interface. */ + cdc_acm_host_control = cdc_acm_host; + + /* In that case, the second one should be the data interface. */ + status = ux_host_stack_class_instance_get(class, 1, (void **) &cdc_acm_host); + + /* Check error. */ + if (status != UX_SUCCESS) + return(status); + + /* Check for the data interface. */ + if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_DATA_CLASS) + { + + /* This is the data interface. */ + cdc_acm_host_data = cdc_acm_host; + + return(UX_SUCCESS); + + } + } + } + + /* Return ERROR. */ + return(UX_ERROR); +} + +static UINT test_slave_change_function(ULONG change) +{ + return 0; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; +} + +static VOID test_swap_framework_bulk_ep_descriptors(VOID) +{ +UCHAR tmp; + + tmp = device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_1_FS]; + device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_1_FS] = device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_2_FS]; + device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_2_FS] = tmp; + + tmp = device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_1_HS]; + device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_1_HS] = device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_2_HS]; + device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_2_HS] = tmp; +} + + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + int x = 0; +} + +static VOID ux_test_hcd_entry_should_not_be_called(UX_TEST_ACTION *action, VOID *params) +{ + + error_counter ++; +} + +static VOID ux_test_hcd_entry_disconnect(UX_TEST_ACTION *action, VOID *params) +{ + + ux_test_dcd_sim_slave_disconnect(); +} + +static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params) +{ + + set_cfg_counter ++; + + rsc_mem_free_on_set_cfg = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count(); + rsc_enum_sem_get_count = ux_test_utility_sim_sem_get_count(); + rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count(); +} + +static VOID ux_test_system_host_enum_hub_function(VOID) +{ + enum_counter ++; +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_host_device_basic_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + + printf("Running Host & Device Basic Functionality 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(); + + /* 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 #1\n"); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + if (status != UX_SUCCESS) + { + + printf(" ERROR #2\n"); + test_control_return(1); + } + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_entry); + if (status != UX_SUCCESS) + { + + printf(" ERROR #3\n"); + test_control_return(1); + } + + /* Simulates hub enum function */ + enum_counter = 0; +#if UX_MAX_DEVICES > 1 + _ux_system_host->ux_system_host_enum_hub_function = ux_test_system_host_enum_hub_function; +#endif + + /* 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, + test_slave_change_function); + if(status!=UX_SUCCESS) + { + + printf(" ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + + if(status!=UX_SUCCESS) + { + + printf(" ERROR #7\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #8\n"); + 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 #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #9\n"); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf(" ERROR #10\n"); + test_control_return(1); + } +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +ULONG mem_free; + + stepinfo("\n"); + + /* Find the cdc_acm class and wait for the link to be up. */ + status = test_class_cdc_acm_get(); + if (status != UX_SUCCESS) + { + + /* DPUMP basic test error. */ + printf("ERROR #11: class not found\n"); + test_control_return(1); + } + if (!cdc_acm_host_control && !cdc_acm_host_data) + { + + printf("ERROR #12: instance not detected\n"); + test_control_return(1); + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + if (cdc_acm_host_control || cdc_acm_host_data) + { + + printf("ERROR #13: instance not removed when disconnect"); + test_control_return(1); + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + + /* Reset testing counts. */ + stepinfo(">>>>>>>>>>>>>>>> Test connect & connection resource\n"); + ux_test_utility_sim_mutex_create_count_reset(); + ux_test_utility_sim_sem_create_count_reset(); + ux_test_utility_sim_sem_get_count_reset(); + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + tx_thread_sleep(100); + /* Log create counts when SetConfigure for further tests. */ + rsc_enum_mutex_usage = rsc_mutex_on_set_cfg; + rsc_enum_sem_usage = rsc_sem_on_set_cfg; + rsc_enum_sem_get_count = rsc_sem_get_on_set_cfg; + rsc_enum_mem_usage = mem_free - rsc_mem_free_on_set_cfg; + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + + /* Reset enum counter */ + enum_counter = 0; + + stepinfo(">>>>>>>>>>>>>>>> Test disconnect on reset\n"); + ux_test_hcd_sim_host_disconnect(); + ux_test_hcd_sim_host_set_actions(disconnect_on_reset); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + if (cdc_acm_host_control || cdc_acm_host_data) + { + + printf("ERROR #13: instance installed when disconnect on reset"); + test_control_return(1); + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); +#if UX_MAX_DEVICES > 1 + /* Enumeration should be processed */ + if (enum_counter == 0) + { + + printf("ERROR #%d: enum entry not invoked\n", __LINE__); + test_control_return(1); + } +#endif + stepinfo(">>>>>>>>>>>>>>>> Test EP0 fail\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_disconnect(); + ux_test_hcd_sim_host_set_actions(endpoint0_create_fail); + error_counter = 0; + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + if (error_counter) + { + + /* DPUMP basic test error. */ + printf("ERROR #14: detect EP transfer when EP0 creation fail\n"); + test_control_return(1); + } + if (cdc_acm_host_control || cdc_acm_host_data) + { + + printf("ERROR #15: instance installed when EP0 creation fail\n"); + test_control_return(1); + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + + stepinfo(">>>>>>>>>>>>>>>> Test disconnect on SetAddress\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_disconnect(); + ux_test_hcd_sim_host_set_actions(disconnect_on_SetAddress); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + if (cdc_acm_host_control) + { + + printf("ERROR #14: detect device when disconnect on SetAddress\n"); + test_control_return(1); + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + + stepinfo(">>>>>>>>>>>>>>>> Test disconnect on GetDeviceDescriptor\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_disconnect(); + ux_test_hcd_sim_host_set_actions(disconnect_on_GetDevDescr); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + if (cdc_acm_host_control) + { + + printf("ERROR #15: detect device when disconnect on GetDeviceDescriptor\n"); + test_control_return(1); + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + + stepinfo(">>>>>>>>>>>>>>>> Test disconnect on GetConfigureDescriptor\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_disconnect(); + ux_test_hcd_sim_host_set_actions(disconnect_on_GetCfgDescr); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + if (cdc_acm_host_control) + { + + printf("ERROR #16: detect device when disconnect on GetConfigureDescriptor\n"); + test_control_return(1); + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + + stepinfo(">>>>>>>>>>>>>>>> Test disconnect on SetConfigure\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_disconnect(); + ux_test_hcd_sim_host_set_actions(disconnect_on_SetCfg); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + if (cdc_acm_host_control) + { + + printf("ERROR #17: detect device when disconnect on SetConfigure\n"); + test_control_return(1); + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + + stepinfo(">>>>>>>>>>>>>>>> Normal replace descriptor test\n"); + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_disconnect(); + ux_test_hcd_sim_host_set_actions(normal_enum_replace); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + tx_thread_sleep(100); + if (!cdc_acm_host_control) + { + + printf("ERROR #18: no device detected when replacing DevDescr and CfgDescr\n"); + test_control_return(1); + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + + /* Swap bulk IN/OUT endpoint position. + Simulate detach and attach for HS enumeration, + and test possible mutex creation error handlings. + */ + if (rsc_enum_mutex_usage) stepinfo(">>>>>>>>>>>>>>>> Mutex errors enumeration test\n"); + for (test_n = 0; test_n < rsc_enum_mutex_usage; test_n ++) + { + + stepinfo("%ld / %ld\n", test_n, rsc_enum_mutex_usage - 1); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Swap EP address. */ + test_swap_framework_bulk_ep_descriptors(); + + /* Generate error while the test_n and after mutex are requested */ + ux_test_utility_sim_mutex_error_generation_start(test_n); + + /* Count SetConfigure */ + set_cfg_counter = 0; + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + + /* Connect. */ + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + if (set_cfg_counter) + { + + printf("ERROR #19.%ld: device detected when there is mutex error\n", test_n); + test_control_return(1); + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + } + ux_test_utility_sim_mutex_error_generation_stop(); + if (rsc_enum_mutex_usage) stepinfo("\n"); + + /* Simulate detach and attach for FS enumeration, + and test possible semaphore creation error handlings. + Note CDC ACM has two semaphore for bulk endpoints, not tested here. + */ + if (rsc_enum_sem_usage) stepinfo(">>>>>>>>>>>>>>>> Semaphore errors enumeration test\n"); + for (test_n = 0; test_n < rsc_enum_sem_usage; test_n ++) + { + + stepinfo("%2ld / %2ld\n", test_n, rsc_enum_sem_usage - 1); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Generate error while the test_n and after semaphore are requested */ + ux_test_utility_sim_sem_error_generation_start(test_n); + + /* Count SetConfigure */ + set_cfg_counter = 0; + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + + /* Connect. */ + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Check error */ + if (set_cfg_counter) + { + + printf("ERROR #21.%ld: device detected when there is semaphore error\n", test_n); + test_control_return(1); + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + } + ux_test_utility_sim_sem_error_generation_stop(); + if (rsc_enum_sem_usage) stepinfo("\n"); + + /* Simulate detach and attach for FS enumeration, + and test possible semaphore get error handlings. + */ + if (rsc_enum_sem_get_count) stepinfo(">>>>>>>>>>>>>>>> Semaphore GET errors enumeration test\n"); + for (test_n = 0; test_n < rsc_enum_sem_get_count; test_n ++) + { + + stepinfo("%2ld / %2ld\n", test_n, rsc_enum_sem_get_count - 1); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Generate error while the test_n and after semaphore are requested */ + ux_test_utility_sim_sem_get_error_generation_start(test_n); + + /* Count SetConfigure */ + set_cfg_counter = 0; + ux_test_hcd_sim_host_set_actions(log_on_SetCfg); + + /* Connect. */ + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + if (set_cfg_counter) + { + + printf("ERROR #24.%ld: device detected when there is semaphore GET error\n", test_n); + test_control_return(1); + } + stepinfo("mem free: %ld\n", _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + } + ux_test_utility_sim_sem_get_error_generation_stop(); + if (rsc_enum_sem_usage) stepinfo("\n"); + + /* Finally disconnect the device. */ + ux_device_stack_disconnect(); + + /* And deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); + } +} diff --git a/test/regression/usbx_ux_host_device_initialize_tests.c b/test/regression/usbx_ux_host_device_initialize_tests.c new file mode 100644 index 00000000..f32b32ab --- /dev/null +++ b/test/regression/usbx_ux_host_device_initialize_tests.c @@ -0,0 +1,1363 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" + +#include "ux_host_class_cdc_acm.h" +#include "ux_host_class_hid.h" +#include "ux_host_class_storage.h" +#include "ux_host_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_class_hid.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +UCHAR test_ux_system_host_class_dummy0_name[] = "ux_host_class_dummy0"; +UCHAR test_ux_system_host_class_dummy1_name[] = "ux_host_class_dummy1"; +UCHAR test_ux_system_host_class_dummy2_name[] = "ux_host_class_dummy2"; +UCHAR test_ux_system_host_class_dummy3_name[] = "ux_host_class_dummy3"; +UCHAR test_ux_system_host_class_dummy4_name[] = "ux_host_class_dummy4"; +UCHAR test_ux_system_host_class_dummy5_name[] = "ux_host_class_dummy5"; +UCHAR test_ux_system_host_class_dummy6_name[] = "ux_host_class_dummy6"; +UCHAR test_ux_system_host_class_dummy7_name[] = "ux_host_class_dummy7"; +UCHAR test_ux_system_host_class_dummy8_name[] = "ux_host_class_dummy8"; +static UINT test_ux_host_class_dummy0_entry(UX_HOST_CLASS_COMMAND *command){return UX_NO_CLASS_MATCH;} +static UINT test_ux_host_class_dummy1_entry(UX_HOST_CLASS_COMMAND *command){return UX_NO_CLASS_MATCH;} +static UINT test_ux_host_class_dummy2_entry(UX_HOST_CLASS_COMMAND *command){return UX_NO_CLASS_MATCH;} +static UINT test_ux_host_class_dummy3_entry(UX_HOST_CLASS_COMMAND *command){return UX_NO_CLASS_MATCH;} +static UINT test_ux_host_class_dummy4_entry(UX_HOST_CLASS_COMMAND *command){return UX_NO_CLASS_MATCH;} +static UINT test_ux_host_class_dummy5_entry(UX_HOST_CLASS_COMMAND *command){return UX_NO_CLASS_MATCH;} +static UINT test_ux_host_class_dummy6_entry(UX_HOST_CLASS_COMMAND *command){return UX_NO_CLASS_MATCH;} +static UINT test_ux_host_class_dummy7_entry(UX_HOST_CLASS_COMMAND *command){return UX_NO_CLASS_MATCH;} +static UINT test_ux_host_class_dummy8_entry(UX_HOST_CLASS_COMMAND *command){return UX_NO_CLASS_MATCH;} + +typedef struct TEST_HOST_CLASS_2_REG_STRUCT { + + UCHAR *class_name; + UINT (*class_entry_function)(struct UX_HOST_CLASS_COMMAND_STRUCT *); +} TEST_HOST_CLASS_2_REG ; +static TEST_HOST_CLASS_2_REG test_host_classes[] = { + {test_ux_system_host_class_dummy0_name, test_ux_host_class_dummy0_entry}, + {_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_entry}, + {test_ux_system_host_class_dummy1_name, test_ux_host_class_dummy1_entry}, + {_ux_system_host_class_hid_name, ux_host_class_hid_entry}, + {_ux_system_host_class_storage_name, ux_host_class_storage_entry}, + {test_ux_system_host_class_dummy2_name, test_ux_host_class_dummy2_entry}, + {test_ux_system_host_class_dummy3_name, test_ux_host_class_dummy3_entry}, + {test_ux_system_host_class_dummy4_name, test_ux_host_class_dummy4_entry}, + {test_ux_system_host_class_dummy5_name, test_ux_host_class_dummy5_entry}, + {test_ux_system_host_class_dummy6_name, test_ux_host_class_dummy6_entry}, +}; + +typedef struct TEST_HCD_2_REG_STRUCT { + + UCHAR *hcd_name; + UINT (*hcd_init_function)(struct UX_HCD_STRUCT *); + ULONG hcd_param1; + ULONG hcd_param2; +} TEST_HCD_2_REG; +static TEST_HCD_2_REG test_hcds[] = { + {_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0}, + {"dummy", _ux_test_hcd_sim_host_initialize, 0, 0}, + {"dummy", _ux_test_hcd_sim_host_initialize, 0, 0}, +}; + +typedef struct TEST_DEVICE_CLASS_2_REG_STRUCT { + + UCHAR *class_name; + UINT (*class_entry_function)(struct UX_SLAVE_CLASS_COMMAND_STRUCT *); + ULONG configuration_number; + ULONG interface_number; +} TEST_DEVICE_CLASS_2_REG ; +static TEST_DEVICE_CLASS_2_REG test_device_classes[] = { + {_ux_system_slave_class_dpump_name, ux_device_class_cdc_acm_entry, 1, 0}, + {_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, 1, 2}, + {_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, 2, 0}, + {_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, 2, 2}, +}; + +/* Define constants. */ +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (128 * 1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +static UINT test_ux_device_class_entry(UX_SLAVE_CLASS_COMMAND *command); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +static UCHAR cdc_acm_slave_change; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; + +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 UINT device_class_entry_return; +static UINT device_class_entry_cmd_req; + +/* Define device framework. */ + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 93 +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 103 +#define STRING_FRAMEWORK_LENGTH 47 +#define LANGUAGE_ID_FRAMEWORK_LENGTH 2 + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Configuration 1 descriptor 9 bytes */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Endpoint 0x83 descriptor 7 bytes */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, /* @ 93 - 14 + 2 = 81 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, /* @ 93 - 7 + 2 = 88 */ + 0x02, + 0x40, 0x00, + 0x00, + +}; + +#define DEVICE_FRAMEWORK_EPA_POS_1_FS (DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 14 + 2) +#define DEVICE_FRAMEWORK_EPA_POS_2_FS (DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 7 + 2) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor */ + 0x05, 0x24, 0x06, + 0x00, + 0x01, + + /* Call Management Functional Descriptor */ + 0x05, 0x24, 0x01, + 0x00, + 0x01, + + /* Endpoint 0x83 descriptor */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor */ + 0x07, 0x05, 0x81, /* @ 103 - 14 + 2 = 91 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor */ + 0x07, 0x05, 0x02, /* @ 103 - 7 + 2 = 98 */ + 0x02, + 0x40, 0x00, + 0x00, + +}; + +#define DEVICE_FRAMEWORK_EPA_POS_1_HS (DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 14 + 2) +#define DEVICE_FRAMEWORK_EPA_POS_2_HS (DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 7 + 2) + +static unsigned char device_framework_no_interface[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Configuration 1 descriptor 9 bytes */ + 0x09, 0x02, 0x09, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, +}; + +static unsigned char device_framework_no_endpoint[] = { + + 0x12, 0x01, 0x10, 0x01, + 0x00, 0x00, 0x00, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Configuration 1 descriptor 9 bytes */ + 0x09, 0x02, 0x12, 0x00, + 0x01, 0x01, 0x00, + 0x40, 0x00, + + /* Interface Descriptor */ + 0x09, 0x04, 0x00, + 0x00, + 0x00, + 0xFF, 0x01, 0x00, + 0x00, +}; + +static unsigned char device_framework_testing[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Configuration 3 descriptor 9 bytes */ + 0x09, 0x02, + 34, 0x00, /* wTotalLength */ + 1, /* bNumInterfaces */ + 3, /* bConfigurationValue */ + 0x00,0x40,0x00, /* iConfiguration, bmAttributes, bMaxPower */ + + /* Interface 1.0 descriptor 9 bytes */ + 0x09, 0x04, + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + 0x02, 0x02, 0x01,/* bInterfaceClass,SubClass,Protocol */ + 0x00, /* iInterface */ + + /* Interface 1.1 descriptor 9 bytes */ + 0x09, 0x04, + 0x00, /* bInterfaceNumber */ + 0x01, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x02, 0x02, 0x01,/* bInterfaceClass,SubClass,Protocol */ + 0x00, /* iInterface */ + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81,/* ...bEndpointAddress */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Configuration 1 descriptor 9 bytes */ + 0x09, 0x02, + 32, 0x00, /* wTotalLength */ + 1, /* bNumInterfaces */ + 1, /* bConfigurationValue */ + 0x00,0x40, 0x00, /* iConfiguration, bmAttributes, bMaxPower */ + + /* Interface 1 descriptor 9 bytes */ + 0x09, 0x04, + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x02, /* bNumEndpoints */ + 0x02, 0x02, 0x01,/* bInterfaceClass,SubClass,Protocol */ + 0x00, /* iInterface */ + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81,/* ...bEndpointAddress */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02,/* ...bEndpointAddress */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Configuration 2 descriptor 9 bytes */ + 0x09, 0x02, + 39, 0x00, /* wTotalLength */ + 1, /* bNumInterfaces */ + 2, /* bConfigurationValue */ + 0x00,0x40, 0x00, /* iConfiguration, bmAttributes, bMaxPower */ + + /* Interface 2 descriptor 9 bytes */ + 0x09, 0x04, + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x03, /* bNumEndpoints */ + 0x02, 0x02, 0x01,/* bInterfaceClass,SubClass,Protocol */ + 0x00, /* iInterface */ + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81,/* ...bEndpointAddress */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02,/* ...bEndpointAddress */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x83 descriptor 7 bytes */ + 0x07, 0x05, 0x83,/* ...bEndpointAddress */ + 0x02, + 0x40, 0x00, + 0x00, + +}; + + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT test_ux_device_class_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + device_class_entry_cmd_req = command->ux_slave_class_command_request; + return device_class_entry_return; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ +} +/* TODO: _ux_system_uninitialize, patch implement to lib if necessary */ +#if 0 +UINT _ux_system_uninitialize(VOID) +{ + + /* Delete the Mutex object used by USBX to control critical sections. */ + if (_ux_system->ux_system_mutex.tx_mutex_id != TX_CLEAR_ID) + _ux_utility_mutex_delete(&_ux_system -> ux_system_mutex); + + return(UX_SUCCESS); +} +#endif +/* TODO: _ux_device_stack_uninitialize, patch implement to lib if necessary */ +#if 0 +UINT _ux_device_stack_uninitialize(VOID) +{ +UX_SLAVE_DEVICE *device; +UX_SLAVE_ENDPOINT *endpoints_pool; +UX_SLAVE_TRANSFER *transfer_request; +ULONG endpoints_found; + + /* If trace is enabled, insert this event into the trace buffer. */ + UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_STACK_INITIALIZE, 0, 0, 0, 0, UX_TRACE_DEVICE_STACK_EVENTS, 0, 0) + + /* Get the pointer to the device. */ + device = &_ux_system_slave -> ux_system_slave_device; + + /* Free class memory. */ + if (_ux_system_slave -> ux_system_slave_class_array) + _ux_utility_memory_free(_ux_system_slave -> ux_system_slave_class_array); + + /* Allocate some memory for the Control Endpoint. First get the address of the transfer request for the + control endpoint. */ + transfer_request = &device -> ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request; + + /* Free memory for the control endpoint buffer. */ + if (transfer_request -> ux_slave_transfer_request_data_pointer) + _ux_utility_memory_free(transfer_request -> ux_slave_transfer_request_data_pointer); + + /* Get the number of endoints found in the device framework. */ + endpoints_found = device -> ux_slave_device_endpoints_pool_number; + + /* Get the endpoint pool address in the device container. */ + endpoints_pool = device -> ux_slave_device_endpoints_pool; + + /* Parse all endpoints and fee memory and semaphore. */ + while (endpoints_found-- != 0) + { + /* Free the memory for endpoint data pointer. */ + if (endpoints_pool -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer) + _ux_utility_memory_free(endpoints_pool -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer); + + /* Remove the TX semaphore for the endpoint. */ + if (endpoints_pool -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_semaphore.tx_semaphore_id != TX_CLEAR_ID) + _ux_utility_semaphore_delete(&endpoints_pool -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_semaphore); + + /* Next endpoint. */ + endpoints_pool++; + } + + /* Free the endpoint pool address in the device container. */ + if (device -> ux_slave_device_endpoints_pool) + _ux_utility_memory_free(device -> ux_slave_device_endpoints_pool); + + /* Free memory for interface pool. */ + if (device -> ux_slave_device_interfaces_pool) + _ux_utility_memory_free(device -> ux_slave_device_interfaces_pool); + + /* Return successful completion. */ + return(UX_SUCCESS); +} +#endif +#if 0 /* _ux_host_stack_uninitialize, move implement to lib if necessary */ +VOID _ux_host_stack_uninitialize(VOID) +{ + if (_ux_system_host->ux_system_host_hcd_thread.tx_thread_id != TX_CLEAR_ID) + { + + tx_thread_terminate(&_ux_system_host->ux_system_host_hcd_thread); + tx_thread_delete(&_ux_system_host->ux_system_host_hcd_thread); + } + + if (_ux_system_host->ux_system_host_enum_thread.tx_thread_id != TX_CLEAR_ID) + { + + tx_thread_terminate(&_ux_system_host->ux_system_host_enum_thread); + tx_thread_delete(&_ux_system_host->ux_system_host_enum_thread); + } + +#if defined(UX_OTG_SUPPORT) + if (_ux_system_host->ux_system_host_hnp_polling_thread.tx_thread_id != TX_CLEAR_ID) + { + tx_thread_terminate(&_ux_system_host->ux_system_host_hnp_polling_thread); + tx_thread_delete(&_ux_system_host->ux_system_host_hnp_polling_thread); + } + if (_ux_system_host->ux_system_host_hnp_polling_thread_stack) + ux_utility_memory_free(_ux_system_host->ux_system_host_hnp_polling_thread_stack); +#endif + + if (_ux_system_host->ux_system_host_hcd_semaphore.tx_semaphore_id != TX_CLEAR_ID) + ux_utility_semaphore_delete(&_ux_system_host->ux_system_host_hcd_semaphore); + + if (_ux_system_host->ux_system_host_enum_semaphore.tx_semaphore_id != TX_CLEAR_ID) + ux_utility_semaphore_delete(&_ux_system_host->ux_system_host_enum_semaphore); + + + if (_ux_system_host -> ux_system_host_enum_thread_stack) + ux_utility_memory_free(_ux_system_host -> ux_system_host_enum_thread_stack); + + if (_ux_system_host -> ux_system_host_device_array) + ux_utility_memory_free(_ux_system_host -> ux_system_host_device_array); + + if (_ux_system_host -> ux_system_host_class_array) + ux_utility_memory_free(_ux_system_host -> ux_system_host_class_array); + + if (_ux_system_host -> ux_system_host_hcd_array) + ux_utility_memory_free(_ux_system_host -> ux_system_host_hcd_array); +} +#endif + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_host_device_initialize_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +ULONG test_n; + +ULONG mem_count; +ULONG sem_count; +ULONG thread_count; + + printf("Running Host & Device Init/Uninit Test.............................. "); + + /* Enable memory logging for tests. */ + ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE); + + /* 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(); + + /* Initialize the free memory pointer */ + stack_pointer = (CHAR *) usbx_memory; + memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 2); + + stepinfo(">>>>>>>>>>>>>>>> Test ux_system_initialize\n"); + + /* Initialize with very small memory should report error */ + status = ux_system_initialize(memory_pointer, 8, UX_NULL, 0); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("ERROR #1: should report memory error when initialize with small buffer\n"); + test_control_return(1); + } + + /* Initialize with mutex error */ + ux_test_utility_sim_mutex_error_generation_start(0); + status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL,0); + if (status != UX_MUTEX_ERROR) + { + + printf("ERROR #2: should report mutex error when system mutex not created\n"); + test_control_return(1); + } + ux_test_utility_sim_mutex_error_generation_stop(); + + /* Initialize USBX Memory */ + status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE / 2, memory_pointer + UX_DEMO_MEMORY_SIZE/ 2, UX_DEMO_MEMORY_SIZE/ 2); + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #3\n"); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + stepinfo(">>>>>>>>>>>>>>>> Test ux_host_stack_initialize\n"); + + /* Initialize to check resources usage */ + _ux_system_uninitialize(); + status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL, 0); + if (status != UX_SUCCESS) + { + + printf("ERROR #4\n"); + test_control_return(1); + } + + ux_test_utility_sim_sem_create_count_reset(); + ux_test_utility_sim_thread_create_count_reset(); + ux_test_utility_sim_mem_alloc_count_reset(); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #5\n"); + test_control_return(1); + } + mem_count = ux_test_utility_sim_mem_alloc_count(); + sem_count = ux_test_utility_sim_sem_create_count(); + thread_count = ux_test_utility_sim_thread_create_count(); + +#if 1 + /* Test memory allocation errors. */ + for (test_n = 0; test_n < mem_count; test_n ++) + { + + stepinfo(" .memTest %2ld / %2ld\n", test_n, mem_count - 1); + + /* Re-initialize memory! */ + if (status == UX_SUCCESS) + _ux_host_stack_uninitialize(); + _ux_system_uninitialize(); + status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL, 0); + if (status != UX_SUCCESS) + { + + printf("ERROR #6.%ld\n", test_n); + test_control_return(1); + } + + /* Start error simulation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n); + status = ux_host_stack_initialize(test_host_change_function); + ux_test_utility_sim_mem_alloc_error_generation_stop(); + if (status != UX_MEMORY_INSUFFICIENT) + { + + printf("ERROR #7.%ld: memory error should be reported\n", test_n); + test_control_return(1); + } + } +#endif +#if 1 + /* Test semaphore creation errors. */ + for (test_n = 0; test_n < sem_count; test_n ++) + { + + stepinfo(" .semTest %2ld / %2ld\n", test_n, sem_count - 1); + + /* Re-initialize memory! */ + if (status == UX_SUCCESS) + _ux_host_stack_uninitialize(); + _ux_system_uninitialize(); + status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL, 0); + if (status != UX_SUCCESS) + { + + printf("ERROR #8.%ld\n", test_n); + test_control_return(1); + } + + /* Start error simulation */ + ux_test_utility_sim_sem_error_generation_start(test_n); + status = ux_host_stack_initialize(test_host_change_function); + ux_test_utility_sim_sem_error_generation_stop(); + if (status != UX_SEMAPHORE_ERROR) + { + + printf("ERROR #9.%ld: semaphore error should be reported\n", test_n); + test_control_return(1); + } + } +#endif +#if 1 + /* Test thread creation errors. */ + for (test_n = 0; test_n < thread_count; test_n ++) + { + + stepinfo(" .threadTest %2ld / %2ld\n", test_n, thread_count - 1); + + /* Re-initialize memory! */ + if (status == UX_SUCCESS) + _ux_host_stack_uninitialize(); + _ux_system_uninitialize(); + status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL, 0); + if (status != UX_SUCCESS) + { + + printf("ERROR #10.%ld\n", test_n); + test_control_return(1); + } + + /* Start error simulation */ + ux_test_utility_sim_thread_error_generation_start(test_n); + status = ux_host_stack_initialize(test_host_change_function); + ux_test_utility_sim_thread_error_generation_stop(); + if (status != UX_THREAD_ERROR) + { + + printf("ERROR #11.%ld: thread error should be reported\n", test_n); + test_control_return(1); + } + } +#endif + + _ux_host_stack_uninitialize(); + _ux_system_uninitialize(); + status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL, 0); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: ux_system_initialize fail\n", __LINE__); + test_control_return(1); + } + status = ux_host_stack_initialize(test_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: ux_host_stack_initialize fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test ux_host_stack_class_register\n"); + + for (test_n = 0; test_n < UX_MAX_CLASS_DRIVER; test_n ++) + { + stepinfo(" .classReg %2ld / %2d : %s\n", test_n, UX_MAX_CLASS_DRIVER - 1, test_host_classes[test_n].class_name); + + status = ux_host_stack_class_register(test_host_classes[test_n].class_name, test_host_classes[test_n].class_entry_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + } + + /* Register again report error */ +#if UX_MAX_CLASS_DRIVER == 1 + status = ux_host_stack_class_register(test_ux_system_host_class_dummy0_name, test_ux_host_class_dummy0_entry); +#else + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_entry); +#endif + if (status != UX_HOST_CLASS_ALREADY_INSTALLED) + { + + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Register more report error */ + status = ux_host_stack_class_register(test_host_classes[UX_MAX_CLASS_DRIVER].class_name, test_host_classes[UX_MAX_CLASS_DRIVER].class_entry_function); + if (status != UX_MEMORY_ARRAY_FULL) + { + + printf("ERROR #%d: register more than %d class should report error\n", __LINE__, UX_MAX_CLASS_DRIVER); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test ux_device_stack_initialize\n"); + +#if !defined(UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE) + /* No interface found, error should be reported. */ + status = ux_device_stack_initialize(device_framework_no_interface, sizeof(device_framework_no_interface), + device_framework_no_interface, sizeof(device_framework_no_interface), + 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); + } +#endif + + /* Try a testing framework. */ + status = ux_device_stack_initialize(device_framework_testing, sizeof(device_framework_testing), + device_framework_testing, sizeof(device_framework_testing), + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH,UX_NULL); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: %x\n", __LINE__, status); + test_control_return(1); + } + + /* Uninitialize the stack to change framework to the one used for enumeration. */ + ux_device_stack_uninitialize(); + + /* Test framework with no endpoint. */ + status = ux_device_stack_initialize(device_framework_no_endpoint, sizeof(device_framework_no_endpoint), + device_framework_no_endpoint, sizeof(device_framework_no_endpoint), + 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); + } + + /* Uninitialize the stack to change framework to the one used for enumeration. */ + ux_device_stack_uninitialize(); + + /* The code below is required for installing the device portion of USBX. No call back for + device status change in this example. */ + ux_test_utility_sim_mem_alloc_count_reset(); + ux_test_utility_sim_sem_create_count_reset(); + 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); + } + mem_count = ux_test_utility_sim_mem_alloc_count(); + sem_count = ux_test_utility_sim_sem_create_count(); + ux_test_utility_sim_mem_alloc_log_lock(); +#if 1 /* FIXME: _ux_device_stack_uninitialize must check resources before free them */ + for (test_n = 0; test_n < mem_count; test_n ++) + { + stepinfo(" .dStackMEM %2ld / %2ld\n", test_n, mem_count - 1); + + /* Confirm uninitialize (no need since stack_initialize fixed) */ + // ux_device_stack_uninitialize(); + + /* Start error generation */ + ux_test_utility_sim_mem_alloc_error_generation_start(test_n); + + /* Check error */ + 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); + /* Stop error generation */ + ux_test_utility_sim_mem_alloc_error_generation_stop(); + if(status != UX_MEMORY_INSUFFICIENT) + { + + printf("ERROR #%d.%ld: memory error should be reported\n", __LINE__, test_n); + test_control_return(1); + } + } +#endif +#if 1 /* FIXME: _ux_device_stack_uninitialize must check resources before free them */ + for (test_n = 0; test_n < sem_count; test_n ++) + { + stepinfo(" .dStackSEM %2ld / %2ld\n", test_n, sem_count - 1); + + /* Confirm uninitialize (no need since stack_initialize fixed) */ + // ux_device_stack_uninitialize(); + + /* Start error generation */ + ux_test_utility_sim_sem_error_generation_start(test_n); + + /* Check error */ + 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); + /* Stop error generation */ + ux_test_utility_sim_sem_error_generation_stop(); + if(status != UX_SEMAPHORE_ERROR) + { + + printf("ERROR #%d.%ld: semaphore error should be reported\n", __LINE__, test_n); + test_control_return(1); + } + } +#endif + /* Do a good initialize for enumeration test. */ + ux_device_stack_uninitialize(); + 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); + } + + stepinfo(">>>>>>>>>>>>>>>> Test ux_device_stack_class_register\n"); + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + + for (test_n = 0; test_n < UX_MAX_SLAVE_CLASS_DRIVER; test_n ++) + { + stepinfo(" .dStackClassReg %2ld / %2d\n", test_n, UX_MAX_SLAVE_CLASS_DRIVER - 1); + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(test_device_classes[test_n].class_name, test_device_classes[test_n].class_entry_function, + test_device_classes[test_n].configuration_number, test_device_classes[test_n].interface_number, + ¶meter); + + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + } + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + + if(status == UX_SUCCESS) + { + + printf("ERROR #%d: register more than %d class should report error\n", __LINE__, UX_MAX_SLAVE_CLASS_DRIVER); + test_control_return(1); + } + + for (test_n = 0; test_n < UX_MAX_SLAVE_CLASS_DRIVER; test_n ++) + { + stepinfo(" .dStackClassUnReg %2ld / %2d\n", test_n, UX_MAX_SLAVE_CLASS_DRIVER - 1); + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_unregister(test_device_classes[UX_MAX_SLAVE_CLASS_DRIVER - 1 - test_n].class_name, + test_device_classes[UX_MAX_SLAVE_CLASS_DRIVER - 1 - test_n].class_entry_function); + + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + } + + status = ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + + if(status == UX_SUCCESS) + { + + printf("ERROR #%d: unregister none exist class should report error\n", __LINE__); + test_control_return(1); + } + + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, test_ux_device_class_entry, + 1,0, ¶meter); + if(status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + device_class_entry_return = UX_ERROR; + status = ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, test_ux_device_class_entry); + if(status == UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + device_class_entry_return = UX_SUCCESS; + status = ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + if(status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + + if(status != UX_SUCCESS) + { + + printf("ERROR #%d: register more than %d class should report error\n", __LINE__, UX_MAX_SLAVE_CLASS_DRIVER); + test_control_return(1); + } + +#if 0 /* FIXME: ? WHY Segmentation faul on _ux_utility_mutex_create(&_ux_system -> ux_system_mutex, "ux_mutex") */ + stepinfo(">>>>>>>>>>>>>>>> Uninitialize all\n"); + /* Missing HCD uninitialize (since initialize called on registering) */ + /* No need ux_host_stack_class_unregister, since there is no entry call */ + ux_device_stack_uninitialize(); + _ux_host_stack_uninitialize(); + _ux_system_uninitialize(); + + stepinfo(">>>>>>>>>>>>>>>> ux_system_initialize\n"); + status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL, 0); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + stepinfo(">>>>>>>>>>>>>>>> ux_host_stack_initialize\n"); + status = ux_host_stack_initialize(test_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + stepinfo(">>>>>>>>>>>>>>>> ux_host_stack_class_register\n"); + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_entry); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + stepinfo(">>>>>>>>>>>>>>>> ux_host_stack_hcd_register\n"); + status = ux_host_stack_hcd_register(test_hcds[test_n].hcd_name, test_hcds[test_n].hcd_init_function, test_hcds[test_n].hcd_param1, test_hcds[test_n].hcd_param2); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + stepinfo(">>>>>>>>>>>>>>>> ux_device_stack_initialize\n"); + 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); + } + stepinfo(">>>>>>>>>>>>>>>> ux_device_stack_class_register\n"); + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#endif + + stepinfo(">>>>>>>>>>>>>>>> Test _ux_test_dcd_sim_slave_initialize\n"); + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test ux_host_stack_hcd_register\n"); + + for (test_n = 0; test_n < UX_MAX_HCD; test_n ++) + { + stepinfo(" .hcdReg %2ld / %2d\n", test_n, UX_MAX_HCD - 1); + + status = ux_host_stack_hcd_register(test_hcds[test_n].hcd_name, test_hcds[test_n].hcd_init_function, test_hcds[test_n].hcd_param1, test_hcds[test_n].hcd_param2); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + } + + /* Register more will report error */ + status = ux_host_stack_hcd_register(test_hcds[UX_MAX_HCD].hcd_name, test_hcds[UX_MAX_HCD].hcd_init_function, test_hcds[UX_MAX_HCD].hcd_param1, test_hcds[UX_MAX_HCD].hcd_param2); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: error should reported if try to add more than %d HCDs\n", __LINE__, UX_MAX_HCD); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG test_n; +ULONG mem_free; + + stepinfo("\n"); + +#if UX_MAX_CLASS_DRIVER > 1 /* CDC is not first class ... */ + /* Test connect. */ + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + tx_thread_sleep(100); + if (cdc_acm_host_control == UX_NULL || cdc_acm_host_data == UX_NULL || cdc_acm_slave == UX_NULL) + { + + printf("ERROR #%d: connection not detected\n", __LINE__); + test_control_return(1); + } + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + test_n = 10; + while((cdc_acm_host_control || cdc_acm_host_data || cdc_acm_slave) && test_n --) + tx_thread_sleep(10); + + if (cdc_acm_host_control || cdc_acm_host_data || cdc_acm_slave) + { + + printf("ERROR #%d: instance not removed when disconnect, %p %p %p\n", __LINE__, cdc_acm_host_control, cdc_acm_host_data, cdc_acm_slave); + test_control_return(1); + } + if (_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available <= mem_free) + { + + printf("ERROR #%d: memory not freed when disconnect\n", __LINE__); + test_control_return(1); + } +#endif + /* Deinitialize the class. */ + status = ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_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 tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Sleep so ThreadX on Win32 will delete this thread. */ + tx_thread_sleep(10); + } +} diff --git a/test/regression/usbx_ux_host_stack_bandwidth_test.c b/test/regression/usbx_ux_host_stack_bandwidth_test.c new file mode 100644 index 00000000..dfb2dd67 --- /dev/null +++ b/test/regression/usbx_ux_host_stack_bandwidth_test.c @@ -0,0 +1,608 @@ +/* This test is designed to test the ux_host_stack_bandwidth_.... */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors. */ +#define DPUMP_IFC_DESC(ifc, alt, nb_ep) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), (alt), (nb_ep), 0x99, 0x99, 0x99, 0x00, + +#define DPUMP_IFC_EP_DESC(epaddr, eptype, epsize) \ + /* Endpoint descriptor */\ + 0x07, 0x05, (epaddr), (eptype), LSB(epsize), MSB(epsize), 0x01, + +#define DPUMP_IFC_DESC_ALL_LEN(nb_ep) (9 + (nb_ep) * 7) + +#define CFG_DESC_ALL_LEN (CFG_DESC_LEN + \ + DPUMP_IFC_DESC_ALL_LEN(0) + \ + DPUMP_IFC_DESC_ALL_LEN(1) + \ + DPUMP_IFC_DESC_ALL_LEN(2) + \ + DPUMP_IFC_DESC_ALL_LEN(3) + \ + DPUMP_IFC_DESC_ALL_LEN(4) \ + ) + +#define CFG_DESC_ALL_LS \ + CFG_DESC(CFG_DESC_ALL_LEN, 5, 1)\ + DPUMP_IFC_DESC(0, 0, 0)\ + DPUMP_IFC_DESC(0, 1, 1)\ + DPUMP_IFC_EP_DESC(0x81, 3, 8)\ + DPUMP_IFC_DESC(0, 2, 2)\ + DPUMP_IFC_EP_DESC(0x81, 3, 8)\ + DPUMP_IFC_EP_DESC(0x02, 3, 8)\ + DPUMP_IFC_DESC(0, 3, 3)\ + DPUMP_IFC_EP_DESC(0x81, 3, 8)\ + DPUMP_IFC_EP_DESC(0x02, 3, 8)\ + DPUMP_IFC_EP_DESC(0x83, 3, 8)\ + DPUMP_IFC_DESC(0, 4, 6)\ + DPUMP_IFC_EP_DESC(0x81, 3, 8)\ + DPUMP_IFC_EP_DESC(0x02, 3, 8)\ + DPUMP_IFC_EP_DESC(0x83, 3, 8)\ + DPUMP_IFC_EP_DESC(0x04, 3, 8)\ + DPUMP_IFC_EP_DESC(0x85, 3, 8)\ + DPUMP_IFC_EP_DESC(0x06, 3, 8) + +#define CFG_DESC_ALL_FS \ + CFG_DESC(CFG_DESC_ALL_LEN, 5, 1)\ + DPUMP_IFC_DESC(0, 0, 0)\ + DPUMP_IFC_DESC(0, 1, 1)\ + DPUMP_IFC_EP_DESC(0x81, 3, 64)\ + DPUMP_IFC_DESC(0, 2, 2)\ + DPUMP_IFC_EP_DESC(0x81, 3, 64)\ + DPUMP_IFC_EP_DESC(0x02, 3, 64)\ + DPUMP_IFC_DESC(0, 3, 3)\ + DPUMP_IFC_EP_DESC(0x81, 3, 64)\ + DPUMP_IFC_EP_DESC(0x02, 3, 64)\ + DPUMP_IFC_EP_DESC(0x83, 3, 64)\ + DPUMP_IFC_DESC(0, 4, 4)\ + DPUMP_IFC_EP_DESC(0x81, 3, 64)\ + DPUMP_IFC_EP_DESC(0x02, 3, 64)\ + DPUMP_IFC_EP_DESC(0x83, 3, 64)\ + DPUMP_IFC_EP_DESC(0x04, 3, 64) + +#define CFG_DESC_ALL_HS \ + CFG_DESC(CFG_DESC_ALL_LEN, 5, 1)\ + DPUMP_IFC_DESC(0, 0, 0)\ + DPUMP_IFC_DESC(0, 1, 1)\ + DPUMP_IFC_EP_DESC(0x81, 3, 1024)\ + DPUMP_IFC_DESC(0, 2, 2)\ + DPUMP_IFC_EP_DESC(0x81, 3, 1024)\ + DPUMP_IFC_EP_DESC(0x02, 3, 1024)\ + DPUMP_IFC_DESC(0, 3, 3)\ + DPUMP_IFC_EP_DESC(0x81, 3, 1024)\ + DPUMP_IFC_EP_DESC(0x02, 3, 1024)\ + DPUMP_IFC_EP_DESC(0x83, 3, 1024)\ + DPUMP_IFC_DESC(0, 4, 4)\ + DPUMP_IFC_EP_DESC(0x81, 3, 1024)\ + DPUMP_IFC_EP_DESC(0x02, 3, 1024)\ + DPUMP_IFC_EP_DESC(0x83, 3, 1024)\ + DPUMP_IFC_EP_DESC(0x04, 3, 1024) + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + +static UCHAR device_framework_low_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC_ALL_LS +}; +#define DEVICE_FRAMEWORK_LENGTH_LOW_SPEED sizeof(device_framework_low_speed) + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC_ALL_FS +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC_ALL_HS +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 test_ux_device_class_dpump_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + switch(command->ux_slave_class_command_request) + { + case UX_SLAVE_CLASS_COMMAND_INITIALIZE: + case UX_SLAVE_CLASS_COMMAND_QUERY: + case UX_SLAVE_CLASS_COMMAND_CHANGE: + return UX_SUCCESS; + + default: + return UX_NO_CLASS_MATCH; + } +} + +static UINT test_ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command) +{ + switch (command -> ux_host_class_command_request) + { + case UX_HOST_CLASS_COMMAND_QUERY: + case UX_HOST_CLASS_COMMAND_ACTIVATE: + return UX_SUCCESS; + + default: + return UX_NO_CLASS_MATCH; + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_stack_bandwidth_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_bandwidth_... Test............................ ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_bandwidth_... Test............................ ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, test_ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_bandwidth_... Test............................ ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_bandwidth_... Test............................ ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = UX_NULL; + parameter.ux_slave_class_dpump_instance_deactivate = UX_NULL; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, test_ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_bandwidth_... Test............................ ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_bandwidth_... Test............................ ERROR #7\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_bandwidth_... Test............................ ERROR #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test host simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_host_stack_bandwidth_... Test............................ ERROR #8\n"); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + +UINT status; +INT i; +INT test; +UX_HCD *hcd; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +UX_INTERFACE *interfaces[8]; +UX_DEVICE hub[3]; +struct _test_def { + UCHAR speed; + UCHAR *framework; + ULONG framework_length; + ULONG hcd_version; + ULONG available_bandwidth; + UX_DEVICE *parent; + UCHAR parent_speed; + ULONG tt_mask; + ULONG tt_bandwidth; + UINT status0; + UINT status1_invert; +} tests[] = { + {UX_LOW_SPEED_DEVICE , device_framework_low_speed , DEVICE_FRAMEWORK_LENGTH_LOW_SPEED , 0x110, 48*8*5, UX_NULL}, + {UX_LOW_SPEED_DEVICE , device_framework_low_speed , DEVICE_FRAMEWORK_LENGTH_LOW_SPEED , 0x200, 48 , UX_NULL}, + {UX_FULL_SPEED_DEVICE, device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, 0x110, 128*5 , UX_NULL}, + {UX_FULL_SPEED_DEVICE, device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, 0x200, 128 , UX_NULL}, + {UX_HIGH_SPEED_DEVICE, device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, 0x110, 2048 , UX_NULL}, + {UX_HIGH_SPEED_DEVICE, device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, 0x200, 2048 , UX_NULL}, + + {UX_FULL_SPEED_DEVICE, device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, 0x200, 6000 , &hub[2], UX_HIGH_SPEED_DEVICE, 0x0, 128, UX_NO_BANDWIDTH_AVAILABLE}, + {UX_FULL_SPEED_DEVICE, device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, 0x200, 6000 , &hub[2], UX_HIGH_SPEED_DEVICE, 0x3, 128}, + + {UX_FULL_SPEED_DEVICE, device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, 0x200, 6000 , &hub[2], UX_FULL_SPEED_DEVICE, 0x3, 128, UX_SUCCESS, UX_TRUE}, +}; + +#if UX_MAX_DEVICES > 1 + + /* Inform user. */ + printf("Running ux_host_stack_bandwidth_... Test............................ "); + + hcd = &_ux_system_host -> ux_system_host_hcd_array[0]; + + /* Build a hub list for tests: hub0 (hs) <- hub1 (fs) <- hub2 (fs). */ + ux_utility_memory_set(hub, 0, sizeof(hub)); + hub[0].ux_device_speed = UX_HIGH_SPEED_DEVICE; + hub[0].ux_device_parent = UX_NULL; + hub[0].ux_device_port_location = 0; + hub[0].ux_device_hub_tt[0].ux_hub_tt_max_bandwidth = UX_TT_BANDWIDTH; + hub[0].ux_device_hub_tt[0].ux_hub_tt_port_mapping = 0; + hub[0].ux_device_hub_tt[1].ux_hub_tt_max_bandwidth = UX_TT_BANDWIDTH; + hub[0].ux_device_hub_tt[1].ux_hub_tt_port_mapping = UX_TT_MASK; + hub[1].ux_device_speed = UX_FULL_SPEED_DEVICE; + hub[1].ux_device_parent = &hub[0]; + hub[1].ux_device_port_location = 2; + hub[2].ux_device_speed = UX_FULL_SPEED_DEVICE; + hub[2].ux_device_parent = &hub[1]; + hub[2].ux_device_port_location = 3; + + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + error_callback_ignore = UX_TRUE; + + for (test = 0; test < sizeof(tests)/sizeof(struct _test_def); test ++) + { + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Connect. */ + hcd -> ux_hcd_version = tests[test].hcd_version; + hcd -> ux_hcd_available_bandwidth = tests[test].available_bandwidth; + ux_test_dcd_sim_slave_connect_framework(tests[test].framework, tests[test].framework_length); + ux_test_hcd_sim_host_connect(tests[test].speed); + tx_thread_sleep(200); + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d.%d: device_get fail\n", __LINE__, test); + test_control_return(1); + } + + status = ux_host_stack_device_configuration_get(device, 0, &configuration); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d.%d: cfg_get fail\n", __LINE__, test); + test_control_return(1); + } + + interface = configuration->ux_configuration_first_interface; + for (i = 0; i < 8; i ++) + { + + if (interface == UX_NULL) + break; + + interfaces[i] = interface; + interface = interface->ux_interface_next_interface; + } + + /* Set configure. */ + status = ux_host_stack_device_configuration_select(configuration); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d.%d: cfg_set fail\n", __LINE__, test); + test_control_return(1); + } + + /* Modify parent. */ + if (tests[test].parent) + { + device->ux_device_parent = tests[test].parent; + hub[0].ux_device_speed = tests[test].parent_speed; + hub[0].ux_device_hub_tt[1].ux_hub_tt_port_mapping = tests[test].tt_mask; + hub[0].ux_device_hub_tt[1].ux_hub_tt_max_bandwidth = tests[test].tt_bandwidth; + } + + /* Switch to interface 0.1, bandwith OK */ + status = ux_host_stack_interface_setting_select(interfaces[1]); + if (status != tests[test].status0) + { + + printf("ERROR #%d.%d: ifc_set status not expected: %x<>%x\n", __LINE__, test, tests[test].status0, status); + error_counter ++; + } + + /* Switch to interface 0.4, bandwidth FAIL */ + error_callback_counter = 0; + status = ux_host_stack_interface_setting_select(interfaces[4]); + if (tests[test].status1_invert) + { + if (status != UX_SUCCESS) + { + + printf("ERROR #%d.%d: Expect ifc_set pass\n", __LINE__, test); + error_counter ++; + } + } + else + { + if (status == UX_SUCCESS) + { + + printf("ERROR #%d.%d: Expect ifc_set fail\n", __LINE__, test); + error_counter ++; + } + if (error_callback_counter == 0) + { + + printf("ERROR #%d.%d: Expect error\n", __LINE__, test); + error_counter ++; + } + } + + /* Restore parent. */ + if (tests[test].parent) + { + + device->ux_device_parent = UX_NULL; + hub[0].ux_device_speed = UX_HIGH_SPEED_DEVICE; + hub[0].ux_device_hub_tt[1].ux_hub_tt_port_mapping = UX_TT_MASK; + hub[0].ux_device_hub_tt[1].ux_hub_tt_max_bandwidth = UX_TT_BANDWIDTH; + } + } + error_callback_ignore = UX_FALSE; + +#else + + /* Inform user. */ + printf("Running ux_host_stack_bandwidth_... Skip for max 1 device .......... "); +#endif + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_ux_host_stack_class_device_scan_test.c b/test/regression/usbx_ux_host_stack_class_device_scan_test.c new file mode 100644 index 00000000..5bf214d4 --- /dev/null +++ b/test/regression/usbx_ux_host_stack_class_device_scan_test.c @@ -0,0 +1,533 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_stack.h" + +/* Define USBX demo constants. */ + +#define UX_DEMO_STACK_SIZE 4096 +#define UX_DEMO_BUFFER_SIZE 2048 +#define UX_DEMO_RUN 1 +#define UX_DEMO_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the demo application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR test_sim_entry; +static ULONG test_sim_query_usage; +static ULONG test_sim_query_count; +static ULONG test_sim_activate_count; + +/* Define USBX demo global variables. */ + +static unsigned char host_out_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; +static unsigned char host_in_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; +static unsigned char slave_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x08, /* bMaxPacketSize0 */ + 0xec, 0x08, 0x10, 0x00, /* idVendor, idProduct */ + 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x01, /* bNumConfigurations */ + + /* Configuration descriptor */ + 0x09, 0x02, + 0x20, 0x00, /* wTotalLength */ + 0x01, 0x01, /* bNumInterfaces, bConfigurationValue */ + 0x00, + 0xc0, 0x32, /* bmAttributes, bMaxPower */ + + /* Interface descriptor */ + 0x09, 0x04, + 0x00, 0x00, 0x02, /* bInterfaceNumber, bAlternateSetting, bNumEndpoints */ + 0x99, 0x99, 0x99, /* bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00 +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 */ + 0x0a, 0x07, /* idVendor */ + 0x25, 0x40, /* idProduct */ + 0x01, 0x00, + 0x01, 0x02, 0x03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 */ + 0x01, /* bNumConfigurations */ + 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00 +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID tx_demo_instance_activate(VOID *dpump_instance); +static VOID tx_demo_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); +static void tx_demo_thread_slave_simulation_entry(ULONG); + +static UINT test_ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command) +{ + if (test_sim_entry) + { + + switch (command -> ux_host_class_command_request) + { + case UX_HOST_CLASS_COMMAND_QUERY: + test_sim_query_count ++; + if (command -> ux_host_class_command_usage != test_sim_query_usage) + return UX_NO_CLASS_MATCH; + break; + + case UX_HOST_CLASS_COMMAND_ACTIVATE: + test_sim_activate_count ++; + break; + + default: + break; + } + return UX_SUCCESS; + } + return ux_host_class_dpump_entry(command); +} + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + 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_stack_class_device_scan_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; + + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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("Running ux_host_stack_class_device_scan Test........................ ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_class_device_scan Test........................ ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, test_ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_class_device_scan Test........................ ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_class_device_scan Test........................ ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = tx_demo_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = tx_demo_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_class_device_scan Test........................ ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_class_device_scan Test........................ ERROR #7\n"); + 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("Running ux_host_stack_class_device_scan Test........................ ERROR #4\n"); + 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("Running ux_host_stack_class_device_scan Test........................ ERROR #8\n"); + test_control_return(1); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_host_stack_class_device_scan Test........................ ERROR #9\n"); + test_control_return(1); + } +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_DEVICE *device; + + + /* Inform user. */ + printf("Running ux_host_stack_class_device_scan Test........................ "); + + /* Find the main data pump container. */ + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + /* DPUMP basic test error. */ + printf("ERROR #10\n"); + test_control_return(1); + } + + /* We get the first instance of the data pump device. */ + do + { + + status = ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump); + tx_thread_relinquish(); + } while (status != UX_SUCCESS); + + /* We still need to wait for the data pump status to be live. */ + while (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + { + + tx_thread_relinquish(); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: fail to get device instance\n", __LINE__); + test_control_return(1); + } + +#if !defined(UX_HOST_STACK_DEVICE_DRIVER_SCAN_DISABLE) + /* Simulate class device scan, query and activate should happen. */ + test_sim_entry = UX_TRUE; + + /* Query fail case */ + test_sim_query_usage = 0xFF; /* UX_HOST_CLASS_COMMAND_USAGE_PIDVID, UX_HOST_CLASS_COMMAND_USAGE_CSP */ + test_sim_activate_count = 0; + test_sim_query_count = 0; + status = _ux_host_stack_class_device_scan(device); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: Queries should fail\n", __LINE__); + error_counter ++; + } + if (test_sim_query_count != 2) + { + + printf("ERROR #%d: Queries tried must be 2\n", __LINE__); + error_counter ++; + } + if (test_sim_activate_count > 0) + { + + printf("ERROR #%d: No activate should be done\n", __LINE__); + error_counter ++; + } + +#if !defined(UX_HOST_STACK_DEVICE_DRIVER_SCAN_VIDPID_DISABLE) + /* VIDPID success case */ + test_sim_query_usage = UX_HOST_CLASS_COMMAND_USAGE_PIDVID; /* UX_HOST_CLASS_COMMAND_USAGE_PIDVID, UX_HOST_CLASS_COMMAND_USAGE_DCSP */ + test_sim_activate_count = 0; + test_sim_query_count = 0; + status = _ux_host_stack_class_device_scan(device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: Queries should pass\n", __LINE__); + error_counter ++; + } + if (test_sim_query_count == 0) + { + + printf("ERROR #%d: There should be at least 1 query\n", __LINE__); + error_counter ++; + } + if (test_sim_activate_count != 1) + { + + printf("ERROR #%d: There must be 1 activate\n", __LINE__); + error_counter ++; + } +#endif /* !defined(UX_HOST_STACK_DEVICE_DRIVER_SCAN_DCSP_DISABLE) */ + +#if !defined(UX_HOST_STACK_DEVICE_DRIVER_SCAN_DCSP_DISABLE) + /* Class/SubClass/Protocol success case */ + test_sim_query_usage = UX_HOST_CLASS_COMMAND_USAGE_DCSP; /* UX_HOST_CLASS_COMMAND_USAGE_PIDVID, UX_HOST_CLASS_COMMAND_USAGE_DCSP */ + test_sim_activate_count = 0; + test_sim_query_count = 0; + status = _ux_host_stack_class_device_scan(device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: Queries should pass\n", __LINE__); + error_counter ++; + } + if (test_sim_query_count == 0) + { + + printf("ERROR #%d: There should be at least 1 query\n", __LINE__); + error_counter ++; + } + if (test_sim_activate_count != 1) + { + + printf("ERROR #%d: There must be 1 activate\n", __LINE__); + error_counter ++; + } +#endif /* !defined(UX_HOST_STACK_DEVICE_DRIVER_SCAN_DCSP_DISABLE) */ + +#endif /* !defined(UX_HOST_STACK_DEVICE_DRIVER_SCAN_DISABLE) */ + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* DPUMP error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + + +static void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Ensure the dpump class on the device is still alive. */ + if (dpump_slave != UX_NULL) + { + + /* Increment thread counter. */ + thread_1_counter++; + } + + /* Let other thread run. */ + tx_thread_sleep(10); + } +} + +static VOID tx_demo_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID tx_demo_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_host_stack_class_get_test.c b/test/regression/usbx_ux_host_stack_class_get_test.c new file mode 100644 index 00000000..5f0848e3 --- /dev/null +++ b/test/regression/usbx_ux_host_stack_class_get_test.c @@ -0,0 +1,519 @@ +/* This test is designed to test the ux_host_stack_class_get. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +/* HID mouse related descriptors */ + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +#define LSB(x) (x & 0x00ff) +#define MSB(x) ((x & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x20, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors 9+7+7=23 bytes. */ +#define DPUMP_IFC_DESC_ALL(ifc, bulk_in_epa, bulk_out_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x02, 0x99, 0x99, 0x99, 0x00,\ + /* Endpoint descriptor (Bulk Out) */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Bulk In) */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00, +#define DPUMP_IFC_DESC_ALL_LEN 23 + +/* HID Mouse interface descriptors 9+9=18 bytes */ +#define HID_MOUSE_IFC0_DESC_ALL(ifc) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH), +#define HID_MOUSE_IFC0_DESC_ALL_LEN 18 + +/* HID Mouse interface descriptors 9+9+7=25 bytes */ +#define HID_MOUSE_IFC1_DESC_ALL(ifc, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x01, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_MOUSE_IFC1_DESC_ALL_LEN 25 + +/* CDC-ACM interfaces descriptors 8 +9+5+4+5+5+7 +9+7+7=66 bytes */ +#define CDC_ACM_IFCES_DESC_ALL(ifc, interrupt_epa, bulk_in_epa, bulk_out_epa) \ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (ifc), 0x02, 0x02, 0x02, 0x00, 0x00,\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (ifc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06,\ + (ifc), /* Master interface */\ + (ifc+1), /* Slave interface */\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03,\ + (ifc+1), /* Data interface */\ + /* Interrupt endpoint descriptor 7 bytes */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 15,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (ifc+1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint descriptor 7 bytes */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor 7 bytes */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00, +#define CDC_ACM_IFCES_DESC_ALL_LEN 66 + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR expect_errors = UX_FALSE; + + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN + CDC_ACM_IFCES_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+9+7 =25 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02) + /* HID 9+9 + 9+9+7=43 */ + HID_MOUSE_IFC0_DESC_ALL(1) + HID_MOUSE_IFC1_DESC_ALL(1, 0x83) + /* CDC-ACM */ + CDC_ACM_IFCES_DESC_ALL(2, 0x86, 0x85, 0x04) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN + CDC_ACM_IFCES_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+9+7 =25 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02) + /* HID 9+9 + 9+9+7=43 */ + HID_MOUSE_IFC0_DESC_ALL(1) + HID_MOUSE_IFC1_DESC_ALL(1, 0x83) + /* CDC-ACM */ + CDC_ACM_IFCES_DESC_ALL(2, 0x86, 0x85, 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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Simulation actions. */ + +static UX_TEST_SIM_ENTRY_ACTION dcd_endpoint_create_fail[] = { +/* 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_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ 0 } +}; + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (!expect_errors) + { + if (error_code != UX_DEVICE_HANDLE_UNKNOWN) + { + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } + } +} + +static UINT test_ux_device_class_hid_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + return UX_SUCCESS; + // return _ux_device_class_hid_entry(command); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_stack_class_get_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; +UX_SLAVE_CLASS_HID_PARAMETER hid_parameter; + + /* Inform user. */ + printf("Running ux_host_stack_class_get Test................................ "); + stepinfo("\n"); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + 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(UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry); + + /* Check for error. */ + 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 */ + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = ux_test_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = ux_test_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Initialize the hid class parameters. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_REPORT_LENGTH; + hid_parameter.ux_device_class_hid_parameter_callback = UX_NULL; + hid_parameter.ux_slave_class_hid_instance_activate = UX_NULL; + + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, test_ux_device_class_hid_entry, + 1, 1, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#endif + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test host simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + +UINT status; +UCHAR invalid_class_name[UX_MAX_CLASS_NAME_LENGTH+2]; +UX_HOST_CLASS *host_class; + + /* Inform user. */ + stepinfo(">>>>>>>>> ENUM check\n"); + + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Enumeration check. */ + if (dpump_slave == UX_NULL) + { + + printf("ERROR #%d: Enum fail\n", __LINE__); + test_control_return(1); + } + + // stepinfo(">>>>>>>>> Disconnect\n"); + // ux_test_dcd_sim_slave_disconnect(); + // ux_test_hcd_sim_host_disconnect(); + + /* Expect errors so skip them in error handler. */ + expect_errors = UX_TRUE; + +#if !defined(UX_NAME_REFERENCED_BY_POINTER) + stepinfo(">>>>>>>>> _ux_host_stack_class_get - error if class_name exceed UX_MAX_CLASS_NAME_LENGTH\n"); + _ux_utility_memory_set(invalid_class_name, 'a', sizeof(invalid_class_name)); + _ux_utility_memory_copy(invalid_class_name, _ux_system_host_class_dpump_name, 19); + status = _ux_host_stack_class_get(invalid_class_name, &host_class); + if (status != UX_ERROR) + { + printf("ERROR %d: expect error %d\n", __LINE__, UX_ERROR); + error_counter ++; + } +#endif + + /* Break on errors. */ + expect_errors = UX_TRUE; + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static VOID ux_test_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID ux_test_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_host_stack_class_instance_destroy_test.c b/test/regression/usbx_ux_host_stack_class_instance_destroy_test.c new file mode 100644 index 00000000..5ac99f99 --- /dev/null +++ b/test/regression/usbx_ux_host_stack_class_instance_destroy_test.c @@ -0,0 +1,463 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_stack.h" + +/* Define USBX demo constants. */ + +#define UX_DEMO_STACK_SIZE 4096 +#define UX_DEMO_BUFFER_SIZE 2048 +#define UX_DEMO_RUN 1 +#define UX_DEMO_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the demo application... */ + +static ULONG test_error_cases = UX_FALSE; + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +/* Define USBX demo global variables. */ + +static unsigned char host_out_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; +static unsigned char host_in_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; +static unsigned char slave_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x08, /* bMaxPacketSize0 */ + 0xec, 0x08, 0x10, 0x00, /* idVendor, idProduct */ + 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x01, /* bNumConfigurations */ + + /* Configuration descriptor */ + 0x09, 0x02, + 0x20, 0x00, /* wTotalLength */ + 0x01, 0x01, /* bNumInterfaces, bConfigurationValue */ + 0x00, + 0xc0, 0x32, /* bmAttributes, bMaxPower */ + + /* Interface descriptor */ + 0x09, 0x04, + 0x00, 0x00, 0x02, /* bInterfaceNumber, bAlternateSetting, bNumEndpoints */ + 0x99, 0x99, 0x99, /* bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00 +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 */ + 0x0a, 0x07, /* idVendor */ + 0x25, 0x40, /* idProduct */ + 0x01, 0x00, + 0x01, 0x02, 0x03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 */ + 0x01, /* bNumConfigurations */ + 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00 +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID tx_demo_instance_activate(VOID *dpump_instance); +static VOID tx_demo_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); +static void tx_demo_thread_slave_simulation_entry(ULONG); + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + if (!test_error_cases) + { + + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + 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_stack_class_instance_destroy_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; + + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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("Running ux_host_stack_class_instance_destroy Test................... ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_class_instance_destroy Test................... ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, _ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_class_instance_destroy Test................... ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_class_instance_destroy Test................... ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = tx_demo_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = tx_demo_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_class_instance_destroy Test................... ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_class_instance_destroy Test................... ERROR #7\n"); + 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("Running ux_host_stack_class_instance_destroy Test................... ERROR #4\n"); + 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("Running ux_host_stack_class_instance_destroy Test................... ERROR #8\n"); + test_control_return(1); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_host_stack_class_instance_destroy Test................... ERROR #9\n"); + test_control_return(1); + } +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG actual_length; +UX_HOST_CLASS *class; +UX_DEVICE *device; +UX_HOST_CLASS class_backup; + + /* Inform user. */ + printf("Running ux_host_stack_class_instance_destroy Test................... "); + + /* Find the main data pump container. */ + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + /* DPUMP basic test error. */ + printf("ERROR #10\n"); + test_control_return(1); + } + + /* We get the first instance of the data pump device. */ + do + { + + status = ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump); + tx_thread_relinquish(); + } while (status != UX_SUCCESS); + + /* We still need to wait for the data pump status to be live. */ + while (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + { + + tx_thread_relinquish(); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: fail to get device instance\n", __LINE__); + test_control_return(1); + } + + /* Simulate _ux_host_stack_class_instance_destroy error cases. */ + + /* Backup class */ + ux_utility_memory_copy(&class_backup, class, sizeof(UX_HOST_CLASS)); + + /* We are testing error cases. */ + test_error_cases = UX_TRUE; + + /* Simulate error: no class instance attached. */ + class->ux_host_class_first_instance = UX_NULL; + status = _ux_host_stack_class_instance_destroy(class, class_backup.ux_host_class_first_instance); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: Expects fail since no class instance in class\n", __LINE__); + error_counter ++; + } + + /* Restore class */ + ux_utility_memory_copy(class, &class_backup, sizeof(UX_HOST_CLASS)); + + /* Simulate error: class instance not found. */ + status = _ux_host_stack_class_instance_destroy(class, &actual_length); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: Expects fail since no class instance match\n", __LINE__); + error_counter ++; + } + + /* We finish testing error cases. */ + test_error_cases = UX_FALSE; + + /* Restore class */ + ux_utility_memory_copy(class, &class_backup, sizeof(UX_HOST_CLASS)); + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* DPUMP error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + + +static void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Ensure the dpump class on the device is still alive. */ + if (dpump_slave != UX_NULL) + { + + /* Increment thread counter. */ + thread_1_counter++; + } + + /* Let other thread run. */ + tx_thread_sleep(10); + } +} + +static VOID tx_demo_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID tx_demo_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_host_stack_class_instance_get_test.c b/test/regression/usbx_ux_host_stack_class_instance_get_test.c new file mode 100644 index 00000000..88298d0b --- /dev/null +++ b/test/regression/usbx_ux_host_stack_class_instance_get_test.c @@ -0,0 +1,437 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_stack.h" + +/* Define USBX demo constants. */ + +#define UX_DEMO_STACK_SIZE 4096 +#define UX_DEMO_BUFFER_SIZE 2048 +#define UX_DEMO_RUN 1 +#define UX_DEMO_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the demo application... */ + +static ULONG test_error_cases = UX_FALSE; + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +/* Define USBX demo global variables. */ + +static unsigned char host_out_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; +static unsigned char host_in_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; +static unsigned char slave_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x08, /* bMaxPacketSize0 */ + 0xec, 0x08, 0x10, 0x00, /* idVendor, idProduct */ + 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x01, /* bNumConfigurations */ + + /* Configuration descriptor */ + 0x09, 0x02, + 0x20, 0x00, /* wTotalLength */ + 0x01, 0x01, /* bNumInterfaces, bConfigurationValue */ + 0x00, + 0xc0, 0x32, /* bmAttributes, bMaxPower */ + + /* Interface descriptor */ + 0x09, 0x04, + 0x00, 0x00, 0x02, /* bInterfaceNumber, bAlternateSetting, bNumEndpoints */ + 0x99, 0x99, 0x99, /* bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00 +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 */ + 0x0a, 0x07, /* idVendor */ + 0x25, 0x40, /* idProduct */ + 0x01, 0x00, + 0x01, 0x02, 0x03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 */ + 0x01, /* bNumConfigurations */ + 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00 +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID tx_demo_instance_activate(VOID *dpump_instance); +static VOID tx_demo_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); +static void tx_demo_thread_slave_simulation_entry(ULONG); + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + if (!test_error_cases) + { + + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + 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_stack_class_instance_get_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; + + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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("Running ux_host_stack_class_instance_get Test....................... ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_class_instance_get Test....................... ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, _ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_class_instance_get Test....................... ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_class_instance_get Test....................... ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = tx_demo_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = tx_demo_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_class_instance_get Test....................... ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_class_instance_get Test....................... ERROR #7\n"); + 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("Running ux_host_stack_class_instance_get Test....................... ERROR #4\n"); + 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("Running ux_host_stack_class_instance_get Test....................... ERROR #8\n"); + test_control_return(1); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_host_stack_class_instance_get Test....................... ERROR #9\n"); + test_control_return(1); + } +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_DEVICE *device; +VOID *class_instance; + + /* Inform user. */ + printf("Running ux_host_stack_class_instance_get Test....................... "); + + /* Find the main data pump container. */ + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + /* DPUMP basic test error. */ + printf("ERROR #10\n"); + test_control_return(1); + } + + /* We get the first instance of the data pump device. */ + do + { + + status = ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump); + tx_thread_relinquish(); + } while (status != UX_SUCCESS); + + /* We still need to wait for the data pump status to be live. */ + while (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + { + + tx_thread_relinquish(); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: fail to get device instance\n", __LINE__); + test_control_return(1); + } + + /* Simulate _ux_host_stack_class_instance_get error cases. */ + + /* Simulate error: no class instance attached. */ + status = _ux_host_stack_class_instance_get(class, 10, &class_instance); + if (status != UX_HOST_CLASS_INSTANCE_UNKNOWN) + { + + printf("ERROR #%d: Expects UX_HOST_CLASS_INSTANCE_UNKNOWN since invalid index is there\n", __LINE__); + error_counter ++; + } + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* DPUMP error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + + +static void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Ensure the dpump class on the device is still alive. */ + if (dpump_slave != UX_NULL) + { + + /* Increment thread counter. */ + thread_1_counter++; + } + + /* Let other thread run. */ + tx_thread_sleep(10); + } +} + +static VOID tx_demo_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID tx_demo_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_host_stack_class_instance_verify_test.c b/test/regression/usbx_ux_host_stack_class_instance_verify_test.c new file mode 100644 index 00000000..48fd5cc0 --- /dev/null +++ b/test/regression/usbx_ux_host_stack_class_instance_verify_test.c @@ -0,0 +1,698 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" + +#include "ux_host_class_cdc_acm.h" +#include "ux_host_class_hid.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#include "ux_host_stack.h" + +/* Define constants. */ +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (96*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bmAttributes, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + (bmAttributes), 0x00, +#define CFG_DESC_LEN 9 + +#define IAD_DESC(bIfc) \ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (bIfc), 0x02, 0x02, 0x02, 0x00, 0x00, +#define IAD_DESC_LEN 8 + +#define CDC_IFC_DESC_ALL(bIfc, bIntIn, bBulkIn, bBulkOut)\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (bIfc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06, (bIfc), (bIfc + 1),\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03, (bIfc + 1),\ + /* Endpoint interrupt in descriptor 7 bytes */\ + 0x07, 0x05, (bIntIn), 0x03, 0x40, 0x00, 0x10,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (bIfc + 1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint bulk in descriptor 7 bytes */\ + 0x07, 0x05, (bBulkIn), 0x02, 0x40, 0x00, 0x01,\ + /* Endpoint bulk out descriptor 7 bytes */\ + 0x07, 0x05, (bBulkOut), 0x02, 0x40, 0x00, 0x01, +#define CDC_IFC_DESC_ALL1(bIfc, bIntIn, bBulkIn, bBulkOut)\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (bIfc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06, (bIfc), (bIfc + 1),\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03, (bIfc + 1),\ + /* Endpoint interrupt in descriptor 7 bytes */\ + 0x07, 0x05, (bIntIn), 0x03, 0x40, 0x00, 0x10,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (bIfc + 1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint bulk out descriptor 7 bytes */\ + 0x07, 0x05, (bBulkOut), 0x02, 0x40, 0x00, 0x01,\ + /* Endpoint bulk in descriptor 7 bytes */\ + 0x07, 0x05, (bBulkIn), 0x02, 0x40, 0x00, 0x01, +#define CDC_IFC_DESC_ALL_LEN (9+5+4+5+5+7+ 9+7+7) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); + +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control = UX_NULL; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data = UX_NULL; + +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control1 = UX_NULL; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data1 = UX_NULL; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave = UX_NULL; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave1 = UX_NULL; + +static UCHAR cdc_acm_slave_change; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; + +static ULONG error_counter; + +static ULONG error_callback_counter; +static UCHAR error_callback_ignore; + +static ULONG call_counter; + +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static UCHAR test_slave_code = 0; +static UCHAR test_slave_state = 0; + +/* Define device framework. */ + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Configuration 1 descriptor 9 bytes, total 75 bytes */ + CFG_DESC(CFG_DESC_LEN + (IAD_DESC_LEN + CDC_IFC_DESC_ALL_LEN) * 2, 4, 0x40, 1) + /* IAD 8 bytes */ + IAD_DESC(0) + /* CDC_ACM interfaces */ + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) + /* IAD 8 bytes */ + IAD_DESC(2) + /* CDC_ACM interfaces */ + CDC_IFC_DESC_ALL1(2, 0x86, 0x85, 0x04) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor 10 bytes */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor 9 bytes, total 75 bytes */ + CFG_DESC(CFG_DESC_LEN + IAD_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 0x60, 1) + /* IAD 8 bytes */ + IAD_DESC(0) + /* CDC_ACM interfaces */ + CDC_IFC_DESC_ALL1(0, 0x83, 0x81, 0x02) + /* IAD 8 bytes */ + IAD_DESC(2) + /* CDC_ACM interfaces */ + CDC_IFC_DESC_ALL(2, 0x86, 0x85, 0x04) +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT break_on_cdc_acm_all_ready(VOID) +{ + + if (cdc_acm_host_control == UX_NULL || cdc_acm_host_data == UX_NULL) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control1 == UX_NULL || cdc_acm_host_data1 == UX_NULL) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_host_data->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control1->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_host_data1->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_slave == UX_NULL || cdc_acm_slave1 == UX_NULL) + /* Do not break. */ + return 0; + + /* All found, break. */ + return 1; +} + +static UINT break_on_removal(VOID) +{ + + if (cdc_acm_host_control != UX_NULL || cdc_acm_host_data != UX_NULL) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control1 != UX_NULL || cdc_acm_host_data1 != UX_NULL) + /* Do not break. */ + return 0; + + if (cdc_acm_slave != UX_NULL || cdc_acm_slave1 != UX_NULL) + /* Do not break. */ + return 0; + + return 1; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + if (cdc_acm_host_control == UX_NULL) + cdc_acm_host_control = cdc_acm; + else + if (cdc_acm_host_control1 == UX_NULL) + cdc_acm_host_control1 = cdc_acm; + } + else + { + if (cdc_acm_host_data == UX_NULL) + cdc_acm_host_data = cdc_acm; + else + if (cdc_acm_host_data1 == UX_NULL) + cdc_acm_host_data1 = cdc_acm; + } + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + if (cdc_acm_host_control == cdc_acm) + cdc_acm_host_control = UX_NULL; + if (cdc_acm_host_control1 == cdc_acm) + cdc_acm_host_control1 = UX_NULL; + } + else + { + if (cdc_acm_host_data == cdc_acm) + cdc_acm_host_data = UX_NULL; + if (cdc_acm_host_data1 == cdc_acm) + cdc_acm_host_data1 = UX_NULL; + } + break; + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + if (cdc_acm_slave == UX_NULL) + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; + else + if (cdc_acm_slave1 == UX_NULL) + cdc_acm_slave1 = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + if ((VOID *)cdc_acm_slave == cdc_instance) + cdc_acm_slave = UX_NULL; + if ((VOID *)cdc_acm_slave1 == cdc_instance) + cdc_acm_slave1 = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + error_callback_counter ++; + + if (!error_callback_ignore) + { + /* Ignore UX_DEVICE_HANDLE_UNKNOWN. */ + if (UX_DEVICE_HANDLE_UNKNOWN == error_code) + return; + { + /* Failed test. */ + printf("#%d, system_level: %d, system_context: %d, error_code: 0x%x\n", __LINE__, system_level, system_context, error_code); + // 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_stack_class_instance_verify_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + +#if UX_TEST_MULTI_IFC_ON + printf("Running ux_host_stack_class_instance_verify Test.................... "); +#else + printf("Running ux_host_stack_class_instance_verify Test................SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + + stepinfo("\n"); + + /* Initialize the free memory pointer */ + stack_pointer = (CHAR *) usbx_memory; + memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 2); + + stepinfo(">>>>>>>>>>>>>>>> ux_system_initialize\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + stepinfo(">>>>>>>>>>>>>>>> ux_host_stack_initialize\n"); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> ux_device_stack_initialize\n"); + + /* 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); + } + + stepinfo(">>>>>>>>>>>>>>>> ux_device_stack_class_register\n"); + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,2, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,4, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#else + error_callback_ignore = UX_TRUE; +#endif + stepinfo(">>>>>>>>>>>>>>>> _ux_test_dcd_sim_slave_initialize\n"); + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Create main test thread\n"); + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #%d\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Create test thread\n"); + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_DONT_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UCHAR invalid_name[UX_MAX_CLASS_NAME_LENGTH + 2]; + +#if !defined(UX_NAME_REFERENCED_BY_POINTER) + stepinfo(">>>>>>>>>>>>>>>> Test _ux_host_stack_class_instance_verify - class name C string errort\n"); + error_callback_ignore = UX_TRUE; + _ux_utility_memory_set(invalid_name, ' ', sizeof(invalid_name)); + _ux_utility_memory_copy(invalid_name, _ux_system_host_class_cdc_acm_name, 21); + status = _ux_host_stack_class_instance_verify(invalid_name, cdc_acm_host_control); + if (status != UX_ERROR) + { + printf("ERROR #%d: expect UX_ERROR but got 0x%x\n", __LINE__, status); + error_counter ++; + } +#if UX_MAX_CLASS_DRIVER > 1 + error_callback_ignore = UX_FALSE; +#endif +#endif + + stepinfo(">>>>>>>>>>>>>>>> Test _ux_host_stack_class_instance_verify - no class driver\n"); + + status = _ux_host_stack_class_instance_verify(_ux_system_host_class_cdc_acm_name, cdc_acm_host_control); + if (status != UX_HOST_CLASS_INSTANCE_UNKNOWN) + { + printf("ERROR #%d: expect UX_HOST_CLASS_INSTANCE_UNKNOWN but got 0x%x\n", __LINE__, status); + error_counter ++; + } + + stepinfo(">>>>>>>>>>>>>>>> ux_host_stack_class_register\n"); +#if UX_MAX_CLASS_DRIVER > 1 + /* Register HID class */ + status = ux_host_stack_class_register(_ux_system_host_class_hid_name, ux_host_class_hid_entry); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#endif + /* Register CDC ACM class */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_entry); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test _ux_host_stack_class_instance_verify - no class driver active\n"); + + status = _ux_host_stack_class_instance_verify(_ux_system_host_class_cdc_acm_name, cdc_acm_host_control); + if (status != UX_HOST_CLASS_INSTANCE_UNKNOWN) + { + printf("ERROR #%d: expect UX_HOST_CLASS_INSTANCE_UNKNOWN but got 0x%x\n", __LINE__, status); + error_counter ++; + } + + stepinfo(">>>>>>>>>>>>>>>> ux_host_stack_hcd_register\n"); + +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + error_callback_ignore = UX_TRUE; /* One of interface no driver. */ +#endif + + /* Register HCD for test */ + 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); + } + + /* Test connect. */ + stepinfo(">>>>>>>>>>>>>>>> Test connect (FS)\n"); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + ux_test_breakable_sleep(500, break_on_cdc_acm_all_ready); + if (!(cdc_acm_host_control + && cdc_acm_host_data + && cdc_acm_slave +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + && cdc_acm_host_control1 + && cdc_acm_host_data1 + && cdc_acm_slave1 +#endif + )) + { + + printf("ERROR #%d: connect fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Test _ux_host_stack_class_instance_verify - instance no match\n"); + + status = _ux_host_stack_class_instance_verify(_ux_system_host_class_cdc_acm_name, (VOID *)4); + if (status != UX_HOST_CLASS_INSTANCE_UNKNOWN) + { + printf("ERROR #%d: expect UX_HOST_CLASS_INSTANCE_UNKNOWN but got 0x%x\n", __LINE__, status); + error_counter ++; + } + + stepinfo(">>>>>>>>>>>>>>>> Test _ux_host_stack_class_instance_verify - class name not match\n"); + + status = _ux_host_stack_class_instance_verify(_ux_system_host_class_hid_name, cdc_acm_host_control); + if (status != UX_HOST_CLASS_INSTANCE_UNKNOWN) + { + printf("ERROR #%d: expect UX_HOST_CLASS_INSTANCE_UNKNOWN but got 0x%x\n", __LINE__, status); + error_counter ++; + } + + stepinfo(">>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + ux_test_breakable_sleep(100, break_on_removal); + + if (cdc_acm_host_control || cdc_acm_host_data || cdc_acm_slave) + { + + printf("ERROR #%d: disconnect fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Deinitialize\n"); + + /* Deinitialize the class. */ + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + + /* Deinitialize the device side of usbx. */ + _ux_device_stack_uninitialize(); + + /* And finally the usbx system resources. */ + _ux_system_uninitialize(); + + stepinfo(">>>>>>>>>>>>>>>> Dump results\n"); + + if (error_counter > 0) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + +void tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + switch (test_slave_code) + { + default: + break; + } + test_slave_state = 0; + tx_thread_suspend(&tx_test_thread_slave_simulation); + } +} diff --git a/test/regression/usbx_ux_host_stack_class_interface_scan_test.c b/test/regression/usbx_ux_host_stack_class_interface_scan_test.c new file mode 100644 index 00000000..bf99fcb9 --- /dev/null +++ b/test/regression/usbx_ux_host_stack_class_interface_scan_test.c @@ -0,0 +1,481 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_stack.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +/* Define USBX demo constants. */ + +#define UX_DEMO_STACK_SIZE 4096 +#define UX_DEMO_BUFFER_SIZE 2048 +#define UX_DEMO_RUN 1 +#define UX_DEMO_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the demo application... */ + +static UCHAR test_error_cases = UX_FALSE; +static UCHAR dpump_entry_error = UX_FALSE; +static ULONG error_callback_counter; + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +/* Define USBX demo global variables. */ + +static unsigned char host_out_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; +static unsigned char host_in_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; +static unsigned char slave_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x08, /* bMaxPacketSize0 */ + 0xec, 0x08, 0x10, 0x00, /* idVendor, idProduct */ + 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x01, /* bNumConfigurations */ + + /* Configuration descriptor */ + 0x09, 0x02, + 0x20, 0x00, /* wTotalLength */ + 0x01, 0x01, /* bNumInterfaces, bConfigurationValue */ + 0x00, + 0xc0, 0x32, /* bmAttributes, bMaxPower */ + + /* Interface descriptor */ + 0x09, 0x04, + 0x00, 0x00, 0x02, /* bInterfaceNumber, bAlternateSetting, bNumEndpoints */ + 0x99, 0x99, 0x99, /* bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00 +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 */ + 0x0a, 0x07, /* idVendor */ + 0x25, 0x40, /* idProduct */ + 0x01, 0x00, + 0x01, 0x02, 0x03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 */ + 0x01, /* bNumConfigurations */ + 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00 +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID tx_demo_instance_activate(VOID *dpump_instance); +static VOID tx_demo_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); +static void tx_demo_thread_slave_simulation_entry(ULONG); + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + error_callback_counter ++; + + /* Failed test. */ + if (!test_error_cases) + { + + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } +} + +static UINT test_ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command) +{ + if (dpump_entry_error) + return UX_NO_CLASS_MATCH; + + return _ux_host_class_dpump_entry(command); +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_stack_class_interface_scan_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; + + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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("Running ux_host_stack_class_interface_scan Test..................... ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_class_interface_scan Test..................... ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, test_ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_class_interface_scan Test..................... ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_class_interface_scan Test..................... ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = tx_demo_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = tx_demo_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_class_interface_scan Test..................... ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_class_interface_scan Test..................... ERROR #7\n"); + 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("Running ux_host_stack_class_interface_scan Test..................... ERROR #4\n"); + 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("Running ux_host_stack_class_interface_scan Test..................... ERROR #8\n"); + test_control_return(1); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_host_stack_class_interface_scan Test..................... ERROR #9\n"); + test_control_return(1); + } +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_DEVICE *device; +UX_DEVICE device_backup; + + /* Inform user. */ + printf("Running ux_host_stack_class_interface_scan Test..................... "); + + /* Find the main data pump container. */ + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + /* DPUMP basic test error. */ + printf("ERROR #10\n"); + test_control_return(1); + } + + /* We get the first instance of the data pump device. */ + do + { + + status = ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump); + tx_thread_relinquish(); + } while (status != UX_SUCCESS); + + /* We still need to wait for the data pump status to be live. */ + while (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + { + + tx_thread_relinquish(); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: fail to get device instance\n", __LINE__); + test_control_return(1); + } + + /* Simulate _ux_host_stack_class_interface_scan error cases. */ + + /* Backup device instance. */ + ux_utility_memory_copy(&device_backup, device, sizeof(device_backup)); + + /* Simulate error: no configuration. */ + device->ux_device_first_configuration = UX_NULL; + status = _ux_host_stack_class_interface_scan(device); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: Expects error since no configuration\n", __LINE__); + error_counter ++; + } + + /* Restore device instance. */ + ux_utility_memory_copy(device, &device_backup, sizeof(device_backup)); + + /* Disconnect. */ + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + dpump_entry_error = UX_TRUE; + test_error_cases = UX_TRUE; + error_callback_counter = 0; + + /* Connect. */ + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + tx_thread_sleep(100); + + if (error_callback_counter == 0) + { + printf("ERROR #%d: expects error\n", __LINE__); + error_counter ++; + } + dpump_entry_error = UX_FALSE; + test_error_cases = UX_FALSE; + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* DPUMP error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + + +static void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Ensure the dpump class on the device is still alive. */ + if (dpump_slave != UX_NULL) + { + + /* Increment thread counter. */ + thread_1_counter++; + } + + /* Let other thread run. */ + tx_thread_sleep(10); + } +} + +static VOID tx_demo_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID tx_demo_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_host_stack_class_register_test.c b/test/regression/usbx_ux_host_stack_class_register_test.c new file mode 100644 index 00000000..7dcd3fc3 --- /dev/null +++ b/test/regression/usbx_ux_host_stack_class_register_test.c @@ -0,0 +1,519 @@ +/* This test is designed to test the ux_host_stack_class_register. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +/* HID mouse related descriptors */ + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +#define LSB(x) (x & 0x00ff) +#define MSB(x) ((x & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x20, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors 9+7+7=23 bytes. */ +#define DPUMP_IFC_DESC_ALL(ifc, bulk_in_epa, bulk_out_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x02, 0x99, 0x99, 0x99, 0x00,\ + /* Endpoint descriptor (Bulk Out) */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Bulk In) */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00, +#define DPUMP_IFC_DESC_ALL_LEN 23 + +/* HID Mouse interface descriptors 9+9=18 bytes */ +#define HID_MOUSE_IFC0_DESC_ALL(ifc) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH), +#define HID_MOUSE_IFC0_DESC_ALL_LEN 18 + +/* HID Mouse interface descriptors 9+9+7=25 bytes */ +#define HID_MOUSE_IFC1_DESC_ALL(ifc, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x01, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_MOUSE_IFC1_DESC_ALL_LEN 25 + +/* CDC-ACM interfaces descriptors 8 +9+5+4+5+5+7 +9+7+7=66 bytes */ +#define CDC_ACM_IFCES_DESC_ALL(ifc, interrupt_epa, bulk_in_epa, bulk_out_epa) \ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (ifc), 0x02, 0x02, 0x02, 0x00, 0x00,\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (ifc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06,\ + (ifc), /* Master interface */\ + (ifc+1), /* Slave interface */\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03,\ + (ifc+1), /* Data interface */\ + /* Interrupt endpoint descriptor 7 bytes */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 15,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (ifc+1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint descriptor 7 bytes */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor 7 bytes */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00, +#define CDC_ACM_IFCES_DESC_ALL_LEN 66 + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR expect_errors = UX_FALSE; + + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN + CDC_ACM_IFCES_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+9+7 =25 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02) + /* HID 9+9 + 9+9+7=43 */ + HID_MOUSE_IFC0_DESC_ALL(1) + HID_MOUSE_IFC1_DESC_ALL(1, 0x83) + /* CDC-ACM */ + CDC_ACM_IFCES_DESC_ALL(2, 0x86, 0x85, 0x04) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN + CDC_ACM_IFCES_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+9+7 =25 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02) + /* HID 9+9 + 9+9+7=43 */ + HID_MOUSE_IFC0_DESC_ALL(1) + HID_MOUSE_IFC1_DESC_ALL(1, 0x83) + /* CDC-ACM */ + CDC_ACM_IFCES_DESC_ALL(2, 0x86, 0x85, 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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Simulation actions. */ + +static UX_TEST_SIM_ENTRY_ACTION dcd_endpoint_create_fail[] = { +/* 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_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ 0 } +}; + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (!expect_errors) + { + if (error_code != UX_DEVICE_HANDLE_UNKNOWN) + { + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } + } +} + +static UINT test_ux_device_class_hid_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + return UX_SUCCESS; + // return _ux_device_class_hid_entry(command); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_stack_class_register_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; +UX_SLAVE_CLASS_HID_PARAMETER hid_parameter; + + /* Inform user. */ + printf("Running ux_host_stack_class_register Test........................... "); + stepinfo("\n"); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + 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(UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry); + + /* Check for error. */ + 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 */ + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = ux_test_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = ux_test_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Initialize the hid class parameters. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_REPORT_LENGTH; + hid_parameter.ux_device_class_hid_parameter_callback = UX_NULL; + hid_parameter.ux_slave_class_hid_instance_activate = UX_NULL; + + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, test_ux_device_class_hid_entry, + 1, 1, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#endif + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test host simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + +UINT status; +UCHAR invalid_class_name[UX_MAX_CLASS_NAME_LENGTH+2]; + + + /* Inform user. */ + stepinfo(">>>>>>>>> ENUM check\n"); + + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Enumeration check. */ + if (dpump_slave == UX_NULL) + { + + printf("ERROR #%d: Enum fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>> Disconnect\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Expect errors so skip them in error handler. */ + expect_errors = UX_TRUE; + +#if !defined(UX_NAME_REFERENCED_BY_POINTER) + stepinfo(">>>>>>>>> _ux_host_stack_class_register - error if class_name exceed UX_MAX_CLASS_NAME_LENGTH\n"); + _ux_utility_memory_set(invalid_class_name, 'a', sizeof(invalid_class_name)); + _ux_utility_memory_copy(invalid_class_name, _ux_system_host_class_dpump_name, 19); + status = _ux_host_stack_class_register(invalid_class_name, ux_host_class_dpump_entry); + if (status != UX_ERROR) + { + printf("ERROR %d: expect error %d\n", __LINE__, UX_ERROR); + error_counter ++; + } +#endif + + /* Break on errors. */ + expect_errors = UX_TRUE; + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static VOID ux_test_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID ux_test_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_host_stack_class_unregister_test.c b/test/regression/usbx_ux_host_stack_class_unregister_test.c new file mode 100644 index 00000000..570712af --- /dev/null +++ b/test/regression/usbx_ux_host_stack_class_unregister_test.c @@ -0,0 +1,797 @@ +/* This test is designed to test the ux_utility_memory_.... */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_device_class_dpump.h" +#include "ux_host_class_dpump.h" + +#include "fx_api.h" +#include "ux_device_class_storage.h" +#include "ux_host_class_storage.h" + +#include "ux_device_class_hid.h" +#include "ux_host_class_hid.h" +#include "ux_host_class_hid_mouse.h" + +#include "ux_host_stack.h" +#include "ux_hcd_sim_host.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_MEMORY_SIZE (256*1024) + +#define UX_RAM_DISK_SIZE (200 * 1024) +#define UX_RAM_DISK_LAST_LBA ((UX_RAM_DISK_SIZE / 512) -1) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter = 0; +static ULONG thread_1_counter = 0; + +static ULONG error_counter = 0; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter = 0; + +static UCHAR bad_name[UX_MAX_HCD_NAME_LENGTH + 1]; + +static FX_MEDIA ram_disk1 = {0}; +static CHAR ram_disk_memory1[UX_RAM_DISK_SIZE]; +static UCHAR ram_disk_buffer1[512]; + +static FX_MEDIA *ram_disks[] = {&ram_disk1}; +static UCHAR *ram_disk_buffers[] = {ram_disk_buffer1}; +static CHAR *ram_disk_memories[] = {ram_disk_memory1}; + +static UX_SLAVE_CLASS_DPUMP_PARAMETER dpump_parameter = {0}; +static UX_SLAVE_CLASS_STORAGE_PARAMETER storage_parameter = {0}; +static UX_SLAVE_CLASS_HID_PARAMETER hid_parameter = {0}; + +UX_HOST_CLASS_DPUMP *host_dpump = UX_NULL; +UX_HOST_CLASS_STORAGE *host_storage = UX_NULL; +UX_HOST_CLASS_HID *host_hid = UX_NULL; + + +/* Define USBX test global variables. */ + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + + +#define CONFIG_DESCRIPTOR(wTotalLength, n_iface) \ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength), (n_iface), 0x01, 0x00, 0xc0, 0x32, + +#define DPUMP_DESCRIPTORS_LENGTH (9+7+7) +#define DPUMP_DESCRIPTORS(iface, ep_out, ep_in, mps) \ + /* Interface descriptor */ \ + 0x09, 0x04, (iface), 0x00, 0x02, 0x99, 0x99, 0x99, 0x00, \ + /* Endpoint descriptor (Bulk Out) */ \ + 0x07, 0x05, (ep_out), 0x02, LSB(mps), MSB(mps), 0x00, \ + /* Endpoint descriptor (Bulk In) */ \ + 0x07, 0x05, (ep_in), 0x02, LSB(mps), MSB(mps), 0x00, + +#define STORAGE_DESCRIPTORS_LENGTH (9+7+7) +#define STORAGE_DESCRIPTORS(iface, ep_out, ep_in, mps) \ + /* Interface descriptor */ \ + 0x09, 0x04, (iface), 0x00, 0x02, 0x08, 0x06, 0x50, 0x00, \ + /* Endpoint descriptor (Bulk In) */ \ + 0x07, 0x05, (ep_in), 0x02, 0x00, 0x01, 0x00, \ + /* Endpoint descriptor (Bulk Out) */ \ + 0x07, 0x05, (ep_out), 0x02, 0x00, 0x01, 0x00, + +#define HID_DESCRIPTORS_LENGTH (9+9+7) +#define HID_DESCRIPTORS(iface, ep_in, mps, interval, rpt_len) \ + /* Interface descriptor */ \ + 0x09, 0x04, (iface), 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, \ + /* HID descriptor */ \ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, \ + LSB(rpt_len), MSB(rpt_len), \ + /* Endpoint descriptor (Interrupt) */ \ + 0x07, 0x05, (ep_in), 0x03, LSB(mps), MSB(mps), (interval), + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CONFIG_DESCRIPTOR(DPUMP_DESCRIPTORS_LENGTH + + STORAGE_DESCRIPTORS_LENGTH + + HID_DESCRIPTORS_LENGTH + 9, 0x03) + DPUMP_DESCRIPTORS(0x00, 0x01, 0x82, 64) + STORAGE_DESCRIPTORS(0x01, 0x03, 0x84, 64) + HID_DESCRIPTORS(0x02, 0x85, 8, 8, HID_MOUSE_REPORT_LENGTH) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CONFIG_DESCRIPTOR(DPUMP_DESCRIPTORS_LENGTH + + STORAGE_DESCRIPTORS_LENGTH + + HID_DESCRIPTORS_LENGTH + 9, 0x03) + DPUMP_DESCRIPTORS(0x00, 0x01, 0x82, 512) + STORAGE_DESCRIPTORS(0x01, 0x03, 0x84, 512) + HID_DESCRIPTORS(0x02, 0x85, 8, 8, HID_MOUSE_REPORT_LENGTH) +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +#define STRING_FRAMEWORK_LENGTH 38 +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* 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 +}; + + +/* Define prototypes for external Controller's (HCD/DCDs), classes and clients. */ + +extern VOID _fx_ram_driver(FX_MEDIA *media_ptr); + +static TX_THREAD ux_test_thread_simulation_0; +static void ux_test_thread_simulation_0_entry(ULONG); + +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_1_entry(ULONG); + +static UX_SLAVE_CLASS_DPUMP *dpump_device = UX_NULL; +static VOID ux_test_dpump_instance_activate(VOID *dpump_instance); +static VOID ux_test_dpump_instance_deactivate(VOID *dpump_instance); + +static UINT ux_test_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT ux_test_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status); +static UINT ux_test_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status); + +/* 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("#%d, system_level: %d, system_context: %d, error_code: 0x%x\n", __LINE__, system_level, system_context, error_code); + } + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_stack_class_unregister_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +UCHAR *stack_pointer; +UCHAR *memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_stack_class_unregister Test......................... "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + +#if UX_TEST_MULTI_CLS_OVER(2) && UX_TEST_MULTI_IFC_OVER(2) /* At least 3 classes used. */ + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); +#endif + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + dpump_parameter.ux_slave_class_dpump_instance_activate = ux_test_dpump_instance_activate; + dpump_parameter.ux_slave_class_dpump_instance_deactivate = ux_test_dpump_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, &dpump_parameter); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Store the number of LUN in this device storage instance. */ + storage_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + /* Initialize the storage class parameters for reading/writing to the first Flash Disk. */ + storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba = UX_RAM_DISK_LAST_LBA; + storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length = 512; + storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type = 0; + storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag = 0x80; + storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = ux_test_media_read; + storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = ux_test_media_write; + storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = ux_test_media_status; + + /* Initialize the device storage class. The class is connected with interface 0 on configuration 1. */ + status = ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_device_class_storage_entry, + 1, 1, (VOID *)&storage_parameter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#endif + + /* Initialize the hid class parameters for a mouse. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_REPORT_LENGTH; + hid_parameter.ux_device_class_hid_parameter_callback = UX_NULL; + + /* 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 UX_MAX_SLAVE_CLASS_DRIVER > 1 + if(status!=UX_SUCCESS) + { + + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } +#endif + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void ux_test_ram_disk_initialize(INT line) +{ +UINT status; + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Reset ram disks memory. */ + ux_utility_memory_set(ram_disk_memory1, 0, UX_RAM_DISK_SIZE); + + /* Format the ram drive. */ + status = fx_media_format(&ram_disk1, _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512, "RAM DISK1", 2, 512, 0, UX_RAM_DISK_SIZE/512, 512, 4, 1, 1); + if (status != FX_SUCCESS) + { + printf("ERROR #%d.%d: 0x%x\n", line, __LINE__, status); + test_control_return(1); + } + + /* Open the ram_disk. */ + status = fx_media_open(&ram_disk1, "RAM DISK1", _fx_ram_driver, ram_disk_memory1, ram_disk_buffer1, 512); + if (status != FX_SUCCESS) + { + printf("ERROR #%d.%d: 0x%x\n", line, __LINE__, status); + test_control_return(1); + } + +} + +static void ux_test_host_stack_class_register(INT line) +{ + +UINT status; + + // printf("#%d.%d: register classes\n", line, __LINE__); + + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: 0x%x\n", line, __LINE__, status); + test_control_return(1); + } + +#if UX_MAX_CLASS_DRIVER == 1 + error_callback_ignore = UX_TRUE; +#endif + + status = ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry); +#if UX_MAX_CLASS_DRIVER > 1 + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: 0x%x\n", line, __LINE__, status); + test_control_return(1); + } +#endif + + status = ux_host_stack_class_register(_ux_system_host_class_hid_name, ux_host_class_hid_entry); +#if UX_MAX_CLASS_DRIVER > 1 + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: 0x%x\n", line, __LINE__, status); + test_control_return(1); + } + + /* Register the HID client(s). */ + status = ux_host_class_hid_client_register(_ux_system_host_class_hid_client_mouse_name, ux_host_class_hid_mouse_entry); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: 0x%x\n", line, __LINE__, status); + test_control_return(1); + } +#endif + +#if UX_MAX_CLASS_DRIVER == 1 + error_callback_ignore = UX_FALSE; +#endif +} + +static void ux_test_host_stack_class_unregister(INT line) +{ + +UINT status; + + // printf("#%d.%d: unregister classes\n", line, __LINE__); + + /* Dpump has no "destroy", ignore UX_FUNCTION_NOT_SUPPORTED print. */ + error_callback_ignore = UX_TRUE; + status = _ux_host_stack_class_unregister(ux_host_class_dpump_entry); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: 0x%x\n", line, __LINE__, status); + test_control_return(1); + } + error_callback_ignore = UX_FALSE; + + status = _ux_host_stack_class_unregister(ux_host_class_storage_entry); +#if UX_MAX_CLASS_DRIVER > 1 + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: 0x%x\n", line, __LINE__, status); + test_control_return(1); + } +#endif + + status = _ux_host_stack_class_unregister(ux_host_class_hid_entry); +#if UX_MAX_CLASS_DRIVER > 1 + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: 0x%x\n", line, __LINE__, status); + test_control_return(1); + } +#endif +} + +static void ux_test_host_stack_hcd_register(INT line) +{ +UINT status; + + /* Register HCD. */ + status = _ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_hcd_sim_host_initialize,0,0); + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: 0x%x\n", line, __LINE__, status); + test_control_return(1); + } +} + +static void ux_test_host_stack_hcd_unregister(INT line) +{ +UINT status; +UX_DEVICE *device; + + /* Unregister HCD. */ + status = _ux_host_stack_hcd_unregister(_ux_system_host_hcd_simulator_name, 0, 0); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Check host device. */ + status = _ux_host_stack_device_get(0, &device); + if (status != UX_DEVICE_HANDLE_UNKNOWN) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void ux_test_wait_connect(INT line) +{ + +UINT status; +INT i; +UX_DEVICE *device; +UX_HOST_CLASS *host_class; + + host_dpump = UX_NULL; + host_storage = UX_NULL; + host_hid = UX_NULL; + + /* Wait for connection. */ + for (i = 0; i < 100; i ++) + { + tx_thread_sleep(UX_MS_TO_TICK_NON_ZERO(10)); + status = _ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + continue; + if (dpump_device == UX_NULL) + continue; + + /* DPUMP. */ + ux_host_stack_class_get(_ux_system_host_class_dpump_name, &host_class); + status = ux_host_stack_class_instance_get(host_class, 0, (VOID **)&host_dpump); + if (status != UX_SUCCESS) + continue; + if (host_dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + continue; + + /* Storage. */ + ux_host_stack_class_get(_ux_system_host_class_storage_name, &host_class); + status = ux_host_stack_class_instance_get(host_class, 0, (VOID **)&host_storage); + if (status != UX_SUCCESS) + continue; + if (host_storage -> ux_host_class_storage_state != UX_HOST_CLASS_INSTANCE_LIVE) + continue; + + /* HID. */ + ux_host_stack_class_get(_ux_system_host_class_hid_name, &host_class); + status = ux_host_stack_class_instance_get(host_class, 0, (VOID **)&host_hid); + if (status != UX_SUCCESS) + continue; + if (host_hid -> ux_host_class_hid_state != UX_HOST_CLASS_INSTANCE_LIVE) + continue; + + /* All ready. */ + break; + } + if (dpump_device == UX_NULL) + { + printf("ERROR #%d.%d\n", line, __LINE__); + test_control_return(1); + } + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d\n", line, __LINE__); + test_control_return(1); + } +} + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + +UINT status; +ULONG rfree; +INT i; +UX_DEVICE *device; + + /* Initialize RAM disk. */ + ux_test_ram_disk_initialize(__LINE__); + + /* Initialize host stack. */ + status = ux_host_stack_initialize(UX_NULL); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /************************** Register & unregister (no device connected). */ + + /* Log memory level. */ + rfree = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + ux_test_host_stack_class_register(__LINE__); + ux_test_host_stack_class_unregister(__LINE__); + + /* Check memory level. */ + if (rfree != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + + /************************** Unregister (after device connect & disconnect). */ + + error_callback_ignore = UX_TRUE; + + // ux_test_dcd_sim_slave_disconnect(); + // ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + + ux_test_host_stack_class_register(__LINE__); + ux_test_host_stack_hcd_register(__LINE__); + ux_test_wait_connect(__LINE__); + + /* Unregister. */ + error_callback_ignore = UX_TRUE; + ux_test_host_stack_hcd_unregister(__LINE__); + error_callback_ignore = UX_FALSE; + + ux_test_host_stack_hcd_register(__LINE__); + ux_test_wait_connect(__LINE__); + + /* Unregister. */ + error_callback_ignore = UX_TRUE; + ux_test_host_stack_hcd_unregister(__LINE__); + ux_test_host_stack_class_unregister(__LINE__); + error_callback_ignore = UX_FALSE; + + // ux_test_dcd_sim_slave_disconnect(); + // ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + + /* Log memory level. */ + rfree = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + ux_test_host_stack_class_register(__LINE__); + ux_test_host_stack_hcd_register(__LINE__); + ux_test_wait_connect(__LINE__); + + /* Unregister. */ + error_callback_ignore = UX_TRUE; + ux_test_host_stack_hcd_unregister(__LINE__); + ux_test_host_stack_class_unregister(__LINE__); + + /* Check memory level. */ + if (rfree != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + printf("Error on line %d\n", __LINE__); + test_control_return(1); + } + error_callback_ignore = UX_FALSE; + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + + +static VOID ux_test_dpump_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_device = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID ux_test_dpump_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_device = UX_NULL; +} + +static UINT ux_test_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + +static UCHAR lun_init_done[2] = {0, 0}; +UINT status; +ULONG mstatus = UX_SLAVE_CLASS_STORAGE_SENSE_KEY_NO_SENSE; + + + (void)storage; + (void)media_id; + + + if (lun > 0) + status = (UX_ERROR); + else if (lun_init_done[lun] > 0) + status = (UX_SUCCESS); + else + { + lun_init_done[lun] ++; + mstatus = UX_SLAVE_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION | (0x28 << 8); + status = (UX_ERROR); + } + + if (media_status) + *media_status = mstatus; + + return status; +} + +UINT ux_test_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + +UINT status = 0; + + if(lba == 0) + { + ram_disks[lun]->fx_media_driver_logical_sector = 0; + ram_disks[lun]->fx_media_driver_sectors = 1; + ram_disks[lun]->fx_media_driver_request = FX_DRIVER_BOOT_READ; + ram_disks[lun]->fx_media_driver_buffer = data_pointer; + _fx_ram_driver(ram_disks[lun]); + *(data_pointer) = 0xeb; + *(data_pointer+1) = 0x3c; + *(data_pointer+2) = 0x90; + *(data_pointer+21) = 0xF8; + + *(data_pointer+24) = 0x01; + *(data_pointer+26) = 0x10; + *(data_pointer+28) = 0x01; + + *(data_pointer+510) = 0x55; + *(data_pointer+511) = 0xaa; + ux_utility_memory_copy(data_pointer+0x36,"FAT12",5); + + + status = ram_disks[lun]->fx_media_driver_status; + } + else + { + while(number_blocks--) + { + status = fx_media_read(ram_disks[lun],lba,data_pointer); + data_pointer+=512; + lba++; + } + } + return(status); +} + +UINT ux_test_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + +UINT status = 0; + + if(lba == 0) + { + ram_disks[lun]->fx_media_driver_logical_sector = 0; + ram_disks[lun]->fx_media_driver_sectors = 1; + ram_disks[lun]->fx_media_driver_request = FX_DRIVER_BOOT_WRITE; + ram_disks[lun]->fx_media_driver_buffer = data_pointer; + _fx_ram_driver(ram_disks[lun]); + + status = ram_disks[lun]->fx_media_driver_status; + + } + else + { + + while(number_blocks--) + { + status = fx_media_write(ram_disks[lun],lba,data_pointer); + data_pointer+=512; + lba++; + } + return(status); + } + return(status); +} diff --git a/test/regression/usbx_ux_host_stack_configuration_descriptor_parse_test.c b/test/regression/usbx_ux_host_stack_configuration_descriptor_parse_test.c new file mode 100644 index 00000000..97fd1f1a --- /dev/null +++ b/test/regression/usbx_ux_host_stack_configuration_descriptor_parse_test.c @@ -0,0 +1,518 @@ +/* This test is designed to test the ux_host_stack_configuration_descriptor_parse. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +/* HID mouse related descriptors */ + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +#define LSB(x) (x & 0x00ff) +#define MSB(x) ((x & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors 9+7+7+7=30 bytes. */ +#define DPUMP_IFC_DESC_ALL(ifc, bulk_in_epa, bulk_out_epa, int_in_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x03, 0x99, 0x99, 0x99, 0x00,\ + /* Endpoint descriptor (Bulk Out) */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Bulk In) */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Interrupt In) */\ + 0x07, 0x05, (int_in_epa), 0x02, 0x40, 0x00, 0x00, +#define DPUMP_IFC_DESC_ALL_LEN 30 + +/* HID Mouse interface descriptors 9+9+7=25 bytes */ +#define HID_MOUSE_IFC_DESC_ALL(ifc, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x01, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_MOUSE_IFC_DESC_ALL_LEN 25 + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+7+7+7 =30 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02, 0x83) + /* HID 9+9+7 =25 */ + HID_MOUSE_IFC_DESC_ALL(1, 0x84) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+7+7+7 =30 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02, 0x83) + /* HID 9+9+7 =25 */ + HID_MOUSE_IFC_DESC_ALL(1, 0x84) +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Simulation actions. */ + +static UX_TEST_SIM_ENTRY_ACTION dcd_endpoint_create_fail[] = { +/* 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_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_SUCCESS , UX_NULL, + UX_TRUE}, +{ UX_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ UX_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ UX_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ UX_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ 0 } +}; + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 test_ux_device_class_hid_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + switch(command->ux_slave_class_command_request) + { + case UX_SLAVE_CLASS_COMMAND_INITIALIZE: + case UX_SLAVE_CLASS_COMMAND_QUERY: + return UX_SUCCESS; + + default: + return UX_NO_CLASS_MATCH; + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_stack_configuration_descriptor_parse_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; +UX_SLAVE_CLASS_HID_PARAMETER hid_parameter; + + +#if !(UX_TEST_MULTI_IFC_ON) + printf("Running ux_host_stack_configuration_descriptor_parse Test........... SKIP!"); + test_control_return(0); + return; +#endif + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_descriptor_parse Test........... ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_descriptor_parse Test........... ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_descriptor_parse Test........... ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_descriptor_parse Test........... ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = ux_test_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = ux_test_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Initialize the hid class parameters. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_REPORT_LENGTH; + hid_parameter.ux_device_class_hid_parameter_callback = UX_NULL; + hid_parameter.ux_slave_class_hid_instance_activate = UX_NULL; + + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, test_ux_device_class_hid_entry, + 1, 1, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_descriptor_parse Test........... ERROR #6\n"); + test_control_return(1); + } +#endif + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_descriptor_parse Test........... ERROR #7\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_descriptor_parse Test........... ERROR #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test host simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_descriptor_parse Test........... ERROR #8\n"); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + +UINT status; +UX_DEVICE *device; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +UX_CONFIGURATION *configuration; +ULONG wTotalLength; + + /* Inform user. */ + printf("Running ux_host_stack_configuration_descriptor_parse Test........... "); + + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Enumeration check. */ + if (dpump_slave == UX_NULL) + { + + printf("ERROR #%d: Enum fail\n", __LINE__); + test_control_return(1); + } + + /* Get device instance. */ + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail: 0x%x\n", __LINE__, status); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Get configuration. */ + status = ux_host_stack_device_configuration_get(device, 0, &configuration); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_configuration_get fail: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Increase wTotalLength for test. */ + wTotalLength = configuration->ux_configuration_descriptor.wTotalLength; + configuration->ux_configuration_descriptor.wTotalLength += 8; + + status = _ux_host_stack_configuration_descriptor_parse(device, configuration, 0); + + /* Restore wTotalLength. */ + configuration->ux_configuration_descriptor.wTotalLength = wTotalLength; + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static VOID ux_test_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID ux_test_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_host_stack_configuration_enumerate_test.c b/test/regression/usbx_ux_host_stack_configuration_enumerate_test.c new file mode 100644 index 00000000..6aa1afbe --- /dev/null +++ b/test/regression/usbx_ux_host_stack_configuration_enumerate_test.c @@ -0,0 +1,468 @@ +/* This test is designed to test the ux_host_stack_configuration_enumerate. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +/* HID mouse related descriptors */ + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +#define LSB(x) (x & 0x00ff) +#define MSB(x) ((x & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors 9+7+7+7=30 bytes. */ +#define DPUMP_IFC_DESC_ALL(ifc, bulk_in_epa, bulk_out_epa, int_in_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x03, 0x99, 0x99, 0x99, 0x00,\ + /* Endpoint descriptor (Bulk Out) */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Bulk In) */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Interrupt In) */\ + 0x07, 0x05, (int_in_epa), 0x02, 0x40, 0x00, 0x00, +#define DPUMP_IFC_DESC_ALL_LEN 30 + +/* HID Mouse interface descriptors 9+9+7=25 bytes */ +#define HID_MOUSE_IFC_DESC_ALL(ifc, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x01, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_MOUSE_IFC_DESC_ALL_LEN 25 + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+7+7+7 =30 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02, 0x83) + /* HID 9+9+7 =25 */ + HID_MOUSE_IFC_DESC_ALL(1, 0x84) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+7+7+7 =30 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02, 0x83) + /* HID 9+9+7 =25 */ + HID_MOUSE_IFC_DESC_ALL(1, 0x84) +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Simulation actions. */ + +static UX_TEST_SETUP _GetConfigDescriptor = UX_TEST_SETUP_GetCfgDescr; + +static UX_TEST_HCD_SIM_ACTION get_cfg_desc_len_error[] = { +/* 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, &_GetConfigDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 18, UX_CONFIGURATION_DESCRIPTOR_LENGTH - 1, 0, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 test_ux_device_class_hid_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + switch(command->ux_slave_class_command_request) + { + case UX_SLAVE_CLASS_COMMAND_INITIALIZE: + case UX_SLAVE_CLASS_COMMAND_QUERY: + return UX_SUCCESS; + + default: + return UX_NO_CLASS_MATCH; + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_stack_configuration_enumerate_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; +UX_SLAVE_CLASS_HID_PARAMETER hid_parameter; + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_enumerate Test.................. ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_enumerate Test.................. ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_enumerate Test.................. ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_enumerate Test.................. ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = ux_test_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = ux_test_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Initialize the hid class parameters. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_REPORT_LENGTH; + hid_parameter.ux_device_class_hid_parameter_callback = UX_NULL; + hid_parameter.ux_slave_class_hid_instance_activate = UX_NULL; + + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, test_ux_device_class_hid_entry, + 1, 1, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_enumerate Test.................. ERROR #6\n"); + test_control_return(1); + } +#endif + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_enumerate Test.................. ERROR #7\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_enumerate Test.................. ERROR #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test host simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_enumerate Test.................. ERROR #8\n"); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + + /* Inform user. */ + printf("Running ux_host_stack_configuration_enumerate Test.................. "); + + /* Simulate GetConfiguration length error. */ + ux_test_hcd_sim_host_set_actions(get_cfg_desc_len_error); + + /* No break if error callback is called. */ + error_callback_ignore = UX_TRUE; + error_callback_counter = 0; + + /* Connect. */ + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + tx_thread_sleep(100); + + /* Enumeration check, may fail if no retry and success on more than one retry. */ + /* There is error reported. */ + if (error_callback_counter == 0) + { + + printf("ERROR #%d: Expect error\n", __LINE__); + error_counter ++; + } + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static VOID ux_test_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID ux_test_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_host_stack_configuration_instance_delete_test.c b/test/regression/usbx_ux_host_stack_configuration_instance_delete_test.c new file mode 100644 index 00000000..edec2c2e --- /dev/null +++ b/test/regression/usbx_ux_host_stack_configuration_instance_delete_test.c @@ -0,0 +1,458 @@ +/* This test is designed to test the ux_host_stack_configuration_instance_delete. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors. */ +#define DPUMP_IFC_DESC(ifc, alt, nb_ep) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), (alt), (nb_ep), 0x99, 0x99, 0x99, 0x00, + +#define DPUMP_IFC_EP_DESC(epa) \ + /* Endpoint descriptor */\ + 0x07, 0x05, (epa), 0x02, 0x40, 0x00, 0x00, + +#define DPUMP_IFC_DESC_ALL_LEN(nb_ep) (9 + (nb_ep) * 7) + +#define CFG_DESC_ALL_LEN (CFG_DESC_LEN + \ + DPUMP_IFC_DESC_ALL_LEN(0) + \ + DPUMP_IFC_DESC_ALL_LEN(1) + \ + DPUMP_IFC_DESC_ALL_LEN(2) + \ + DPUMP_IFC_DESC_ALL_LEN(3) + \ + DPUMP_IFC_DESC_ALL_LEN(4) \ + ) + +#define CFG_DESC_ALL \ + CFG_DESC(CFG_DESC_ALL_LEN, 5, 1)\ + DPUMP_IFC_DESC(0, 0, 0)\ + DPUMP_IFC_DESC(0, 1, 1)\ + DPUMP_IFC_EP_DESC(0x81)\ + DPUMP_IFC_DESC(0, 2, 2)\ + DPUMP_IFC_EP_DESC(0x81)\ + DPUMP_IFC_EP_DESC(0x02)\ + DPUMP_IFC_DESC(0, 3, 3)\ + DPUMP_IFC_EP_DESC(0x81)\ + DPUMP_IFC_EP_DESC(0x02)\ + DPUMP_IFC_EP_DESC(0x83)\ + DPUMP_IFC_DESC(0, 4, 4)\ + DPUMP_IFC_EP_DESC(0x81)\ + DPUMP_IFC_EP_DESC(0x02)\ + DPUMP_IFC_EP_DESC(0x83)\ + DPUMP_IFC_EP_DESC(0x04) + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC_ALL +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC_ALL +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 test_ux_device_class_dpump_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + switch(command->ux_slave_class_command_request) + { + case UX_SLAVE_CLASS_COMMAND_INITIALIZE: + case UX_SLAVE_CLASS_COMMAND_QUERY: + case UX_SLAVE_CLASS_COMMAND_CHANGE: + return UX_SUCCESS; + + default: + return UX_NO_CLASS_MATCH; + } +} + +static UINT test_ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command) +{ + switch (command -> ux_host_class_command_request) + { + case UX_HOST_CLASS_COMMAND_QUERY: + case UX_HOST_CLASS_COMMAND_ACTIVATE: + return UX_SUCCESS; + + default: + return UX_NO_CLASS_MATCH; + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_stack_configuration_instance_delete_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; + +#if !(UX_TEST_MULTI_IFC_ON) + printf("Running ux_host_stack_configuration_instance_delete Test............ SKIP!"); + test_control_return(0); + return; +#endif + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_instance_delete Test............ ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_instance_delete Test............ ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, test_ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_instance_delete Test............ ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_instance_delete Test............ ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = UX_NULL; + parameter.ux_slave_class_dpump_instance_deactivate = UX_NULL; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, test_ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_instance_delete Test............ ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_instance_delete Test............ ERROR #7\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_instance_delete Test............ ERROR #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test host simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_instance_delete Test............ ERROR #8\n"); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + +UINT status; +INT i; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +UX_INTERFACE *interfaces[8]; + + /* Inform user. */ + printf("Running ux_host_stack_configuration_instance_delete Test............ "); + + /* Connect. */ + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + tx_thread_sleep(100); + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_configuration_get(device, 0, &configuration); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: cfg_get fail\n", __LINE__); + test_control_return(1); + } + + interface = configuration->ux_configuration_first_interface; + for (i = 0; i < 8; i ++) + { + + if (interface == UX_NULL) + break; + + interfaces[i] = interface; + interface = interface->ux_interface_next_interface; + } + + /* Set configure. */ + status = ux_host_stack_device_configuration_select(configuration); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: cfg_set fail\n", __LINE__); + test_control_return(1); + } + + /* Switch to interface 0.4 */ + status = ux_host_stack_interface_setting_select(interfaces[4]); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: ifc_set fail\n", __LINE__); + error_counter ++; + } + + /* Reset configuration. */ + status = _ux_host_stack_device_configuration_reset(device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: cfg_reset fail\n", __LINE__); + error_counter ++; + } + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_ux_host_stack_configuration_interface_get_test.c b/test/regression/usbx_ux_host_stack_configuration_interface_get_test.c new file mode 100644 index 00000000..af698fb2 --- /dev/null +++ b/test/regression/usbx_ux_host_stack_configuration_interface_get_test.c @@ -0,0 +1,412 @@ +/* This test is designed to test the ux_host_stack_configuration_interface_get. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + + +/* Define USBX test global variables. */ + +static unsigned char host_out_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; +static unsigned char host_in_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; +static unsigned char slave_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave; + + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x32, 0x00, 0x02, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, + + /* Interface descriptor */ + 0x09, 0x04, 0x01, 0x00, 0x00, 0xFF, 0xFF, 0xFF, + 0x00, + + /* Interface descriptor */ + 0x09, 0x04, 0x01, 0x01, 0x00, 0xFF, 0xFF, 0xFF, + 0x00 + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 78 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x32, 0x00, 0x02, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00, + + /* Interface descriptor */ + 0x09, 0x04, 0x01, 0x00, 0x00, 0xFF, 0xFF, 0xFF, + 0x00, + + /* Interface descriptor */ + 0x09, 0x04, 0x01, 0x01, 0x00, 0xFF, 0xFF, 0xFF, + 0x00 + + }; + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* 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 + }; + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_host_simulation; +static TX_THREAD ux_test_thread_slave_simulation; +static void ux_test_thread_host_simulation_entry(ULONG); +static void ux_test_thread_slave_simulation_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (error_code != UX_INTERFACE_HANDLE_UNKNOWN) + { + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + 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_stack_configuration_interface_get_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; + + + /* Inform user. */ + printf("Running ux_host_stack_configuration_interface_get Test.............. "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = ux_test_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = ux_test_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #7\n"); + 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 #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_host_simulation, "test host simulation", ux_test_thread_host_simulation_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #8\n"); + test_control_return(1); + } +} + + +static void ux_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_INTERFACE *test_interface; + + + /* Find the main data pump container. */ + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + /* DPUMP basic test error. */ + printf("ERROR #9\n"); + test_control_return(1); + } + + /* We get the first instance of the data pump device. */ + do + { + + status = ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump); + tx_thread_relinquish(); + } while (status != UX_SUCCESS); + + /* We still need to wait for the data pump status to be live. */ + while (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + { + + tx_thread_relinquish(); + } + + /* At this point, the data pump class has been found. Now get the interface + using invalid interface index. */ + status = _ux_host_stack_configuration_interface_get(dpump -> ux_host_class_dpump_device -> ux_device_first_configuration, 3, 0, &test_interface); + if (status != UX_INTERFACE_HANDLE_UNKNOWN) + { + + /* ux_host_stack_device_get test error. */ + error_counter++; + } + + /* Now get the interface using invalid alternate setting index. */ + status = _ux_host_stack_configuration_interface_get(dpump -> ux_host_class_dpump_device -> ux_device_first_configuration, 0, 1, &test_interface); + if (status != UX_INTERFACE_HANDLE_UNKNOWN) + { + + /* ux_host_stack_device_get test error. */ + error_counter++; + } + + /* Now get the interface using invalid alternate setting index. */ + status = _ux_host_stack_configuration_interface_get(dpump -> ux_host_class_dpump_device -> ux_device_first_configuration, 1, 2, &test_interface); + if (status != UX_INTERFACE_HANDLE_UNKNOWN) + { + + /* ux_host_stack_device_get test error. */ + error_counter++; + } + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #10\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static VOID ux_test_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID ux_test_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_host_stack_configuration_set_test.c b/test/regression/usbx_ux_host_stack_configuration_set_test.c new file mode 100644 index 00000000..16a3879c --- /dev/null +++ b/test/regression/usbx_ux_host_stack_configuration_set_test.c @@ -0,0 +1,532 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_stack.h" + +#include "ux_test_hcd_sim_host.h" +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_utility_sim.h" + +/* Define USBX demo constants. */ + +#define UX_DEMO_STACK_SIZE 4096 +#define UX_DEMO_BUFFER_SIZE 2048 +#define UX_DEMO_RUN 1 +#define UX_DEMO_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the demo application... */ + +static ULONG test_error_cases = UX_FALSE; +static ULONG test_error_counter = 0; + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +/* Define USBX demo global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x08, /* bMaxPacketSize0 */ + 0xec, 0x08, 0x10, 0x00, /* idVendor, idProduct */ + 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x01, /* bNumConfigurations */ + + /* Configuration descriptor */ + 0x09, 0x02, + 0x20 + 5, 0x00, /* wTotalLength */ + 0x01, 0x01, /* bNumInterfaces, bConfigurationValue */ + 0x00, + 0xc0, 0x32, /* bmAttributes, bMaxPower */ + + /* OTG Descriptor. */ + 0x05, 0x09, 0x03, 0x02, 0x00, + + /* Interface descriptor */ + 0x09, 0x04, + 0x00, 0x00, 0x02, /* bInterfaceNumber, bAlternateSetting, bNumEndpoints */ + 0x99, 0x99, 0x99, /* bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00 +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 */ + 0x0a, 0x07, /* idVendor */ + 0x25, 0x40, /* idProduct */ + 0x01, 0x00, + 0x01, 0x02, 0x03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 */ + 0x01, /* bNumConfigurations */ + 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20 + 5, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* OTG Descriptor. */ + 0x05, 0x09, 0x03, 0x02, 0x00, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00 +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID tx_test_instance_activate(VOID *dpump_instance); +static VOID tx_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static void tx_test_thread_host_simulation_entry(ULONG); +static void tx_test_thread_slave_simulation_entry(ULONG); + +static VOID ux_test_hcd_entry_invoked(UX_TEST_ACTION *action, VOID *params); + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +/* Simulation */ + +static UX_TEST_SETUP _b_hnp_support = {0x00,0x03,UX_OTG_FEATURE_A_HNP_SUPPORT,0x0000}; + +static UX_TEST_HCD_SIM_ACTION b_hnp_support_request_err[] = { +/* 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, &_b_hnp_support, + UX_FALSE, 0, + UX_TEST_SETUP_MATCH_REQ_V, 0, UX_NULL, 0, UX_ERROR, + UX_ERROR, ux_test_hcd_entry_invoked}, +{ UX_HCD_TRANSFER_REQUEST, &_b_hnp_support, + UX_FALSE, 0, + UX_TEST_SETUP_MATCH_REQ_V, 0, UX_NULL, 0, UX_ERROR, + UX_ERROR, ux_test_hcd_entry_invoked}, +{ UX_HCD_TRANSFER_REQUEST, &_b_hnp_support, + UX_FALSE, 0, + UX_TEST_SETUP_MATCH_REQ_V, 0, UX_NULL, 0, UX_ERROR, + UX_ERROR, ux_test_hcd_entry_invoked}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION b_hnp_support_request_ok[] = { +/* 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, &_b_hnp_support, + UX_FALSE, 0, + UX_TEST_SETUP_MATCH_REQ_V, 0, UX_NULL, 0, UX_SUCCESS, + UX_SUCCESS, ux_test_hcd_entry_invoked}, +{ 0 } +}; + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + test_error_counter ++; + + /* Failed test. */ + if (!test_error_cases) + { + + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + 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_stack_configuration_set_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; + + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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("Running ux_host_stack_configuration_set Test........................ ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_set Test........................ ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, _ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_set Test........................ ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_set Test........................ ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = tx_test_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = tx_test_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_set Test........................ ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_set Test........................ ERROR #7\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_set Test........................ ERROR #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx demo host simulation", tx_test_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("Running ux_host_stack_configuration_set Test........................ ERROR #8\n"); + test_control_return(1); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx demo slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_host_stack_configuration_set Test........................ ERROR #9\n"); + test_control_return(1); + } +} + + +static void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_HCD *hcd; + + /* Inform user. */ + printf("Running ux_host_stack_configuration_set Test........................ "); + + /* Wait for enumeration. */ + ux_test_wait_for_enum_thread_completion(); + + /* Disconnect. */ + ux_test_hcd_sim_host_disconnect(); + + /* Wait for disconnect. */ + ux_test_wait_for_enum_thread_completion(); + + /* Simulate OTG HNP Support on HCD. */ + hcd = &_ux_system_host -> ux_system_host_hcd_array[0]; +#ifdef UX_OTG_SUPPORT + hcd -> ux_hcd_otg_capabilities = UX_HCD_OTG_CAPABLE; +#endif + test_error_counter = 0; + ux_test_hcd_sim_host_set_actions(b_hnp_support_request_err); + + /* Connect, with OTG descriptor. */ + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Check device connection. */ + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: fail to get device instance\n", __LINE__); + test_control_return(1); + } + + /* Get configuration. */ + status = ux_host_stack_device_configuration_get(device, 0, &configuration); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: fail to get device configuration\n", __LINE__); + test_control_return(1); + } + +#ifdef UX_OTG_SUPPORT + if (test_error_counter == 0) + { + + printf("ERROR #%d: Expect a_hnp_support request\n", __LINE__); + error_counter ++; + } + if (configuration->ux_configuration_otg_capabilities) + { + + printf("ERROR #%d: Expect no OTG since a_hnp_support request fail\n", __LINE__); + error_counter ++; + } + + /* SetConfiguration but device connected to hub. */ + configuration->ux_configuration_otg_capabilities |= UX_OTG_HNP_SUPPORT; + configuration->ux_configuration_device->ux_device_parent = device; + status = _ux_host_stack_configuration_set(configuration); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: fail to set configuration (no SNP request)\n", __LINE__); + error_counter ++; + } + configuration->ux_configuration_device->ux_device_parent = UX_NULL; + + /* Simulate OTG HNP Support on HCD. */ + UX_DEVICE_HCD_GET(configuration->ux_configuration_device)->ux_hcd_otg_capabilities |= UX_HCD_OTG_CAPABLE; + + test_error_counter = 0; + ux_test_hcd_sim_host_set_actions(b_hnp_support_request_ok); + + status = _ux_host_stack_configuration_set(configuration); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: fail to set configuration (no SNP request)\n", __LINE__); + error_counter ++; + } + if (test_error_counter == 0) + { + + printf("ERROR #%d: Expect a_hnp_support request\n", __LINE__); + error_counter ++; + } + if (!configuration->ux_configuration_otg_capabilities) + { + + printf("ERROR #%d: Expect OTG since a_hnp_support request pass\n", __LINE__); + error_counter ++; + } +#endif + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* DPUMP error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + + +static void tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Ensure the dpump class on the device is still alive. */ + if (dpump_slave != UX_NULL) + { + + /* Increment thread counter. */ + thread_1_counter++; + } + + /* Let other thread run. */ + tx_thread_sleep(10); + } +} + +static VOID tx_test_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID tx_test_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + +static VOID ux_test_hcd_entry_invoked(UX_TEST_ACTION *action, VOID *params) +{ + + test_error_counter ++; +} \ No newline at end of file diff --git a/test/regression/usbx_ux_host_stack_device_address_set_test.c b/test/regression/usbx_ux_host_stack_device_address_set_test.c new file mode 100644 index 00000000..eb370946 --- /dev/null +++ b/test/regression/usbx_ux_host_stack_device_address_set_test.c @@ -0,0 +1,533 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_stack.h" + +#include "ux_test_hcd_sim_host.h" +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_utility_sim.h" + +/* Define USBX demo constants. */ + +#define UX_DEMO_STACK_SIZE 4096 +#define UX_DEMO_BUFFER_SIZE 2048 +#define UX_DEMO_RUN 1 +#define UX_DEMO_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the demo application... */ + +static ULONG test_error_cases = UX_FALSE; +static ULONG test_error_counter = 0; + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +/* Define USBX demo global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x08, /* bMaxPacketSize0 */ + 0xec, 0x08, 0x10, 0x00, /* idVendor, idProduct */ + 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x01, /* bNumConfigurations */ + + /* Configuration descriptor */ + 0x09, 0x02, + 0x20 + 5, 0x00, /* wTotalLength */ + 0x01, 0x01, /* bNumInterfaces, bConfigurationValue */ + 0x00, + 0xc0, 0x32, /* bmAttributes, bMaxPower */ + + /* OTG Descriptor. */ + 0x05, 0x09, 0x03, 0x02, 0x00, + + /* Interface descriptor */ + 0x09, 0x04, + 0x00, 0x00, 0x02, /* bInterfaceNumber, bAlternateSetting, bNumEndpoints */ + 0x99, 0x99, 0x99, /* bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00 +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 */ + 0x0a, 0x07, /* idVendor */ + 0x25, 0x40, /* idProduct */ + 0x01, 0x00, + 0x01, 0x02, 0x03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 */ + 0x01, /* bNumConfigurations */ + 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20 + 5, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* OTG Descriptor. */ + 0x05, 0x09, 0x03, 0x02, 0x00, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00 +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID tx_test_instance_activate(VOID *dpump_instance); +static VOID tx_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static void tx_test_thread_host_simulation_entry(ULONG); +static void tx_test_thread_slave_simulation_entry(ULONG); + +static VOID ux_test_hcd_entry_invoked(UX_TEST_ACTION *action, VOID *params); + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +/* Simulation */ + +static UX_TEST_SETUP _SetAddress = UX_TEST_SETUP_SetAddress; + +static UX_TEST_HCD_SIM_ACTION set_address_request[] = { +/* 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, &_SetAddress, + UX_FALSE, 0, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, UX_SUCCESS, + UX_SUCCESS, ux_test_hcd_entry_invoked}, +{ UX_HCD_TRANSFER_REQUEST, &_SetAddress, + UX_FALSE, 0, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, UX_SUCCESS, + UX_SUCCESS, ux_test_hcd_entry_invoked}, +{ UX_HCD_TRANSFER_REQUEST, &_SetAddress, + UX_FALSE, 0, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, UX_SUCCESS, + UX_SUCCESS, ux_test_hcd_entry_invoked}, +{ 0 } +}; + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + test_error_counter ++; + + /* Failed test. */ + if (!test_error_cases) + { + + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + 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_stack_device_address_set_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; + + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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("Running ux_host_stack_device_address_set Test....................... ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_device_address_set Test....................... ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, _ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_device_address_set Test....................... ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_device_address_set Test....................... ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = tx_test_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = tx_test_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_device_address_set Test....................... ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_device_address_set Test....................... ERROR #7\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_device_address_set Test....................... ERROR #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx demo host simulation", tx_test_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("Running ux_host_stack_device_address_set Test....................... ERROR #8\n"); + test_control_return(1); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx demo slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_host_stack_device_address_set Test....................... ERROR #9\n"); + test_control_return(1); + } +} + + +static void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_HCD *hcd; +UX_DEVICE device_back; + + /* Inform user. */ + printf("Running ux_host_stack_device_address_set Test....................... "); + + /* Connect. */ + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Check device connection. */ + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: fail to get device instance\n", __LINE__); + test_control_return(1); + } + + /* Get configuration. */ + status = ux_host_stack_device_configuration_get(device, 0, &configuration); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: fail to get device configuration\n", __LINE__); + test_control_return(1); + } + +#if UX_MAX_DEVICES > 1 + /* Simulate address set error. */ + + /* Backup device instance. */ + ux_utility_memory_copy(&device_back, device, sizeof(UX_DEVICE)); + + /* Modify address usage map. */ + hcd = UX_DEVICE_HCD_GET(device); + ux_utility_memory_set(hcd->ux_hcd_address, 0xFF, 16); + + /* Set address, expect error since all device address used. */ + test_error_counter = 0; + ux_test_hcd_sim_host_set_actions(set_address_request); + status = _ux_host_stack_device_address_set(device); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: expect error\n", __LINE__); + error_counter ++; + } + if (test_error_counter) + { + + printf("ERROR #%d: expect no call of SetAddress\n", __LINE__); + error_counter ++; + } + + /* Set address, expect address 1. */ + ux_utility_memory_set(hcd->ux_hcd_address, 0x00, 16); + hcd->ux_hcd_address[0] = 1; + hcd->ux_hcd_address[1] = 1; + /* Set address, expect no error since all device address used. */ + test_error_counter = 0; + ux_test_hcd_sim_host_set_actions(set_address_request); + status = _ux_host_stack_device_address_set(device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: expect no error 0x%x\n", __LINE__, status); + error_counter ++; + } + if (test_error_counter != 1) + { + + printf("ERROR #%d: expect 1 call of SetAddress but not %ld\n", __LINE__, test_error_counter); + error_counter ++; + } + if (hcd->ux_hcd_address[0] != 0x03 || hcd->ux_hcd_address[1] != 0x01) + { + printf("ERROR #%d: expect address map 0x03 0x01 but not 0x%x 0x%x\n", __LINE__, hcd->ux_hcd_address[0], hcd->ux_hcd_address[1]); + error_counter ++; + } + + /* Set address, expect address 1. */ + ux_utility_memory_set(hcd->ux_hcd_address, 0x00, 16); + hcd->ux_hcd_address[0] = 0xFF; + hcd->ux_hcd_address[1] = 1; + /* Set address, expect no error since all device address used. */ + test_error_counter = 0; + ux_test_hcd_sim_host_set_actions(set_address_request); + status = _ux_host_stack_device_address_set(device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: expect no error 0x%x\n", __LINE__, status); + error_counter ++; + } + if (test_error_counter != 1) + { + + printf("ERROR #%d: expect 1 call of SetAddress but not %ld\n", __LINE__, test_error_counter); + error_counter ++; + } + if (hcd->ux_hcd_address[0] != 0xFF || hcd->ux_hcd_address[1] != 0x03) + { + printf("ERROR #%d: expect address map 0xFF 0x03 but not 0x%x 0x%x\n", __LINE__, hcd->ux_hcd_address[0], hcd->ux_hcd_address[1]); + error_counter ++; + } + +#endif + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* DPUMP error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + + +static void tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Ensure the dpump class on the device is still alive. */ + if (dpump_slave != UX_NULL) + { + + /* Increment thread counter. */ + thread_1_counter++; + } + + /* Let other thread run. */ + tx_thread_sleep(10); + } +} + +static VOID tx_test_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID tx_test_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + +static VOID ux_test_hcd_entry_invoked(UX_TEST_ACTION *action, VOID *params) +{ + + test_error_counter ++; +} \ No newline at end of file diff --git a/test/regression/usbx_ux_host_stack_device_configuration_activate_test.c b/test/regression/usbx_ux_host_stack_device_configuration_activate_test.c new file mode 100644 index 00000000..4fa48288 --- /dev/null +++ b/test/regression/usbx_ux_host_stack_device_configuration_activate_test.c @@ -0,0 +1,492 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include + +#include "tx_api.h" + +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_test.h" + + +/* Define USBX demo constants. */ + +#define UX_DEMO_STACK_SIZE 4096 +#define UX_DEMO_BUFFER_SIZE 2048 +#define UX_DEMO_RUN 1 +#define UX_DEMO_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the demo application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static int error_counter = 0; + + +/* Define USBX demo global variables. */ + +static unsigned char host_out_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; +static unsigned char host_in_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; +static unsigned char slave_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave; + +static UINT ignore_error = UX_FALSE; + +#define BYTE0(x) (((x) ) & 0xFF) +#define BYTE1(x) (((x) >> 8) & 0xFF) + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, + 0x02, /* bNumConfigurations */ + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, + 0x09, 0x00, /* wTotalLength */ + 0x00, /* bNumInterfaces */ + 0x02, /* bConfigurationValue */ + 0x00, 0xc0, 0x32, +}; + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, + 0x02, /* bNumConfigurations */ + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, + 0x09, 0x00, /* wTotalLength */ + 0x00, /* bNumInterfaces */ + 0x02, /* bConfigurationValue */ + 0x00, 0xc0, 0x32, +}; + +/* 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 sizeof(string_framework) +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* 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 + }; + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID tx_demo_instance_activate(VOID *dpump_instance); +static VOID tx_demo_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); + +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); +static void tx_demo_thread_slave_simulation_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (!ignore_error) + { + /* Failed test. */ + printf("Error #%d, system_level: %d, system_context: %d, code: %x(%d)\n", + __LINE__, system_level, system_context, error_code, error_code); + 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_stack_device_configuration_activate_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; + + + printf("Running ux_host_stack_device_configuration_(de)activate Test........ "); + stepinfo("\n"); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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 #%d:0x%x\n", __LINE__, status); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + printf("ERROR #%d:0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + printf("ERROR #%d:0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + printf("ERROR #%d:0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = tx_demo_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = tx_demo_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + printf("ERROR #%d:0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + printf("ERROR #%d:0x%x\n", __LINE__, status); + 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 #%d:0x%x\n", __LINE__, status); + 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 #%d:0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + printf("ERROR #%d:0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static UINT tx_demo_dpump_get(void) +{ +UINT status; +UX_HOST_CLASS *class_inst; + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class_inst); + if (status != UX_SUCCESS) + return(UX_ERROR); + status = ux_host_stack_class_instance_get(class_inst, 0, (VOID **) &dpump); + if (status != UX_SUCCESS) + return(UX_ERROR); + if (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + return(UX_ERROR); + return(UX_SUCCESS); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +INT i; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +ULONG temp; + + /* Wait until dpump is ready. */ + for (i = 0; i < 100; i ++) + { + if (tx_demo_dpump_get() == UX_SUCCESS && dpump_slave != UX_NULL) + break; + tx_thread_sleep(UX_MS_TO_TICK_NON_ZERO(10)); + } + if (dpump == UX_NULL || dpump_slave == UX_NULL) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + device = dpump -> ux_host_class_dpump_device; + configuration = device -> ux_device_first_configuration; + + /* >>>>> Test configuration deactivate. */ + + ignore_error = UX_TRUE; + + /* >>>>> ux_host_stack_device_configuration_deactivate: invalid device. */ + temp = device -> ux_device_handle; + device -> ux_device_handle = 0; + status = ux_host_stack_device_configuration_deactivate(device); + if (status != UX_DEVICE_HANDLE_UNKNOWN) + { + printf("ERROR #%d:0x%x\n", __LINE__, status); + test_control_return(1); + } + device -> ux_device_handle = temp; + + /* >>>>> ux_host_stack_device_configuration_deactivate: invalid device semaphore. */ + _ux_utility_semaphore_delete(&device -> ux_device_protection_semaphore); + status = ux_host_stack_device_configuration_deactivate(device); + if (status != UX_SEMAPHORE_ERROR) + { + printf("ERROR #%d:0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_utility_semaphore_create(&device -> ux_device_protection_semaphore, "ux_device_protection_semaphore", 1); + + ignore_error = UX_FALSE; + + /* >>>>> ux_host_stack_device_configuration_deactivate: OK. */ + status = ux_host_stack_device_configuration_deactivate(device); + if (status != UX_SUCCESS) + { + printf("ERROR #%d:0x%x\n", __LINE__, status); + test_control_return(1); + } + UX_TEST_ASSERT(dpump_slave == UX_NULL); + + /* >>>>> ux_host_stack_device_configuration_deactivate: Already done, OK. */ + status = ux_host_stack_device_configuration_deactivate(device); + if (status != UX_SUCCESS) + { + printf("ERROR #%d:0x%x\n", __LINE__, status); + test_control_return(1); + } + + ignore_error = UX_TRUE; + + /* >>>>> ux_host_stack_device_configuration_activate: invalid configuration handle. */ + temp = configuration -> ux_configuration_handle; + configuration -> ux_configuration_handle = 0; + status = ux_host_stack_device_configuration_activate(configuration); + if (status != UX_CONFIGURATION_HANDLE_UNKNOWN) + { + printf("ERROR #%d:0x%x\n", __LINE__, status); + test_control_return(1); + } + configuration -> ux_configuration_handle = temp; + + /* >>>>> ux_host_stack_device_configuration_activate: invalid device semaphore. */ + _ux_utility_semaphore_delete(&device -> ux_device_protection_semaphore); + status = ux_host_stack_device_configuration_activate(configuration); + if (status != UX_SEMAPHORE_ERROR) + { + printf("ERROR #%d:0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_utility_semaphore_create(&device -> ux_device_protection_semaphore, "ux_device_protection_semaphore", 1); + + ignore_error = UX_FALSE; + + /* >>>>> ux_host_stack_device_configuration_activate: OK. */ + status = ux_host_stack_device_configuration_activate(configuration); + if (status != UX_SUCCESS) + { + printf("ERROR #%d:0x%x\n", __LINE__, status); + test_control_return(1); + } + UX_TEST_ASSERT(dpump_slave != UX_NULL); + + /* >>>>> ux_host_stack_device_configuration_activate: Already done, OK. */ + status = ux_host_stack_device_configuration_activate(configuration); + if (status != UX_SUCCESS) + { + printf("ERROR #%d:0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* >>>>> ux_host_stack_device_configuration_activate: Activate another, FAIL. */ + status = ux_host_stack_device_configuration_activate(configuration -> ux_configuration_next_configuration); + if (status != UX_ALREADY_ACTIVATED) + { + printf("ERROR #%d:0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* DPUMP error. */ + printf("ERROR %d\n", error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + + +static void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ +} + +static VOID tx_demo_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID tx_demo_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + 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 new file mode 100644 index 00000000..0d10702a --- /dev/null +++ b/test/regression/usbx_ux_host_stack_device_configuration_get_test.c @@ -0,0 +1,375 @@ +/* This test is designed to test the ux_host_stack_device_configuration_get. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + + +/* Define USBX test global variables. */ + +static unsigned char host_out_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; +static unsigned char host_in_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; +static unsigned char slave_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave; + + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00 + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00 + }; + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* 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 + }; + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_host_simulation; +static TX_THREAD ux_test_thread_slave_simulation; +static void ux_test_thread_host_simulation_entry(ULONG); +static void ux_test_thread_slave_simulation_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (error_code != UX_CONFIGURATION_HANDLE_UNKNOWN) + { + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + 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_stack_device_configuration_get_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; + + + /* Inform user. */ + printf("Running ux_host_stack_device_configuration_get Test................. "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = ux_test_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = ux_test_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #7\n"); + 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 #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_host_simulation, "test host simulation", ux_test_thread_host_simulation_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #8\n"); + test_control_return(1); + } +} + + +static void ux_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_CONFIGURATION *test_configuration; + + /* Find the main data pump container. */ + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + /* DPUMP basic test error. */ + printf("ERROR #10\n"); + test_control_return(1); + } + + /* We get the first instance of the data pump device. */ + do + { + + status = ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump); + tx_thread_relinquish(); + } while (status != UX_SUCCESS); + + /* We still need to wait for the data pump status to be live. */ + while (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + { + + tx_thread_relinquish(); + } + + /* At this point, the data pump class has been found. Now call _ux_host_stack_device_configuration_get + with invalid configuration index. */ + + status = _ux_host_stack_device_configuration_get(dpump->ux_host_class_dpump_device, 1, &test_configuration); + if (status != UX_CONFIGURATION_HANDLE_UNKNOWN) + { + + /* ux_host_stack_device_get test error. */ + error_counter++; + } + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static VOID ux_test_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID ux_test_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_host_stack_device_configuration_reset_coverage_test.c b/test/regression/usbx_ux_host_stack_device_configuration_reset_coverage_test.c new file mode 100644 index 00000000..bf9fcf8b --- /dev/null +++ b/test/regression/usbx_ux_host_stack_device_configuration_reset_coverage_test.c @@ -0,0 +1,61 @@ +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" +#include "ux_test.h" +#include "ux_host_class_storage.h" +#include "ux_test_utility_sim.h" + +static UX_DEVICE device; +static UCHAR memory_buffer[4096]; +static UX_ENDPOINT endpoint; +static UX_DEVICE endpoint_device; +static UX_HCD hcd; + +static UINT entry_function(struct UX_HCD_STRUCT *parm1, UINT parm2, VOID *parm3) +{ + + return(UX_SUCCESS); + +} + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_class_stack_device_configuration_reset_coverage_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status = 0; +UX_TRANSFER *transfer_request; + + /* Inform user. */ + printf("Running USB host stack device configuration Reset Coverage Test .... "); + + ux_system_initialize(memory_buffer, 4096, UX_NULL, 0); + + device.ux_device_state = UX_DEVICE_SELF_POWERED_STATE; + + device.ux_device_packed_configuration = (UCHAR*)_ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, 16); + + transfer_request = &device.ux_device_control_endpoint.ux_endpoint_transfer_request; + transfer_request->ux_transfer_request_endpoint = &endpoint; + endpoint.ux_endpoint_device = &endpoint_device; + endpoint_device.ux_device_state = UX_DEVICE_CONFIGURED; + endpoint.ux_endpoint_descriptor.bEndpointAddress = 0x7; +#if UX_MAX_HCD > 1 + endpoint_device.ux_device_hcd = &hcd; +#else + _ux_system_host->ux_system_host_hcd_array = &hcd; +#endif + hcd.ux_hcd_entry_function = entry_function; + + _ux_host_stack_device_configuration_reset(&device); + + printf("SUCCESS!\n"); + + test_control_return(0); + return; +} diff --git a/test/regression/usbx_ux_host_stack_device_configuration_reset_select_test.c b/test/regression/usbx_ux_host_stack_device_configuration_reset_select_test.c new file mode 100644 index 00000000..7f7eac0e --- /dev/null +++ b/test/regression/usbx_ux_host_stack_device_configuration_reset_select_test.c @@ -0,0 +1,483 @@ +/* This test is designed to test the ux_host_stack_device_configuration_reset/select. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + + +/* Define USBX test global variables. */ + +static unsigned char host_out_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; +static unsigned char host_in_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; +static unsigned char slave_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave; + + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 114 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x02, 0x00, 0x80, + 0xFA, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x03, 0x00, 0xC0, + 0xFA, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, + +}; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00 + }; + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* 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 + }; + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_host_simulation; +static TX_THREAD ux_test_thread_slave_simulation; +static void ux_test_thread_host_simulation_entry(ULONG); +static void ux_test_thread_slave_simulation_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if ((error_code != UX_CONFIGURATION_HANDLE_UNKNOWN) && + (error_code != UX_OVER_CURRENT_CONDITION)) + { + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + 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_stack_device_configuration_reset_select_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; + + + /* Inform user. */ + printf("Running ux_host_stack_device_configuration_reset/select Test........ "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = ux_test_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = ux_test_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #7\n"); + 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 #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_host_simulation, "test host simulation", ux_test_thread_host_simulation_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #8\n"); + test_control_return(1); + } +} + + +static void ux_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +static UX_CONFIGURATION test_configuration; +UX_CONFIGURATION *configuration1; +UX_CONFIGURATION *configuration2; +UX_CONFIGURATION *configuration3; +UX_DEVICE *device; + + + /* Find the main data pump container. */ + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + /* DPUMP basic test error. */ + printf("ERROR #10\n"); + test_control_return(1); + } + + /* We get the first instance of the data pump device. */ + do + { + + status = ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump); + tx_thread_relinquish(); + } while (status != UX_SUCCESS); + + /* We still need to wait for the data pump status to be live. */ + while (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + { + + tx_thread_relinquish(); + } + + /* At this point, the data pump class has been found. Now call _ux_host_stack_device_configuration_select + with invalid configuration. */ + status = ux_host_stack_device_configuration_select(&test_configuration); + if (status != UX_CONFIGURATION_HANDLE_UNKNOWN) + { + + /* ux_host_stack_device_get test error. */ + error_counter++; + } + + device = dpump -> ux_host_class_dpump_device; + configuration1 = dpump -> ux_host_class_dpump_interface -> ux_interface_configuration; + configuration2 = configuration1 -> ux_configuration_next_configuration; + configuration3 = configuration2 -> ux_configuration_next_configuration; + + /* Select configuration 2. */ + status = ux_host_stack_device_configuration_select(configuration2); + if (status != UX_SUCCESS) + { + + /* Test error. */ + error_counter++; + } + + /* Select configuration 1. */ + status = ux_host_stack_device_configuration_select(configuration1); + if (status != UX_SUCCESS) + { + + /* Test error. */ + error_counter++; + } +#if UX_MAX_DEVICES > 1 + /* Set max power to test over current condition. */ + device -> ux_device_max_power = 50; + + /* Select configuration 2 again. */ + status = ux_host_stack_device_configuration_select(configuration2); + if (status != UX_OVER_CURRENT_CONDITION) + { + + /* Test error. */ + error_counter++; + } + + /* Select configuration 3. */ + status = ux_host_stack_device_configuration_select(configuration3); + if (status != UX_SUCCESS) + { + + /* Test error. */ + error_counter++; + } + + /* Set max power back. */ + device -> ux_device_max_power = 250; + + /* Select configuration 2 for configuration_reset test. */ + status = ux_host_stack_device_configuration_select(configuration2); + if (status != UX_SUCCESS) + { + + /* Test error. */ + error_counter++; + } +#endif + /* Reset configuration. */ + status = ux_host_stack_device_configuration_reset(device); + if (status != UX_SUCCESS) + { +printf("%s:%d\n", __FILE__, __LINE__); + /* Test error. */ + error_counter++; + } + + /* Reset configuration again. */ + status = ux_host_stack_device_configuration_reset(device); + if (status != UX_SUCCESS) + { +printf("%s:%d\n", __FILE__, __LINE__); + /* Test error. */ + error_counter++; + } + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static VOID ux_test_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID ux_test_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_host_stack_device_descriptor_read_test.c b/test/regression/usbx_ux_host_stack_device_descriptor_read_test.c new file mode 100644 index 00000000..3f305596 --- /dev/null +++ b/test/regression/usbx_ux_host_stack_device_descriptor_read_test.c @@ -0,0 +1,486 @@ +/* This test is designed to test the ux_host_stack_device_descriptor_read. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +/* HID mouse related descriptors */ + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +#define LSB(x) (x & 0x00ff) +#define MSB(x) ((x & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors 9+7+7+7=30 bytes. */ +#define DPUMP_IFC_DESC_ALL(ifc, bulk_in_epa, bulk_out_epa, int_in_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x03, 0x99, 0x99, 0x99, 0x00,\ + /* Endpoint descriptor (Bulk Out) */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Bulk In) */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Interrupt In) */\ + 0x07, 0x05, (int_in_epa), 0x02, 0x40, 0x00, 0x00, +#define DPUMP_IFC_DESC_ALL_LEN 30 + +/* HID Mouse interface descriptors 9+9+7=25 bytes */ +#define HID_MOUSE_IFC_DESC_ALL(ifc, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x01, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_MOUSE_IFC_DESC_ALL_LEN 25 + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+7+7+7 =30 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02, 0x83) + /* HID 9+9+7 =25 */ + HID_MOUSE_IFC_DESC_ALL(1, 0x84) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+7+7+7 =30 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02, 0x83) + /* HID 9+9+7 =25 */ + HID_MOUSE_IFC_DESC_ALL(1, 0x84) +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Simulation actions. */ + +static UX_TEST_SETUP _GetDeviceDescriptor = UX_TEST_SETUP_GetDevDescr; + +static UX_TEST_HCD_SIM_ACTION get_dev_desc_len_error[] = { +/* 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, &_GetDeviceDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 0, 7, 0, + UX_SUCCESS, UX_NULL}, +{ UX_HCD_TRANSFER_REQUEST, &_GetDeviceDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 0, 8, 0, + UX_SUCCESS, UX_NULL}, +{ UX_HCD_TRANSFER_REQUEST, &_GetDeviceDescriptor, + UX_FALSE, 0, + UX_TEST_SIM_REQ_ANSWER | UX_TEST_SETUP_MATCH_REQ_V, 0, device_framework_full_speed + 0, UX_DEVICE_DESCRIPTOR_LENGTH - 1, 0, + UX_SUCCESS, UX_NULL}, +{ 0 } +}; + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +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 >= 2) + return error_callback_counter; + + return UX_SUCCESS; +} + +static UINT test_ux_device_class_hid_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + switch(command->ux_slave_class_command_request) + { + case UX_SLAVE_CLASS_COMMAND_INITIALIZE: + case UX_SLAVE_CLASS_COMMAND_QUERY: + return UX_SUCCESS; + + default: + return UX_NO_CLASS_MATCH; + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_stack_device_descriptor_read_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; +UX_SLAVE_CLASS_HID_PARAMETER hid_parameter; + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_device_descriptor_read Test................... ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_device_descriptor_read Test................... ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_device_descriptor_read Test................... ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_device_descriptor_read Test................... ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = ux_test_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = ux_test_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Initialize the hid class parameters. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_REPORT_LENGTH; + hid_parameter.ux_device_class_hid_parameter_callback = UX_NULL; + hid_parameter.ux_slave_class_hid_instance_activate = UX_NULL; + + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, test_ux_device_class_hid_entry, + 1, 1, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_device_descriptor_read Test................... ERROR #6\n"); + test_control_return(1); + } +#endif + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_device_descriptor_read Test................... ERROR #7\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_device_descriptor_read Test................... ERROR #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test host simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_host_stack_device_descriptor_read Test................... ERROR #8\n"); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + + /* Inform user. */ + printf("Running ux_host_stack_device_descriptor_read Test................... "); + + /* Simulate GetConfiguration length error. */ + ux_test_hcd_sim_host_set_actions(get_dev_desc_len_error); + + /* No break if error callback is called. */ + error_callback_ignore = UX_TRUE; + error_callback_counter = 0; + + /* Connect. */ + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + ux_test_breakable_sleep(100, sleep_break_on_error); + + /* Enumeration check, may fail if no retry and success on more than one retry. */ + /* There is error reported. */ + if (error_callback_counter == 0) + { + + printf("ERROR #%d: Expect error\n", __LINE__); + error_counter ++; + } + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static VOID ux_test_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID ux_test_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_host_stack_device_get_test.c b/test/regression/usbx_ux_host_stack_device_get_test.c new file mode 100644 index 00000000..8ef100b5 --- /dev/null +++ b/test/regression/usbx_ux_host_stack_device_get_test.c @@ -0,0 +1,401 @@ +/* This test is designed to test the ux_host_stack_device_get. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + + +/* Define USBX test global variables. */ + +static unsigned char host_out_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; +static unsigned char host_in_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; +static unsigned char slave_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave; + + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00 + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00 + }; + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* 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 + }; + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_host_simulation; +static TX_THREAD ux_test_thread_slave_simulation; +static void ux_test_thread_host_simulation_entry(ULONG); +static void ux_test_thread_slave_simulation_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (error_code != UX_DEVICE_HANDLE_UNKNOWN) + { + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + 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_stack_device_get_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; + + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_device_get Test............................... ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_device_get Test............................... ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_device_get Test............................... ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_device_get Test............................... ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = ux_test_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = ux_test_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_device_get Test............................... ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_device_get Test............................... ERROR #7\n"); + 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("Running ux_host_stack_device_get Test............................... ERROR #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_host_simulation, "test host simulation", ux_test_thread_host_simulation_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_host_stack_device_get Test............................... ERROR #8\n"); + test_control_return(1); + } +} + + +static void ux_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_DEVICE *test_device; + + /* Inform user. */ + printf("Running ux_host_stack_device_get Test............................... "); + + /* Find the main data pump container. */ + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + /* DPUMP basic test error. */ + printf("ERROR #10\n"); + test_control_return(1); + } + + /* We get the first instance of the data pump device. */ + do + { + + status = ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump); + tx_thread_relinquish(); + } while (status != UX_SUCCESS); + + /* We still need to wait for the data pump status to be live. */ + while (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + { + + tx_thread_relinquish(); + } + + /* At this point, the data pump class has been found. Now get the first + device using ux_host_stack_device_get. */ + status = ux_host_stack_device_get(0, &test_device); + if (status != UX_SUCCESS) + { + + /* ux_host_stack_device_get test error. */ + error_counter++; + } + + /* Check if we get correct device. */ + if (test_device != dpump -> ux_host_class_dpump_device) + { + + /* ux_host_stack_device_get test error. */ + error_counter++; + } + + /* Call ux_host_stack_device_get with device index 1. */ + status = ux_host_stack_device_get(1, &test_device); + if (status != UX_DEVICE_HANDLE_UNKNOWN) + { + + /* ux_host_stack_device_get test error. */ + error_counter++; + } + + /* Call ux_host_stack_device_get with device index exceeding maximum. */ + status = ux_host_stack_device_get(100, &test_device); + if (status != UX_DEVICE_HANDLE_UNKNOWN) + { + + /* ux_host_stack_device_get test error. */ + error_counter++; + } + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static VOID ux_test_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID ux_test_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_host_stack_device_remove_test.c b/test/regression/usbx_ux_host_stack_device_remove_test.c new file mode 100644 index 00000000..a3f67744 --- /dev/null +++ b/test/regression/usbx_ux_host_stack_device_remove_test.c @@ -0,0 +1,547 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_stack.h" + +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +/* Define USBX demo constants. */ + +#define UX_DEMO_STACK_SIZE 4096 +#define UX_DEMO_BUFFER_SIZE 2048 +#define UX_DEMO_RUN 1 +#define UX_DEMO_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the demo application... */ + +static ULONG test_error_cases = UX_FALSE; + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +/* Define USBX demo global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave; + +static UCHAR test_sim_entry; +static ULONG test_sim_query_usage; +static ULONG test_sim_query_count; +static ULONG test_sim_activate_count; +static ULONG test_sim_deactivate_count; + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x08, /* bMaxPacketSize0 */ + 0xec, 0x08, 0x10, 0x00, /* idVendor, idProduct */ + 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x01, /* bNumConfigurations */ + + /* Configuration descriptor */ + 0x09, 0x02, + 0x20, 0x00, /* wTotalLength */ + 0x01, 0x01, /* bNumInterfaces, bConfigurationValue */ + 0x00, + 0xc0, 0x32, /* bmAttributes, bMaxPower */ + + /* Interface descriptor */ + 0x09, 0x04, + 0x00, 0x00, 0x02, /* bInterfaceNumber, bAlternateSetting, bNumEndpoints */ + 0x99, 0x99, 0x99, /* bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00 +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 */ + 0x0a, 0x07, /* idVendor */ + 0x25, 0x40, /* idProduct */ + 0x01, 0x00, + 0x01, 0x02, 0x03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 */ + 0x01, /* bNumConfigurations */ + 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00 +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID tx_demo_instance_activate(VOID *dpump_instance); +static VOID tx_demo_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); +static void tx_demo_thread_slave_simulation_entry(ULONG); + +static UINT test_ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command) +{ + +UX_DEVICE *device; + + if (test_sim_entry) + { + + switch (command -> ux_host_class_command_request) + { + case UX_HOST_CLASS_COMMAND_QUERY: + test_sim_query_count ++; + if (command -> ux_host_class_command_usage != test_sim_query_usage) + return UX_NO_CLASS_MATCH; + break; + + case UX_HOST_CLASS_COMMAND_ACTIVATE: + device = (UX_DEVICE *) command -> ux_host_class_command_container; + device -> ux_device_class_instance = (VOID *)&device; + test_sim_activate_count ++; + break; + + case UX_HOST_CLASS_COMMAND_DEACTIVATE: + test_sim_deactivate_count ++; + break; + + default: + break; + } + return UX_SUCCESS; + } + return ux_host_class_dpump_entry(command); +} + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + if (!test_error_cases) + { + + printf("Error on line %d, system_level: %d, system_context: %d, error code: 0x%x\n", __LINE__, system_level, system_context, error_code); + 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_stack_device_remove_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; + + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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("Running ux_host_stack_device_remove Test............................ ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_device_remove Test............................ ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, test_ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_device_remove Test............................ ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_device_remove Test............................ ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = tx_demo_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = tx_demo_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_device_remove Test............................ ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_device_remove Test............................ ERROR #7\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_device_remove Test............................ ERROR #4\n"); + 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("Running ux_host_stack_device_remove Test............................ ERROR #8\n"); + test_control_return(1); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_host_stack_device_remove Test............................ ERROR #9\n"); + test_control_return(1); + } +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG tmp; +UX_HCD *hcd; +UX_DEVICE *device; +UX_DEVICE device_backup; + + /* Inform user. */ + printf("Running ux_host_stack_device_remove Test............................ "); + + /* Simulate query good on device connect - associate class with device. */ + test_sim_entry = UX_TRUE; + test_sim_query_usage = UX_HOST_CLASS_COMMAND_USAGE_PIDVID; + test_sim_query_count = 0; + test_sim_activate_count = 0; + test_sim_deactivate_count = 0; + + /* Connect. */ + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + tx_thread_sleep(100); + + /* Check device connection. */ + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: fail to get device instance\n", __LINE__); + test_control_return(1); + } + if (test_sim_query_count == 0) + { + + printf("ERROR #%d: class query not happen\n", __LINE__); + error_counter ++; + } + if (test_sim_activate_count == 0) + { + + printf("ERROR #%d: class activate not happen\n", __LINE__); + error_counter ++; + } + if (test_sim_deactivate_count != 0) + { + + printf("ERROR #%d: class deactivate not expected\n", __LINE__); + error_counter ++; + } + + /* Get HCD instance. */ + hcd = UX_DEVICE_HCD_GET(device); + + /* Disconnect so device associated class call deactivate. */ + ux_test_hcd_sim_host_disconnect(); + if (test_sim_deactivate_count == 0) + { + + printf("ERROR #%d: class deactivate not happen\n", __LINE__); + error_counter ++; + } + +#if UX_MAX_DEVICES > 1 + /* Simulate 3 invalid devices in ux_system_host_device_array. */ + + /* Handle OK, parent error. */ + _ux_system_host -> ux_system_host_device_array[0].ux_device_handle = (ULONG)(ALIGN_TYPE)device; + _ux_system_host -> ux_system_host_device_array[0].ux_device_parent = &device_backup; + + /* Handle OK, parent OK, port location error. */ + _ux_system_host -> ux_system_host_device_array[1].ux_device_handle = (ULONG)(ALIGN_TYPE)device; + _ux_system_host -> ux_system_host_device_array[1].ux_device_parent = UX_NULL; + _ux_system_host -> ux_system_host_device_array[1].ux_device_port_location = 3; + + /* Handle OK, parent OK, port location OK, hcd error. */ + _ux_system_host -> ux_system_host_device_array[2].ux_device_handle = (ULONG)(ALIGN_TYPE)device; + _ux_system_host -> ux_system_host_device_array[2].ux_device_parent = UX_NULL; + _ux_system_host -> ux_system_host_device_array[2].ux_device_port_location = 0; +#if UX_MAX_HCD > 1 + _ux_system_host -> ux_system_host_device_array[2].ux_device_hcd = UX_NULL; +#endif + /* Connect. */ + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + tx_thread_sleep(100); + if (_ux_system_host -> ux_system_host_device_array[3].ux_device_handle == 0) + { + + printf("ERROR #%d: device[3] must be used\n", __LINE__); + error_counter ++; + } + + test_error_cases = UX_TRUE; + + /* backup and invalidate device[3] */ + tmp = _ux_system_host -> ux_system_host_device_array[3].ux_device_handle; + _ux_system_host -> ux_system_host_device_array[3].ux_device_handle = 0; + + /* Disconnect. */ + ux_test_hcd_sim_host_disconnect(); + if (_ux_system_host -> ux_system_host_device_array[0].ux_device_handle == 0) + { + + printf("ERROR #%d: device[0] must not be removed\n", __LINE__); + error_counter ++; + } + if (_ux_system_host -> ux_system_host_device_array[1].ux_device_handle == 0) + { + + printf("ERROR #%d: device[1] must not be removed\n", __LINE__); + error_counter ++; + } + if (_ux_system_host -> ux_system_host_device_array[2].ux_device_handle == 0) + { + + printf("ERROR #%d: device[2] must not be removed\n", __LINE__); + error_counter ++; + } + _ux_system_host -> ux_system_host_device_array[3].ux_device_handle = tmp; +#endif + + test_error_cases = UX_FALSE; + + /* Connect. */ + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + tx_thread_sleep(100); + + /* Disconnect. */ + ux_test_hcd_sim_host_disconnect(); + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* DPUMP error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + + +static void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Ensure the dpump class on the device is still alive. */ + if (dpump_slave != UX_NULL) + { + + /* Increment thread counter. */ + thread_1_counter++; + } + + /* Let other thread run. */ + tx_thread_sleep(10); + } +} + +static VOID tx_demo_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID tx_demo_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_host_stack_device_string_get_test.c b/test/regression/usbx_ux_host_stack_device_string_get_test.c new file mode 100644 index 00000000..99b9a8e9 --- /dev/null +++ b/test/regression/usbx_ux_host_stack_device_string_get_test.c @@ -0,0 +1,484 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" +#include "ux_test.h" + + +/* Define USBX demo constants. */ + +#define UX_DEMO_STACK_SIZE 4096 +#define UX_DEMO_BUFFER_SIZE 2048 +#define UX_DEMO_RUN 1 +#define UX_DEMO_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the demo application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + + +/* Define USBX demo global variables. */ + +static unsigned char host_out_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; +static unsigned char host_in_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; +static unsigned char slave_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave; + +static UINT ignore_errors; + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00 +}; + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00 +}; + +/* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +#define STRING_FRAMEWORK_LENGTH 38 +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* 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 +}; + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID tx_demo_instance_activate(VOID *dpump_instance); +static VOID tx_demo_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_test_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); +static void tx_demo_thread_test_simulation_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (!ignore_errors) + { + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: 0x%x(%d)\n", + __LINE__, system_level, system_context, error_code, error_code); + 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_stack_device_string_get_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; + + printf("Running ux_host_stack_device_string_get Test........................ "); + stepinfo("\n"); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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 #%d:0x%x\n", __LINE__, status); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d:0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d:0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d:0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = tx_demo_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = tx_demo_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d:0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d:0x%x\n", __LINE__, status); + 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 #%d:0x%x\n", __LINE__, status); + 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 #%d:0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_test_simulation, "tx demo test simulation", tx_demo_thread_test_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_DONT_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d:0x%x\n", __LINE__, status); + test_control_return(1); + } +} + + +static UINT tx_demo_dpump_get(void) +{ +UINT status; +UX_HOST_CLASS *class_inst; + +#if defined(UX_HOST_STANDALONE) + ux_system_tasks_run(); +#endif + + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class_inst); + if (status != UX_SUCCESS) + return(UX_ERROR); + status = ux_host_stack_class_instance_get(class_inst, 0, (VOID **) &dpump); + if (status != UX_SUCCESS) + return(UX_ERROR); + if (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + return(UX_ERROR); + return(UX_SUCCESS); +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ +UINT status; +INT i; +UX_DEVICE *device; +ULONG temp; + + /* Wait a while before instances are ready. */ + for (i = 0; i < 1000;i ++) + { + if (tx_demo_dpump_get() == UX_SUCCESS && + dpump_slave != UX_NULL) + break; + tx_thread_sleep(1); + } + if (dpump == UX_NULL || dpump_slave == UX_NULL) + { + printf("ERROR #%d: Enumeration fail %p %p\n", __LINE__, dpump, dpump_slave); + test_control_return(1); + } + device = dpump -> ux_host_class_dpump_device; + + ignore_errors = UX_TRUE; + + /* >>>>> Test case, device instance error. */ + temp = device -> ux_device_handle; + device -> ux_device_handle = 0; + status = ux_host_stack_device_string_get(device, host_in_buffer, UX_HOST_CLASS_DPUMP_PACKET_SIZE, 0, 0); + if (status != UX_DEVICE_HANDLE_UNKNOWN) + { + printf("ERROR #%d:0x%x\n", __LINE__, status); + test_control_return(1); + } + device -> ux_device_handle = temp; + +#if !defined(UX_HOST_STANDALONE) + /* >>>>> Test case, semaphore get error. */ + _ux_utility_semaphore_delete(&device -> ux_device_protection_semaphore); + status = ux_host_stack_device_string_get(device, host_in_buffer, UX_HOST_CLASS_DPUMP_PACKET_SIZE, 0, 0); + if (status != UX_SEMAPHORE_ERROR) + { + printf("ERROR #%d:0x%x\n", __LINE__, status); + test_control_return(1); + } + _ux_utility_semaphore_create(&device -> ux_device_protection_semaphore, "ux_device_protection_semaphore", 1); +#endif + + ignore_errors = UX_FALSE; + + /* >>>>> Test case, semaphore get after a while. */ + /* Return a LANG ID. */ + tx_thread_resume(&tx_demo_thread_test_simulation); + status = ux_host_stack_device_string_get(device, host_in_buffer, UX_HOST_CLASS_DPUMP_PACKET_SIZE, 0, 0); + if (status != UX_SUCCESS) + { + printf("ERROR #%d:0x%x\n", __LINE__, status); + test_control_return(1); + } + UX_TEST_ASSERT(host_in_buffer[0] == 4); + UX_TEST_ASSERT(host_in_buffer[1] == UX_STRING_DESCRIPTOR_ITEM); + UX_TEST_ASSERT(host_in_buffer[2] == 0x09); + UX_TEST_ASSERT(host_in_buffer[3] == 0x04); + + /* >>>>> Test case, string get (0x30, 0x30, 0x30, 0x31). */ + status = ux_host_stack_device_string_get(device, host_in_buffer, UX_HOST_CLASS_DPUMP_PACKET_SIZE, 0x0409, 3); + if (status != UX_SUCCESS) + { + printf("ERROR #%d:0x%x\n", __LINE__, status); + test_control_return(1); + } + UX_TEST_ASSERT(host_in_buffer[0] >= 10); + UX_TEST_ASSERT(host_in_buffer[1] == UX_STRING_DESCRIPTOR_ITEM); + UX_TEST_ASSERT(host_in_buffer[2] == 0x30); + UX_TEST_ASSERT(host_in_buffer[3] == 0x00); + UX_TEST_ASSERT(host_in_buffer[4] == 0x30); + UX_TEST_ASSERT(host_in_buffer[5] == 0x00); + UX_TEST_ASSERT(host_in_buffer[6] == 0x30); + UX_TEST_ASSERT(host_in_buffer[7] == 0x00); + UX_TEST_ASSERT(host_in_buffer[8] == 0x31); + UX_TEST_ASSERT(host_in_buffer[9] == 0x00); + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* DPUMP error. */ + printf("ERROR count %ld\n", error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + + +static void tx_demo_thread_test_simulation_entry(ULONG arg) +{ +UINT status; +UX_DEVICE *device; + + while(1) + { + +#if defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); +#endif + +#if !defined(UX_HOST_STANDALONE) + if (dpump && dpump -> ux_host_class_dpump_device) + { + /* Get control semaphore for a while. */ + device = dpump -> ux_host_class_dpump_device; + status = tx_semaphore_get(&device -> ux_device_protection_semaphore, UX_WAIT_FOREVER); + if (status != TX_SUCCESS) + { + printf("ERROR #%d:0x%x\n", __LINE__, status); + test_control_return(1); + } + tx_thread_sleep(20); + status = tx_semaphore_put(&device -> ux_device_protection_semaphore); + if (status != TX_SUCCESS) + { + printf("ERROR #%d:0x%x\n", __LINE__, status); + test_control_return(1); + } + } + tx_thread_suspend(&tx_demo_thread_test_simulation); +#endif + + } +} + +static VOID tx_demo_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID tx_demo_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_host_stack_endpoint_instance_create_test.c b/test/regression/usbx_ux_host_stack_endpoint_instance_create_test.c new file mode 100644 index 00000000..d47a810e --- /dev/null +++ b/test/regression/usbx_ux_host_stack_endpoint_instance_create_test.c @@ -0,0 +1,489 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_stack.h" + +#include "ux_test_hcd_sim_host.h" +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_utility_sim.h" + +/* Define USBX demo constants. */ + +#define UX_DEMO_STACK_SIZE 4096 +#define UX_DEMO_BUFFER_SIZE 2048 +#define UX_DEMO_RUN 1 +#define UX_DEMO_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the demo application... */ + +static ULONG test_error_cases = UX_FALSE; +static ULONG test_error_counter = 0; + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +/* Define USBX demo global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x08, /* bMaxPacketSize0 */ + 0xec, 0x08, 0x10, 0x00, /* idVendor, idProduct */ + 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x01, /* bNumConfigurations */ + + /* Configuration descriptor */ + 0x09, 0x02, + 0x20, 0x00, /* wTotalLength */ + 0x01, 0x01, /* bNumInterfaces, bConfigurationValue */ + 0x00, + 0xc0, 0x32, /* bmAttributes, bMaxPower */ + + /* Interface descriptor */ + 0x09, 0x04, + 0x00, 0x00, 0x02, /* bInterfaceNumber, bAlternateSetting, bNumEndpoints */ + 0x99, 0x99, 0x99, /* bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00 +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 */ + 0x0a, 0x07, /* idVendor */ + 0x25, 0x40, /* idProduct */ + 0x01, 0x00, + 0x01, 0x02, 0x03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 */ + 0x01, /* bNumConfigurations */ + 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00 +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +static UCHAR iso_ep_desc[] = +{ + /* Endpoint descriptor (ISO) */ + 0x07, 0x05, 0x01, 0x01, 0x00, 0x01, 0x00, +}; + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID tx_test_instance_activate(VOID *dpump_instance); +static VOID tx_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static void tx_test_thread_host_simulation_entry(ULONG); +static void tx_test_thread_slave_simulation_entry(ULONG); + +static VOID ux_test_hcd_entry_invoked(UX_TEST_ACTION *action, VOID *params); + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +/* Simulation */ + +static UX_TEST_HCD_SIM_ACTION endpoint_create_fail[] = { +/* 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_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR, ux_test_hcd_entry_invoked}, +{ 0 } +}; + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + test_error_counter ++; + + /* Failed test. */ + if (!test_error_cases) + { + + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + 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_stack_endpoint_instance_create_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; + + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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("Running ux_host_stack_endpoint_instance_create Test................. ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_endpoint_instance_create Test................. ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, _ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_endpoint_instance_create Test................. ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_endpoint_instance_create Test................. ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = tx_test_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = tx_test_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_endpoint_instance_create Test................. ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_endpoint_instance_create Test................. ERROR #7\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_endpoint_instance_create Test................. ERROR #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx demo host simulation", tx_test_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("Running ux_host_stack_endpoint_instance_create Test................. ERROR #8\n"); + test_control_return(1); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx demo slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_host_stack_endpoint_instance_create Test................. ERROR #9\n"); + test_control_return(1); + } +} + + +static void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_DEVICE *device; +UX_ENDPOINT endpoint; +UX_HCD *hcd; + + /* Inform user. */ + printf("Running ux_host_stack_endpoint_instance_create Test................. "); + + /* Find the main data pump container. */ + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + /* DPUMP basic test error. */ + printf("ERROR #10\n"); + test_control_return(1); + } + + /* We get the first instance of the data pump device. */ + do + { + + status = ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump); + tx_thread_relinquish(); + } while (status != UX_SUCCESS); + + /* We still need to wait for the data pump status to be live. */ + while (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + { + + tx_thread_relinquish(); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: fail to get device instance\n", __LINE__); + test_control_return(1); + } + + /* Simulate _ux_host_stack_endpoint_instance_create error cases. */ + hcd = &_ux_system_host -> ux_system_host_hcd_array[0]; + endpoint.ux_endpoint_device = device; + + _ux_utility_descriptor_parse(iso_ep_desc, _ux_system_endpoint_descriptor_structure, + UX_ENDPOINT_DESCRIPTOR_ENTRIES, (UCHAR *) &endpoint.ux_endpoint_descriptor); + + test_error_cases = UX_TRUE; + + /* Simulate endpoint creation error. */ + ux_test_hcd_sim_host_set_actions(endpoint_create_fail); + status = _ux_host_stack_endpoint_instance_create(&endpoint); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: expect error\n", __LINE__); + error_counter ++; + } +#if UX_MAX_DEVICES > 1 + /* Simulate bandwidth error: available bandwidth is 0. */ + hcd -> ux_hcd_available_bandwidth = 0; + + status = _ux_host_stack_endpoint_instance_create(&endpoint); + if (status != UX_NO_BANDWIDTH_AVAILABLE) + { + + printf("ERROR #%d: expect UX_NO_BANDWIDTH_AVAILABLE but got %x\n", __LINE__, status); + error_counter ++; + } +#endif + test_error_cases = UX_FALSE; + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* DPUMP error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + + +static void tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Ensure the dpump class on the device is still alive. */ + if (dpump_slave != UX_NULL) + { + + /* Increment thread counter. */ + thread_1_counter++; + } + + /* Let other thread run. */ + tx_thread_sleep(10); + } +} + +static VOID tx_test_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID tx_test_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + +static VOID ux_test_hcd_entry_invoked(UX_TEST_ACTION *action, VOID *params) +{ + + test_error_counter ++; +} \ No newline at end of file diff --git a/test/regression/usbx_ux_host_stack_endpoint_instance_test.c b/test/regression/usbx_ux_host_stack_endpoint_instance_test.c new file mode 100644 index 00000000..9de7476d --- /dev/null +++ b/test/regression/usbx_ux_host_stack_endpoint_instance_test.c @@ -0,0 +1,443 @@ +/* This test is designed to test the ux_host_stack_endpoint_instance_.... */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors. */ +#define DPUMP_IFC_DESC(ifc, alt, nb_ep) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), (alt), (nb_ep), 0x99, 0x99, 0x99, 0x00, + +#define DPUMP_IFC_EP_DESC(epaddr, eptype, epsize) \ + /* Endpoint descriptor */\ + 0x07, 0x05, (epaddr), (eptype), LSB(epsize), MSB(epsize), 0x01, + +#define DPUMP_IFC_DESC_ALL_LEN(nb_ep) (9 + (nb_ep) * 7) + +#define CFG_DESC_ALL_LEN (CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN(4)) + +#define CFG_DESC_ALL \ + CFG_DESC(CFG_DESC_ALL_LEN, 1, 1)\ + DPUMP_IFC_DESC(0, 0, 4)\ + DPUMP_IFC_EP_DESC(0x81, 2, 64)\ + DPUMP_IFC_EP_DESC(0x02, 2, 64)\ + DPUMP_IFC_EP_DESC(0x83, 1, 64)\ + DPUMP_IFC_EP_DESC(0x84, 3, 64)\ + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC_ALL +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC_ALL +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +/* Simulator actions. */ + +static UX_TEST_HCD_SIM_ACTION endpoint0x83_create_del_skip[] = { +/* 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_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x83, UX_NULL, 0, 0, + UX_SUCCESS}, +{ UX_HCD_DESTROY_ENDPOINT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x83, UX_NULL, 0, 0, + UX_SUCCESS}, +{ 0 } +}; + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 break_on_dpump_ready(VOID) +{ + +UINT status; +UX_HOST_CLASS *class; + + /* Find the main data pump container. */ + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class); + if (status != UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + /* Find the instance. */ + status = ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump); + if (status != UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + if (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + + +static UINT test_ux_device_class_dpump_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + switch(command->ux_slave_class_command_request) + { + case UX_SLAVE_CLASS_COMMAND_INITIALIZE: + case UX_SLAVE_CLASS_COMMAND_QUERY: + case UX_SLAVE_CLASS_COMMAND_CHANGE: + return UX_SUCCESS; + + default: + return UX_NO_CLASS_MATCH; + } +} + +static UINT test_ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command) +{ + switch (command -> ux_host_class_command_request) + { + case UX_HOST_CLASS_COMMAND_QUERY: + default: + return _ux_host_class_dpump_entry(command); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_stack_endpoint_instance_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_endpoint_instance_... Test.................... ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_endpoint_instance_... Test.................... ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, test_ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_endpoint_instance_... Test.................... ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_endpoint_instance_... Test.................... ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = UX_NULL; + parameter.ux_slave_class_dpump_instance_deactivate = UX_NULL; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, test_ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_endpoint_instance_... Test.................... ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_endpoint_instance_... Test.................... ERROR #7\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_endpoint_instance_... Test.................... ERROR #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test host simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_host_stack_endpoint_instance_... Test.................... ERROR #8\n"); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + + /* Inform user. */ + printf("Running ux_host_stack_endpoint_instance_... Test.................... "); + + /* Skip ISO EP create/delete. */ + ux_test_hcd_sim_host_set_actions(endpoint0x83_create_del_skip); + + /* Connect. */ + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + ux_test_breakable_sleep(100, break_on_dpump_ready); + + if (dpump == UX_NULL || dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + { + + printf("ERROR #%d: dpump not ready\n", __LINE__); + error_counter ++; + } + + /* Disconnect. */ + ux_test_hcd_sim_host_disconnect(); + ux_test_breakable_sleep(100, break_on_removal); + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_ux_host_stack_endpoint_reset_test.c b/test/regression/usbx_ux_host_stack_endpoint_reset_test.c new file mode 100644 index 00000000..a6e0c014 --- /dev/null +++ b/test/regression/usbx_ux_host_stack_endpoint_reset_test.c @@ -0,0 +1,669 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "fx_api.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_device_stack.h" + +#include "ux_host_class_cdc_acm.h" +#include "ux_host_class_hid.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +#include "ux_host_stack.h" + +/* Define constants. */ +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1) +#define UX_DEMO_XMIT_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BUFFER_SIZE 512 +#define UX_DEMO_FILE_BUFFER_SIZE 512 +#define UX_DEMO_RECEPTION_BLOCK_SIZE 64 +#define UX_DEMO_MEMORY_SIZE (96*1024) +#define UX_DEMO_FILE_SIZE (128 * 1024) +#define UX_RAM_DISK_MEMORY (256 * 1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bmAttributes, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + (bmAttributes), 0x00, +#define CFG_DESC_LEN 9 + +#define IAD_DESC(bIfc) \ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (bIfc), 0x02, 0x02, 0x02, 0x00, 0x00, +#define IAD_DESC_LEN 8 + +#define CDC_IFC_DESC_ALL(bIfc, bIntIn, bBulkIn, bBulkOut)\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (bIfc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06, (bIfc), (bIfc + 1),\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03, (bIfc + 1),\ + /* Endpoint interrupt in descriptor 7 bytes */\ + 0x07, 0x05, (bIntIn), 0x03, 0x40, 0x00, 0x10,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (bIfc + 1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint bulk in descriptor 7 bytes */\ + 0x07, 0x05, (bBulkIn), 0x02, 0x40, 0x00, 0x01,\ + /* Endpoint bulk out descriptor 7 bytes */\ + 0x07, 0x05, (bBulkOut), 0x02, 0x40, 0x00, 0x01, +#define CDC_IFC_DESC_ALL1(bIfc, bIntIn, bBulkIn, bBulkOut)\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (bIfc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06, (bIfc), (bIfc + 1),\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03, (bIfc + 1),\ + /* Endpoint interrupt in descriptor 7 bytes */\ + 0x07, 0x05, (bIntIn), 0x03, 0x40, 0x00, 0x10,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (bIfc + 1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint bulk out descriptor 7 bytes */\ + 0x07, 0x05, (bBulkOut), 0x02, 0x40, 0x00, 0x01,\ + /* Endpoint bulk in descriptor 7 bytes */\ + 0x07, 0x05, (bBulkIn), 0x02, 0x40, 0x00, 0x01, +#define CDC_IFC_DESC_ALL_LEN (9+5+4+5+5+7+ 9+7+7) + +/* Define local/extern function prototypes. */ +static VOID test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static VOID tx_test_thread_host_simulation_entry(ULONG); +static VOID tx_test_thread_slave_simulation_entry(ULONG); + +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance); + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control = UX_NULL; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data = UX_NULL; + +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control1 = UX_NULL; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data1 = UX_NULL; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave = UX_NULL; + +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave1 = UX_NULL; + +static UCHAR cdc_acm_slave_change; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER parameter; + +static ULONG error_counter; + +static ULONG error_callback_counter; +static UCHAR error_callback_ignore; + +static ULONG call_counter; + +static UCHAR buffer[UX_DEMO_BUFFER_SIZE]; + +static UCHAR test_slave_code = 0; +static UCHAR test_slave_state = 0; + +/* Define device framework. */ + +static unsigned char device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Configuration 1 descriptor 9 bytes, total 75 bytes */ + CFG_DESC(CFG_DESC_LEN + (IAD_DESC_LEN + CDC_IFC_DESC_ALL_LEN) * 2, 4, 0x40, 1) + /* IAD 8 bytes */ + IAD_DESC(0) + /* CDC_ACM interfaces */ + CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02) + /* IAD 8 bytes */ + IAD_DESC(2) + /* CDC_ACM interfaces */ + CDC_IFC_DESC_ALL1(2, 0x86, 0x85, 0x04) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor 10 bytes */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor 9 bytes, total 75 bytes */ + CFG_DESC(CFG_DESC_LEN + IAD_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 0x60, 1) + /* IAD 8 bytes */ + IAD_DESC(0) + /* CDC_ACM interfaces */ + CDC_IFC_DESC_ALL1(0, 0x83, 0x81, 0x02) + /* IAD 8 bytes */ + IAD_DESC(2) + /* CDC_ACM interfaces */ + CDC_IFC_DESC_ALL(2, 0x86, 0x85, 0x04) +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Simulation actions. */ + +static UX_TEST_SIM_ENTRY_ACTION hcd_transfer_request_fail[] = { +/* 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, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static UINT break_on_cdc_acm_all_ready(VOID) +{ + + if (cdc_acm_host_control == UX_NULL || cdc_acm_host_data == UX_NULL) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control1 == UX_NULL || cdc_acm_host_data1 == UX_NULL) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_host_data->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control1->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_host_data1->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return 0; + + if (cdc_acm_slave == UX_NULL || cdc_acm_slave1 == UX_NULL) + /* Do not break. */ + return 0; + + /* All found, break. */ + return 1; +} + +static UINT break_on_removal(VOID) +{ + + if (cdc_acm_host_control != UX_NULL || cdc_acm_host_data != UX_NULL) + /* Do not break. */ + return 0; + + if (cdc_acm_host_control1 != UX_NULL || cdc_acm_host_data1 != UX_NULL) + /* Do not break. */ + return 0; + + if (cdc_acm_slave != UX_NULL || cdc_acm_slave1 != UX_NULL) + /* Do not break. */ + return 0; + + return 1; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + if (cdc_acm_host_control == UX_NULL) + cdc_acm_host_control = cdc_acm; + else + if (cdc_acm_host_control1 == UX_NULL) + cdc_acm_host_control1 = cdc_acm; + } + else + { + if (cdc_acm_host_data == UX_NULL) + cdc_acm_host_data = cdc_acm; + else + if (cdc_acm_host_data1 == UX_NULL) + cdc_acm_host_data1 = cdc_acm; + } + break; + + case UX_DEVICE_REMOVAL: + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + { + if (cdc_acm_host_control == cdc_acm) + cdc_acm_host_control = UX_NULL; + if (cdc_acm_host_control1 == cdc_acm) + cdc_acm_host_control1 = UX_NULL; + } + else + { + if (cdc_acm_host_data == cdc_acm) + cdc_acm_host_data = UX_NULL; + if (cdc_acm_host_data1 == cdc_acm) + cdc_acm_host_data1 = UX_NULL; + } + break; + + default: + break; + } + return 0; +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + if (cdc_acm_slave == UX_NULL) + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; + else + if (cdc_acm_slave1 == UX_NULL) + cdc_acm_slave1 = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + if ((VOID *)cdc_acm_slave == cdc_instance) + cdc_acm_slave = UX_NULL; + if ((VOID *)cdc_acm_slave1 == cdc_instance) + cdc_acm_slave1 = UX_NULL; +} + +static VOID test_cdc_instance_parameter_change(VOID *cdc_instance) +{ + + /* Set CDC parameter change flag. */ + cdc_acm_slave_change = UX_TRUE; +} + +static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + error_callback_counter ++; + + if (!error_callback_ignore) + { + /* Ignore UX_DEVICE_HANDLE_UNKNOWN. */ + if (UX_DEVICE_HANDLE_UNKNOWN == error_code) + return; + { + /* 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); + } + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_stack_endpoint_reset_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; + + printf("Running ux_host_stack_endpoint_reset Test........................... "); + + stepinfo("\n"); + + /* Initialize the free memory pointer */ + stack_pointer = (CHAR *) usbx_memory; + memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 2); + + stepinfo(">>>>>>>>>>>>>>>> ux_system_initialize\n"); + + /* 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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(test_ux_error_callback); + + stepinfo(">>>>>>>>>>>>>>>> ux_host_stack_initialize\n"); + + /* The code below is required for installing the host portion of USBX */ + status = ux_host_stack_initialize(test_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> ux_device_stack_initialize\n"); + + /* 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); + } + + stepinfo(">>>>>>>>>>>>>>>> ux_device_stack_class_register\n"); + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + parameter.ux_slave_class_cdc_acm_parameter_change = test_cdc_instance_parameter_change; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,2, ¶meter); + status |= ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,4, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + if(status!=UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#else + error_callback_ignore = UX_TRUE; +#endif + stepinfo(">>>>>>>>>>>>>>>> _ux_test_dcd_sim_slave_initialize\n"); + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> ux_host_stack_class_register\n"); + +#if UX_MAX_CLASS_DRIVER > 1 + /* Register HID class */ + status = ux_host_stack_class_register(_ux_system_host_class_hid_name, ux_host_class_hid_entry); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#endif + + /* Register CDC ACM class */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_entry); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> ux_host_stack_hcd_register\n"); + +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + error_callback_ignore = UX_TRUE; /* One of interface no driver. */ +#endif + + /* Register HCD for test */ + 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); + } + + stepinfo(">>>>>>>>>>>>>>>> Create main test thread\n"); + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_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 #%d\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Create test thread\n"); + + /* Create the main slave simulation thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_DONT_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; + + /* Test connect. */ + stepinfo(">>>>>>>>>>>>>>>> Test connect (FS)\n"); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + ux_test_breakable_sleep(500, break_on_cdc_acm_all_ready); + if (!(cdc_acm_host_control + && cdc_acm_host_data + && cdc_acm_slave +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + && cdc_acm_host_control1 + && cdc_acm_host_data1 + && cdc_acm_slave1 +#endif + )) + { + + printf("ERROR #%d: connect fail\n", __LINE__); + test_control_return(1); + } + + error_callback_ignore = UX_TRUE; + + stepinfo(">>>>>>>>>>>>>>>> Test _ux_host_stack_endpoint_reset - request fail\n"); + + ux_test_hcd_sim_host_set_actions(hcd_transfer_request_fail); + status = _ux_host_stack_endpoint_reset(cdc_acm_host_data->ux_host_class_cdc_acm_bulk_in_endpoint); + if (status == UX_SUCCESS) + { + printf("ERROR #%d: expect error\n", __LINE__); + error_counter ++; + } + + + stepinfo(">>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + ux_test_breakable_sleep(100, break_on_removal); + + if (cdc_acm_host_control || cdc_acm_host_data || cdc_acm_slave) + { + + printf("ERROR #%d: disconnect fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>>>>>>>>> Deinitialize\n"); + + /* Deinitialize the class. */ + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry); + + /* Deinitialize the device side of usbx. */ + _ux_device_stack_uninitialize(); + + /* And finally the usbx system resources. */ + _ux_system_uninitialize(); + + stepinfo(">>>>>>>>>>>>>>>> Dump results\n"); + + if (error_counter > 0) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + +void tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + switch (test_slave_code) + { + default: + break; + } + test_slave_state = 0; + tx_thread_suspend(&tx_test_thread_slave_simulation); + } +} diff --git a/test/regression/usbx_ux_host_stack_enum_bMaxPacketSize0_test.c b/test/regression/usbx_ux_host_stack_enum_bMaxPacketSize0_test.c new file mode 100644 index 00000000..2ef10293 --- /dev/null +++ b/test/regression/usbx_ux_host_stack_enum_bMaxPacketSize0_test.c @@ -0,0 +1,465 @@ +/* This test is designed to test the BOS. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_test.h" +#include "ux_test_utility_sim.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_dcd_sim_slave.h" +#include "ux_host_class_dummy.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +static UX_HOST_CLASS_DUMMY *dummy; + +static UX_DEVICE *device; + +/* Define USBX test global variables. */ + +#define DW3(x) (((x) >> 24) & 0xFFu) +#define DW2(x) (((x) >> 16) & 0xFFu) +#define DW1(x) (((x) >> 8) & 0xFFu) +#define DW0(x) ( (x) & 0xFFu) +#define W1(x) (((x) >> 8) & 0xFFu) +#define W0(x) ( (x) & 0xFFu) + +#define _DEVICE_DESCRIPTOR \ + /* Device descriptor. */ \ + 18, UX_DEVICE_DESCRIPTOR_ITEM, \ + W0(0x201), W1(0x201), \ + UX_CLASS_BILLBOARD_CLASS, \ + UX_CLASS_BILLBOARD_SUBCLASS, \ + UX_CLASS_BILLBOARD_PROTOCOL, \ + 64, \ + W0(0xec08), W1(0xec08), \ + W0(0x0001), W1(0x0001), \ + W0(0x0001), W1(0x0001), \ + 0, 0, 0, \ + 1 + +#define _DEVICE_QUALIFIER_DESCRIPTOR \ + /* Device Qualifier Descriptor. */ \ + 10, UX_DEVICE_QUALIFIER_DESCRIPTOR_ITEM,\ + W0(0x201), W1(0x201), \ + UX_CLASS_BILLBOARD_CLASS, \ + UX_CLASS_BILLBOARD_SUBCLASS, \ + UX_CLASS_BILLBOARD_PROTOCOL, \ + 8, \ + 1, \ + 0 + +#define _CONFIGURATION_DESCRIPTOR \ + /* Configuration Descriptor. */ \ + 9, UX_CONFIGURATION_DESCRIPTOR_ITEM,\ + W0(18), W1(18), \ + 1, 1, \ + 0, 0xc0, 0x32 + +#define _INTERFACE_DESCRIPTOR \ + /* Interface Descriptor. */ \ + 9, UX_INTERFACE_DESCRIPTOR_ITEM,\ + 0, 0, 0, \ + UX_CLASS_BILLBOARD_CLASS, \ + UX_CLASS_BILLBOARD_SUBCLASS, \ + UX_CLASS_BILLBOARD_PROTOCOL, \ + 0 + +#define _BOS_DESCRIPTORS_LENGTH (5+7+56+8+8+8) +#define _BOS_DESCRIPTORS \ + /* BOS descriptor. */ \ + 5, UX_BOS_DESCRIPTOR_ITEM, \ + W0(_BOS_DESCRIPTORS_LENGTH), W1(_BOS_DESCRIPTORS_LENGTH), 1,\ + /* USB 2.0 Extension descriptor */ \ + 7, UX_DEVICE_CAPABILITY_DESCRIPTOR_ITEM, UX_CAPABILITY_USB_2_0_EXTENSION, \ + DW0(0x00000002u), DW1(0x00000002u), DW2(0x00000002u), DW3(0x00000002u), \ + /* Billboard Capability Descriptor Example (44+3*4=56) */\ + 56, UX_DEVICE_CAPABILITY_DESCRIPTOR_ITEM, UX_CAPABILITY_BILLBOARD, 0, \ + 1, 0, \ + W0(0), W1(0), \ + 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + W0(0x0000), W0(0x0000), \ + 0x00, 0x00, \ + W0(0x8087), W1(0x8087), 0x00, 0x00, \ + W0(0x8087), W1(0x8087), 0x01, 0x00, \ + W0(0xFF01), W1(0xFF01), 0x00, 0x00, \ + /* Billboard Alternate Mode Capability Descriptor Examples */\ + 8, UX_DEVICE_CAPABILITY_DESCRIPTOR_ITEM, UX_CAPABILITY_BILLBOARD_EX, \ + 0, DW0(0x00000010), DW1(0x00000010), DW2(0x00000010), DW3(0x00000010), \ + 8, UX_DEVICE_CAPABILITY_DESCRIPTOR_ITEM, UX_CAPABILITY_BILLBOARD_EX, \ + 1, DW0(0x00000002), DW1(0x00000002), DW2(0x00000002), DW3(0x00000002), \ + 8, UX_DEVICE_CAPABILITY_DESCRIPTOR_ITEM, UX_CAPABILITY_BILLBOARD_EX, \ + 2, DW0(0x000C00C5), DW1(0x000C00C5), DW2(0x000C00C5), DW3(0x000C00C5) + + +static UCHAR device_framework_full_speed[] = { + + _DEVICE_DESCRIPTOR, + _BOS_DESCRIPTORS, + _CONFIGURATION_DESCRIPTOR, + _INTERFACE_DESCRIPTOR, +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + _DEVICE_DESCRIPTOR, + _BOS_DESCRIPTORS, + _DEVICE_QUALIFIER_DESCRIPTOR, + _CONFIGURATION_DESCRIPTOR, + _INTERFACE_DESCRIPTOR, +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_host_simulation; +static TX_THREAD ux_test_thread_slave_simulation; +static void ux_test_thread_host_simulation_entry(ULONG); +static void ux_test_thread_slave_simulation_entry(ULONG); + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst); + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static ULONG enum_done_count = 0; +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (error_code == UX_DEVICE_ENUMERATION_FAILURE) + enum_done_count ++; + + if (error_code != UX_DEVICE_HANDLE_UNKNOWN && + error_code != UX_DEVICE_ENUMERATION_FAILURE) + { + /* 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); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_stack_enum_bMaxPacketSize0_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; + + + printf("Running ux_host_stack bMaxPacketSize0 Test.........................."); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + 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_host_change_function); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register a dummy class. */ + status = ux_host_stack_class_register(_ux_host_class_dummy_name, _ux_host_class_dummy_entry); + UX_TEST_CHECK_SUCCESS(status); + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%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 #%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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_host_simulation, "test host simulation", ux_test_thread_host_simulation_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +static void ux_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +INT i; +ULONG mem_free; +const struct _test { + ULONG bMaxPacketSize0; + UINT expect_no_device; +} tests[] = { + { 0, UX_FALSE}, + { 8, UX_FALSE}, + { 16, UX_FALSE}, + { 32, UX_FALSE}, + { 64, UX_FALSE}, + {128, UX_FALSE}, + { 20, UX_FALSE}, +}; +#define N_TESTS (sizeof(tests)/sizeof(struct _test)) + + /* Wait device connection. */ + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + status = ux_test_wait_for_value_ulong(&enum_done_count, 1); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + status = ux_test_wait_for_null_wait_time((VOID**)&device, 1000); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + for (i = 0; i < N_TESTS; i ++) + { + // printf("Test %d\n", i); + + enum_done_count = 0; + device_framework_full_speed[7] = tests[i].bMaxPacketSize0; + device_framework_high_speed[7] = tests[i].bMaxPacketSize0; + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + status = ux_test_wait_for_value_ulong(&enum_done_count, 1); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (tests[i].expect_no_device) + { + if (status == UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + } + else + { + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + status = ux_test_wait_for_null_wait_time((VOID**)&device, 3000); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + } + + if (_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available != mem_free) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + } + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS\n"); + test_control_return(0); + } +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_DUMMY *dummy_ptr = (UX_HOST_CLASS_DUMMY *) inst; + + // printf("hCHG:%lx,%p,%p\n", event, cls, inst); + switch(event) + { + + case UX_DEVICE_INSERTION: + + // printf("hINS:%p,%p:%ld\n", cls, inst, dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber); + if (dummy == UX_NULL) + { + dummy = dummy_ptr; + enum_done_count ++; + } + break; + + case UX_DEVICE_REMOVAL: + + // printf("hRMV:%p,%p:%ld\n", cls, inst, dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber); + if (dummy == dummy_ptr) + dummy = UX_NULL; + break; + + case UX_DEVICE_CONNECTION: + if (device == UX_NULL) + device = (UX_DEVICE *)inst; + break; + + case UX_DEVICE_DISCONNECTION: + if ((VOID *)device == inst) + device = UX_NULL; + break; + + default: + break; + } + return 0; +} diff --git a/test/regression/usbx_ux_host_stack_enum_wMaxPacketSize_test.c b/test/regression/usbx_ux_host_stack_enum_wMaxPacketSize_test.c new file mode 100644 index 00000000..8d3a9f3d --- /dev/null +++ b/test/regression/usbx_ux_host_stack_enum_wMaxPacketSize_test.c @@ -0,0 +1,545 @@ +/* This test is designed to test the BOS. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_test.h" +#include "ux_test_utility_sim.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_dcd_sim_slave.h" +#include "ux_host_class_dummy.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +static UX_HOST_CLASS_DUMMY *dummy; + +static UX_DEVICE *device; + +/* Define USBX test global variables. */ + +#define DW3(x) (((x) >> 24) & 0xFFu) +#define DW2(x) (((x) >> 16) & 0xFFu) +#define DW1(x) (((x) >> 8) & 0xFFu) +#define DW0(x) ( (x) & 0xFFu) +#define W1(x) (((x) >> 8) & 0xFFu) +#define W0(x) ( (x) & 0xFFu) + +#define _DEVICE_DESCRIPTOR \ + /* Device descriptor. */ \ + 18, UX_DEVICE_DESCRIPTOR_ITEM, \ + W0(0x201), W1(0x201), \ + UX_CLASS_BILLBOARD_CLASS, \ + UX_CLASS_BILLBOARD_SUBCLASS, \ + UX_CLASS_BILLBOARD_PROTOCOL, \ + 64, \ + W0(0xec08), W1(0xec08), \ + W0(0x0001), W1(0x0001), \ + W0(0x0001), W1(0x0001), \ + 0, 0, 0, \ + 1 + +#define _DEVICE_QUALIFIER_DESCRIPTOR \ + /* Device Qualifier Descriptor. */ \ + 10, UX_DEVICE_QUALIFIER_DESCRIPTOR_ITEM,\ + W0(0x201), W1(0x201), \ + UX_CLASS_BILLBOARD_CLASS, \ + UX_CLASS_BILLBOARD_SUBCLASS, \ + UX_CLASS_BILLBOARD_PROTOCOL, \ + 8, \ + 1, \ + 0 + +#define _CONFIGURATION_DESCRIPTOR_LENGTH (9+9+7*4) +#define _CONFIGURATION_DESCRIPTOR \ + /* Configuration Descriptor. */ \ + 9, UX_CONFIGURATION_DESCRIPTOR_ITEM, \ + W0(_CONFIGURATION_DESCRIPTOR_LENGTH), \ + W1(_CONFIGURATION_DESCRIPTOR_LENGTH), \ + 1, 1, \ + 0, 0xc0, 0x32 + +#define _INTERFACE_DESCRIPTOR \ + /* Interface Descriptor. */ \ + 9, UX_INTERFACE_DESCRIPTOR_ITEM,\ + 0, 0, 4, \ + UX_CLASS_BILLBOARD_CLASS, \ + UX_CLASS_BILLBOARD_SUBCLASS, \ + UX_CLASS_BILLBOARD_PROTOCOL, \ + 0 + +#define _ENDPOINT_DESCRIPTOR(addr,attr,mps,interval) \ + /* Endpoint descriptor. */ \ + 7, UX_ENDPOINT_DESCRIPTOR_ITEM, \ + (addr), (attr), \ + W0(mps), W1(mps), \ + (interval) + +#define _BOS_DESCRIPTORS_LENGTH (5+7+56+8+8+8) +#define _BOS_DESCRIPTORS \ + /* BOS descriptor. */ \ + 5, UX_BOS_DESCRIPTOR_ITEM, \ + W0(_BOS_DESCRIPTORS_LENGTH), W1(_BOS_DESCRIPTORS_LENGTH), 1,\ + /* USB 2.0 Extension descriptor */ \ + 7, UX_DEVICE_CAPABILITY_DESCRIPTOR_ITEM, UX_CAPABILITY_USB_2_0_EXTENSION, \ + DW0(0x00000002u), DW1(0x00000002u), DW2(0x00000002u), DW3(0x00000002u), \ + /* Billboard Capability Descriptor Example (44+3*4=56) */\ + 56, UX_DEVICE_CAPABILITY_DESCRIPTOR_ITEM, UX_CAPABILITY_BILLBOARD, 0, \ + 1, 0, \ + W0(0), W1(0), \ + 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + W0(0x0000), W0(0x0000), \ + 0x00, 0x00, \ + W0(0x8087), W1(0x8087), 0x00, 0x00, \ + W0(0x8087), W1(0x8087), 0x01, 0x00, \ + W0(0xFF01), W1(0xFF01), 0x00, 0x00, \ + /* Billboard Alternate Mode Capability Descriptor Examples */\ + 8, UX_DEVICE_CAPABILITY_DESCRIPTOR_ITEM, UX_CAPABILITY_BILLBOARD_EX, \ + 0, DW0(0x00000010), DW1(0x00000010), DW2(0x00000010), DW3(0x00000010), \ + 8, UX_DEVICE_CAPABILITY_DESCRIPTOR_ITEM, UX_CAPABILITY_BILLBOARD_EX, \ + 1, DW0(0x00000002), DW1(0x00000002), DW2(0x00000002), DW3(0x00000002), \ + 8, UX_DEVICE_CAPABILITY_DESCRIPTOR_ITEM, UX_CAPABILITY_BILLBOARD_EX, \ + 2, DW0(0x000C00C5), DW1(0x000C00C5), DW2(0x000C00C5), DW3(0x000C00C5) + + +static UCHAR device_framework_full_speed[] = { + + _DEVICE_DESCRIPTOR, + _BOS_DESCRIPTORS, + _CONFIGURATION_DESCRIPTOR, + _INTERFACE_DESCRIPTOR, + _ENDPOINT_DESCRIPTOR(0x81, 0, 8, 0), /* Control. */ + _ENDPOINT_DESCRIPTOR(0x82, 1, 8, 1), /* Isochronous. */ + _ENDPOINT_DESCRIPTOR(0x83, 2, 8, 0), /* Bulk. */ + _ENDPOINT_DESCRIPTOR(0x84, 3, 8, 1), /* Interrupt. */ +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + _DEVICE_DESCRIPTOR, + _BOS_DESCRIPTORS, + _DEVICE_QUALIFIER_DESCRIPTOR, + _CONFIGURATION_DESCRIPTOR, + _INTERFACE_DESCRIPTOR, + _ENDPOINT_DESCRIPTOR(0x81, 0, 8, 0), /* Control. */ + _ENDPOINT_DESCRIPTOR(0x82, 1, 8, 1), /* Isochronous. */ + _ENDPOINT_DESCRIPTOR(0x83, 2, 8, 0), /* Bulk. */ + _ENDPOINT_DESCRIPTOR(0x84, 3, 8, 1), /* Interrupt. */ +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +#define _INT_INTERVAL_B_OFFSET (-1) +#define _INT_MPS_B_OFFSET (-3) +#define _BULK_MPS_B_OFFSET (_INT_MPS_B_OFFSET-7) +#define _ISO_INTERVAL_B_OFFSET (_INT_INTERVAL_B_OFFSET-2*7) +#define _ISO_MPS_B_OFFSET (_BULK_MPS_B_OFFSET-7) +#define _CTRL_MPS_B_OFFSET (_ISO_MPS_B_OFFSET-7) + + +/* 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 +*/ +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_host_simulation; +static TX_THREAD ux_test_thread_slave_simulation; +static void ux_test_thread_host_simulation_entry(ULONG); +static void ux_test_thread_slave_simulation_entry(ULONG); + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst); + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + +static ULONG enum_done_count = 0; +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (error_code == UX_DEVICE_ENUMERATION_FAILURE) + enum_done_count ++; + + if (error_code != UX_DEVICE_HANDLE_UNKNOWN && + error_code != UX_DEVICE_ENUMERATION_FAILURE) + { + /* 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); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_stack_enum_bMaxPacketSize0_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; + + + printf("Running ux_host_stack wMaxPacketSize Test..........................."); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + 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_host_change_function); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register a dummy class. */ + status = ux_host_stack_class_register(_ux_host_class_dummy_name, _ux_host_class_dummy_entry); + UX_TEST_CHECK_SUCCESS(status); + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%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 #%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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_host_simulation, "test host simulation", ux_test_thread_host_simulation_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +static void ux_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +INT i, offset; +ULONG mem_free; +const struct _test { + ULONG speed; + ULONG bmAttributes; + INT wMaxPacketSize_offset; + ULONG wMaxPacketSize; + ULONG bInterval; + UINT expect_no_device; +} tests[] = { + /* Control endpoint. */ + {UX_FULL_SPEED_DEVICE, 0, _CTRL_MPS_B_OFFSET, 0, 0, UX_FALSE}, + {UX_FULL_SPEED_DEVICE, 0, _CTRL_MPS_B_OFFSET, 8, 0, UX_FALSE}, + {UX_FULL_SPEED_DEVICE, 0, _CTRL_MPS_B_OFFSET, 16, 0, UX_FALSE}, + {UX_FULL_SPEED_DEVICE, 0, _CTRL_MPS_B_OFFSET, 20, 0, UX_FALSE}, + /* Bulk endpoint. */ + {UX_FULL_SPEED_DEVICE, 1, _BULK_MPS_B_OFFSET, 0, 0, UX_FALSE}, + {UX_FULL_SPEED_DEVICE, 1, _BULK_MPS_B_OFFSET, 64, 0, UX_FALSE}, + {UX_HIGH_SPEED_DEVICE, 1, _BULK_MPS_B_OFFSET, 512, 0, UX_FALSE}, + {UX_HIGH_SPEED_DEVICE, 1, _BULK_MPS_B_OFFSET, 960, 0, UX_FALSE}, + {UX_FULL_SPEED_DEVICE, 1, _BULK_MPS_B_OFFSET, 20, 0, UX_FALSE}, + /* Interrupt endpoint. */ + {UX_FULL_SPEED_DEVICE, 2, _INT_MPS_B_OFFSET , 0 , 0, UX_FALSE}, + {UX_FULL_SPEED_DEVICE, 2, _INT_MPS_B_OFFSET , 0 , 1, UX_FALSE}, + {UX_FULL_SPEED_DEVICE, 2, _INT_MPS_B_OFFSET , 32 , 0, UX_FALSE}, + {UX_FULL_SPEED_DEVICE, 2, _INT_MPS_B_OFFSET , 32 , 1, UX_FALSE}, + {UX_HIGH_SPEED_DEVICE, 2, _INT_MPS_B_OFFSET , 32 ,16, UX_FALSE}, + {UX_HIGH_SPEED_DEVICE, 2, _INT_MPS_B_OFFSET , 32 ,17, UX_FALSE}, + {UX_FULL_SPEED_DEVICE, 2, _INT_MPS_B_OFFSET , 32 ,17, UX_FALSE}, + {UX_HIGH_SPEED_DEVICE, 2, _INT_MPS_B_OFFSET ,1024 , 1, UX_FALSE}, + {UX_HIGH_SPEED_DEVICE, 2, _INT_MPS_B_OFFSET ,1025 , 1, UX_FALSE}, + {UX_FULL_SPEED_DEVICE, 2, _INT_MPS_B_OFFSET , 20 , 1, UX_FALSE}, + {UX_HIGH_SPEED_DEVICE, 2, _INT_MPS_B_OFFSET ,1024|(1<<11), 1, UX_FALSE}, + {UX_HIGH_SPEED_DEVICE, 2, _INT_MPS_B_OFFSET , 128|(2<<11), 1, UX_FALSE}, + {UX_HIGH_SPEED_DEVICE, 2, _INT_MPS_B_OFFSET , 512|(3<<11), 1, UX_FALSE}, + /* Isochronous endpoint. */ + {UX_FULL_SPEED_DEVICE, 3, _ISO_MPS_B_OFFSET , 0 , 0, UX_FALSE}, + {UX_FULL_SPEED_DEVICE, 3, _ISO_MPS_B_OFFSET , 0 , 1, UX_FALSE}, + {UX_FULL_SPEED_DEVICE, 3, _ISO_MPS_B_OFFSET , 32 , 0, UX_FALSE}, + {UX_FULL_SPEED_DEVICE, 3, _ISO_MPS_B_OFFSET , 32 ,17, UX_FALSE}, + {UX_FULL_SPEED_DEVICE, 3, _ISO_MPS_B_OFFSET , 32 , 1, UX_FALSE}, + {UX_HIGH_SPEED_DEVICE, 3, _ISO_MPS_B_OFFSET , 32 ,16, UX_FALSE}, + {UX_HIGH_SPEED_DEVICE, 3, _ISO_MPS_B_OFFSET , 32 ,17, UX_FALSE}, + {UX_HIGH_SPEED_DEVICE, 3, _ISO_MPS_B_OFFSET ,1025 , 1, UX_FALSE}, + {UX_FULL_SPEED_DEVICE, 3, _ISO_MPS_B_OFFSET , 20 , 1, UX_FALSE}, + {UX_HIGH_SPEED_DEVICE, 3, _ISO_MPS_B_OFFSET ,1024|(1<<11), 1, UX_FALSE}, + {UX_HIGH_SPEED_DEVICE, 3, _ISO_MPS_B_OFFSET , 128|(2<<11), 1, UX_FALSE}, + {UX_HIGH_SPEED_DEVICE, 3, _ISO_MPS_B_OFFSET , 512|(3<<11), 1, UX_FALSE}, +}; +#define N_TESTS (sizeof(tests)/sizeof(struct _test)) + + /* Wait device connection. */ + stepinfo(">>>>>>>>>>>>>>>> Test connect\n"); + status = ux_test_wait_for_value_ulong(&enum_done_count, 1); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Test disconnect. */ + stepinfo(">>>>>>>>>>>>>>>> Test disconnect\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + status = ux_test_wait_for_null_wait_time((VOID**)&device, 1100); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + mem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + for (i = 0; i < N_TESTS; i ++) + { + // printf("Test %d\n", i); + + enum_done_count = 0; + if (tests[i].speed == UX_HIGH_SPEED_DEVICE) + { + offset = DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED; + offset += tests[i].wMaxPacketSize_offset; + _ux_utility_short_put(device_framework_high_speed + offset, tests[i].wMaxPacketSize); + device_framework_high_speed[offset + 2] = tests[i].bInterval; + + // for (INT n = offset - 4; n < offset + 3; n ++) + // printf(" %2x", device_framework_high_speed[n]); + // printf("\n"); + } + else + { + offset = DEVICE_FRAMEWORK_LENGTH_FULL_SPEED; + offset += tests[i].wMaxPacketSize_offset; + _ux_utility_short_put(device_framework_full_speed + offset, tests[i].wMaxPacketSize); + device_framework_full_speed[offset + 2] = tests[i].bInterval; + + // for (INT n = offset - 4; n < offset + 3; n ++) + // printf(" %2x", device_framework_full_speed[n]); + // printf("\n"); + } + ux_test_dcd_sim_slave_connect(tests[i].speed); + ux_test_hcd_sim_host_connect(tests[i].speed); + + status = ux_test_wait_for_value_ulong(&enum_done_count, 1); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (tests[i].expect_no_device) + { + if (status == UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + } + else + { + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + status = ux_test_wait_for_null_wait_time((VOID**)&device, 3000); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + } + + if (_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available != mem_free) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + } + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS\n"); + test_control_return(0); + } +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + +UX_HOST_CLASS_DUMMY *dummy_ptr = (UX_HOST_CLASS_DUMMY *) inst; + + // printf("hCHG:%lx,%p,%p\n", event, cls, inst); + switch(event) + { + + case UX_DEVICE_INSERTION: + + // printf("hINS:%p,%p:%ld\n", cls, inst, dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber); + if (dummy == UX_NULL) + { + dummy = dummy_ptr; + enum_done_count ++; + } + break; + + case UX_DEVICE_REMOVAL: + + // printf("hRMV:%p,%p:%ld\n", cls, inst, dummy -> ux_host_class_dummy_interface -> ux_interface_descriptor.bInterfaceNumber); + if (dummy == dummy_ptr) + dummy = UX_NULL; + break; + + case UX_DEVICE_CONNECTION: + if (device == UX_NULL) + device = (UX_DEVICE *)inst; + break; + + case UX_DEVICE_DISCONNECTION: + // printf("hDisc: %p <> %p\n", device, inst); + if ((VOID *)device == inst) + device = UX_NULL; + break; + + default: + break; + } + return 0; +} diff --git a/test/regression/usbx_ux_host_stack_hcd_register_test.c b/test/regression/usbx_ux_host_stack_hcd_register_test.c new file mode 100644 index 00000000..4b3a8f64 --- /dev/null +++ b/test/regression/usbx_ux_host_stack_hcd_register_test.c @@ -0,0 +1,517 @@ +/* This test is designed to test the ux_host_stack_hcd_register. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +/* HID mouse related descriptors */ + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +#define LSB(x) (x & 0x00ff) +#define MSB(x) ((x & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x20, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors 9+7+7=23 bytes. */ +#define DPUMP_IFC_DESC_ALL(ifc, bulk_in_epa, bulk_out_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x02, 0x99, 0x99, 0x99, 0x00,\ + /* Endpoint descriptor (Bulk Out) */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Bulk In) */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00, +#define DPUMP_IFC_DESC_ALL_LEN 23 + +/* HID Mouse interface descriptors 9+9=18 bytes */ +#define HID_MOUSE_IFC0_DESC_ALL(ifc) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH), +#define HID_MOUSE_IFC0_DESC_ALL_LEN 18 + +/* HID Mouse interface descriptors 9+9+7=25 bytes */ +#define HID_MOUSE_IFC1_DESC_ALL(ifc, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x01, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_MOUSE_IFC1_DESC_ALL_LEN 25 + +/* CDC-ACM interfaces descriptors 8 +9+5+4+5+5+7 +9+7+7=66 bytes */ +#define CDC_ACM_IFCES_DESC_ALL(ifc, interrupt_epa, bulk_in_epa, bulk_out_epa) \ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (ifc), 0x02, 0x02, 0x02, 0x00, 0x00,\ + /* Communication Class Interface Descriptor Requirement. 9 bytes. */\ + 0x09, 0x04, (ifc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06,\ + (ifc), /* Master interface */\ + (ifc+1), /* Slave interface */\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03,\ + (ifc+1), /* Data interface */\ + /* Interrupt endpoint descriptor 7 bytes */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 15,\ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (ifc+1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\ + /* Endpoint descriptor 7 bytes */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor 7 bytes */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00, +#define CDC_ACM_IFCES_DESC_ALL_LEN 66 + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR expect_errors = UX_FALSE; + + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN + CDC_ACM_IFCES_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+9+7 =25 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02) + /* HID 9+9 + 9+9+7=43 */ + HID_MOUSE_IFC0_DESC_ALL(1) + HID_MOUSE_IFC1_DESC_ALL(1, 0x83) + /* CDC-ACM */ + CDC_ACM_IFCES_DESC_ALL(2, 0x86, 0x85, 0x04) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN + CDC_ACM_IFCES_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+9+7 =25 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02) + /* HID 9+9 + 9+9+7=43 */ + HID_MOUSE_IFC0_DESC_ALL(1) + HID_MOUSE_IFC1_DESC_ALL(1, 0x83) + /* CDC-ACM */ + CDC_ACM_IFCES_DESC_ALL(2, 0x86, 0x85, 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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Simulation actions. */ + +static UX_TEST_SIM_ENTRY_ACTION dcd_endpoint_create_fail[] = { +/* 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_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ 0 } +}; + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (!expect_errors) + { + if (error_code != UX_DEVICE_HANDLE_UNKNOWN) + { + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } + } +} + +static UINT test_ux_device_class_hid_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + return UX_SUCCESS; + // return _ux_device_class_hid_entry(command); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_stack_hcd_register_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; +UX_SLAVE_CLASS_HID_PARAMETER hid_parameter; + + /* Inform user. */ + printf("Running ux_host_stack_hcd_register Test............................. "); + stepinfo("\n"); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + 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(UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry); + + /* Check for error. */ + 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 */ + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = ux_test_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = ux_test_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Initialize the hid class parameters. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_REPORT_LENGTH; + hid_parameter.ux_device_class_hid_parameter_callback = UX_NULL; + hid_parameter.ux_slave_class_hid_instance_activate = UX_NULL; + + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, test_ux_device_class_hid_entry, + 1, 1, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#endif + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test host simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + +UINT status; +UCHAR invalid_class_name[UX_MAX_CLASS_NAME_LENGTH+2]; + + + /* Inform user. */ + stepinfo(">>>>>>>>> ENUM check\n"); + + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Enumeration check. */ + if (dpump_slave == UX_NULL) + { + + printf("ERROR #%d: Enum fail\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>>>>>>> Disconnect\n"); + ux_test_dcd_sim_slave_disconnect(); + ux_test_hcd_sim_host_disconnect(); + + /* Expect errors so skip them in error handler. */ + expect_errors = UX_TRUE; +#if !defined(UX_NAME_REFERENCED_BY_POINTER) + stepinfo(">>>>>>>>> _ux_host_stack_hcd_register - error if class_name exceed UX_MAX_CLASS_NAME_LENGTH\n"); + _ux_utility_memory_set(invalid_class_name, 'a', sizeof(invalid_class_name)); + _ux_utility_memory_copy(invalid_class_name, _ux_system_host_hcd_simulator_name, 16); + status = _ux_host_stack_hcd_register(invalid_class_name, _ux_test_hcd_sim_host_initialize, 0, 0); + if (status != UX_ERROR) + { + printf("ERROR %d: expect error %d\n", __LINE__, UX_ERROR); + error_counter ++; + } +#endif + /* Break on errors. */ + expect_errors = UX_TRUE; + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static VOID ux_test_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID ux_test_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_host_stack_hcd_thread_entry_test.c b/test/regression/usbx_ux_host_stack_hcd_thread_entry_test.c new file mode 100644 index 00000000..34ddf766 --- /dev/null +++ b/test/regression/usbx_ux_host_stack_hcd_thread_entry_test.c @@ -0,0 +1,520 @@ +/* This test is designed to test the _ux_host_stack_hcd_thread_entry. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_host_stack.h" +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static ULONG hcd_thread_counter[UX_MAX_HCD]; + +static ULONG error_callback_ignore = UX_FALSE; + + +/* Define USBX test global variables. */ + +static unsigned char host_out_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; +static unsigned char host_in_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; +static unsigned char slave_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave; + + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00 + }; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00 + }; + + /* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string + */ + +#define STRING_FRAMEWORK_LENGTH 38 +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* 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 + }; + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_host_simulation; +static TX_THREAD ux_test_thread_slave_simulation; +static void ux_test_thread_host_simulation_entry(ULONG); +static void ux_test_thread_slave_simulation_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (error_callback_ignore != UX_TRUE && + error_code != UX_CONFIGURATION_HANDLE_UNKNOWN) + { + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } +} + +UINT _ux_hcd_test_host_entry(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; + + + /* Check the status of the controller. */ + if (hcd -> ux_hcd_status == UX_UNUSED) + { + + /* Error trap. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HCD, UX_CONTROLLER_UNKNOWN); + + /* If trace is enabled, insert this event into the trace buffer. */ + UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_CONTROLLER_UNKNOWN, 0, 0, 0, UX_TRACE_ERRORS, 0, 0) + + return(UX_CONTROLLER_UNKNOWN); + } + + hcd_thread_counter[hcd -> ux_hcd_io] ++; + + /* look at the function and route it. */ + switch(function) + { + + case UX_HCD_GET_PORT_STATUS: + + status = UX_PORT_INDEX_UNKNOWN; + break; + case UX_HCD_GET_FRAME_NUMBER: + case UX_HCD_DISABLE_CONTROLLER: + case UX_HCD_ENABLE_PORT: + case UX_HCD_DISABLE_PORT: + case UX_HCD_POWER_ON_PORT: + case UX_HCD_POWER_DOWN_PORT: + case UX_HCD_SUSPEND_PORT: + case UX_HCD_RESUME_PORT: + case UX_HCD_RESET_PORT: + case UX_HCD_SET_FRAME_NUMBER: + case UX_HCD_TRANSFER_REQUEST: + case UX_HCD_TRANSFER_ABORT: + case UX_HCD_CREATE_ENDPOINT: + case UX_HCD_DESTROY_ENDPOINT: + case UX_HCD_RESET_ENDPOINT: + case UX_HCD_PROCESS_DONE_QUEUE: + + status = UX_SUCCESS; + break; + + + default: + + /* Error trap. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HCD, UX_FUNCTION_NOT_SUPPORTED); + + /* If trace is enabled, insert this event into the trace buffer. */ + UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_FUNCTION_NOT_SUPPORTED, 0, 0, 0, UX_TRACE_ERRORS, 0, 0) + + /* Unknown request, return an error. */ + status = UX_FUNCTION_NOT_SUPPORTED; + } + + /* Return completion status. */ + return(status); +} + +static void _ux_hcd_test_host_signal_event(UX_HCD *hcd) +{ + hcd -> ux_hcd_thread_signal ++; + _ux_utility_semaphore_put(&_ux_system_host->ux_system_host_hcd_semaphore); +} + +UINT _ux_hcd_test_host_initialize(UX_HCD *hcd) +{ + + /* Initialize the function collector for this HCD. */ + hcd -> ux_hcd_entry_function = _ux_hcd_test_host_entry; + + /* Set the host controller into the operational state. */ + hcd -> ux_hcd_status = UX_HCD_STATUS_OPERATIONAL; + + /* Get the number of ports on the controller. The number of ports needs to be reflected both + for the generic HCD container and the local sim_host container. In the simulator, + the number of ports is hardwired to 1 only. */ + hcd -> ux_hcd_nb_root_hubs = 1; + + /* Something happened on this port. Signal it to the root hub thread. */ + hcd -> ux_hcd_root_hub_signal[0] = 1; + + /* We need to simulate a Root HUB Status Change for the USB stack since the simulator + has not root HUB per se. */ + _ux_utility_semaphore_put(&_ux_system_host -> ux_system_host_enum_semaphore); + + /* Return successful completion. */ + return(UX_SUCCESS); +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_stack_hcd_thread_entry_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; + + + /* Inform user. */ + printf("Running _ux_host_stack_hcd_thread_entry Test........................ "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = ux_test_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = ux_test_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #7\n"); + test_control_return(1); + } + + /* Register all the USB host controllers available in this system */ + hcd_thread_counter[0] = 0; + 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 #4\n"); + test_control_return(1); + } + +#if UX_MAX_HCD > 1 + /* Register all the USB host controllers available in this system */ + hcd_thread_counter[1] = 0; + status = ux_host_stack_hcd_register("hcd_test_driver 1", _ux_hcd_test_host_initialize, 1, 0); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #4\n"); + test_control_return(1); + } +#endif + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_host_simulation, "test host simulation", ux_test_thread_host_simulation_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #8\n"); + test_control_return(1); + } +} + + +static void ux_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; + + /* Find the main data pump container. */ + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + /* DPUMP basic test error. */ + printf("ERROR #10\n"); + test_control_return(1); + } + + /* We get the first instance of the data pump device. */ + do + { + + status = ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump); + tx_thread_relinquish(); + } while (status != UX_SUCCESS); + + /* We still need to wait for the data pump status to be live. */ + while (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + { + + tx_thread_relinquish(); + } + + /* At this point, the data pump class has been found. */ + +#if UX_MAX_HCD > 1 + /* Check if thread entry is called once. */ + if (hcd_thread_counter[1] != 1) + { + printf("ERROR #%d, %d\n", __LINE__, hcd_thread_counter[1]); + test_control_return(1); + } + + /* Check if thread entry is called. */ + _ux_hcd_test_host_signal_event(&_ux_system_host->ux_system_host_hcd_array[1]); + _ux_utility_delay_ms(10); + if (hcd_thread_counter[1] != 2) + { + printf("ERROR #%d, %d\n", __LINE__, hcd_thread_counter[1]); + test_control_return(1); + } + + /* Check if thread entry is still called when first HCD unregistered. */ + error_callback_ignore = UX_TRUE; + ux_host_stack_hcd_unregister(_ux_system_host_hcd_simulator_name, 0, 0); + _ux_utility_delay_ms(10); + if (_ux_system_host->ux_system_host_hcd_array[0].ux_hcd_status == UX_HCD_STATUS_OPERATIONAL) + { + printf("ERROR #%d, HCD unregister fail\n", __LINE__); + test_control_return(1); + } + + _ux_hcd_test_host_signal_event(&_ux_system_host->ux_system_host_hcd_array[1]); + _ux_utility_delay_ms(10); + if (hcd_thread_counter[1] != 3) + { + printf("ERROR #%d, %d\n", __LINE__, hcd_thread_counter[1]); + test_control_return(1); + } +#endif + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static VOID ux_test_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID ux_test_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_host_stack_hcd_transfer_request_test.c b/test/regression/usbx_ux_host_stack_hcd_transfer_request_test.c new file mode 100644 index 00000000..c4ea98a5 --- /dev/null +++ b/test/regression/usbx_ux_host_stack_hcd_transfer_request_test.c @@ -0,0 +1,495 @@ +/* This test is designed to test the ux_host_stack_hcd_transfer_request. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +/* HID mouse related descriptors */ + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +#define LSB(x) (x & 0x00ff) +#define MSB(x) ((x & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors 9+7+7=23 bytes. */ +#define DPUMP_IFC_DESC_ALL(ifc, bulk_in_epa, bulk_out_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x02, 0x99, 0x99, 0x99, 0x00,\ + /* Endpoint descriptor (Bulk Out) */\ + 0x07, 0x05, (bulk_out_epa), 0x02, 0x40, 0x00, 0x00,\ + /* Endpoint descriptor (Bulk In) */\ + 0x07, 0x05, (bulk_in_epa), 0x02, 0x40, 0x00, 0x00, +#define DPUMP_IFC_DESC_ALL_LEN 23 + +/* HID Mouse interface descriptors 9+9=18 bytes */ +#define HID_MOUSE_IFC0_DESC_ALL(ifc) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH), +#define HID_MOUSE_IFC0_DESC_ALL_LEN 18 + +/* HID Mouse interface descriptors 9+9+7=25 bytes */ +#define HID_MOUSE_IFC1_DESC_ALL(ifc, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x01, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_MOUSE_IFC1_DESC_ALL_LEN 25 + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR expect_errors = UX_FALSE; + + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor 9 bytes */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN, 2, 1) + /* DPUMP 9+9+7 =25 */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02) + /* HID 9+9 + 9+9+7=43 */ + HID_MOUSE_IFC0_DESC_ALL(1) + HID_MOUSE_IFC1_DESC_ALL(1, 0x83) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN, 2, 1) + /* DPUMP */ + DPUMP_IFC_DESC_ALL(0, 0x81, 0x02) + /* HID */ + HID_MOUSE_IFC0_DESC_ALL(1) + HID_MOUSE_IFC1_DESC_ALL(1, 0x83) +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Simulation actions. */ + +static UX_TEST_SIM_ENTRY_ACTION dcd_endpoint_create_fail[] = { +/* 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_DCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ 0 } +}; + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (!expect_errors) + { + if (error_code != UX_DEVICE_HANDLE_UNKNOWN) + { + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } + } +} + +static UINT test_ux_device_class_hid_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + return UX_SUCCESS; + // return _ux_device_class_hid_entry(command); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_stack_hcd_transfer_request_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; +UX_SLAVE_CLASS_HID_PARAMETER hid_parameter; + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_hcd_transfer_request Test..................... ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_hcd_transfer_request Test..................... ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_hcd_transfer_request Test..................... ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_hcd_transfer_request Test..................... ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = ux_test_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = ux_test_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Initialize the hid class parameters. */ + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_REPORT_LENGTH; + hid_parameter.ux_device_class_hid_parameter_callback = UX_NULL; + hid_parameter.ux_slave_class_hid_instance_activate = UX_NULL; + + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, test_ux_device_class_hid_entry, + 1, 1, ¶meter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_hcd_transfer_request Test..................... ERROR #6\n"); + test_control_return(1); + } +#endif + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_hcd_transfer_request Test..................... ERROR #7\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_hcd_transfer_request Test..................... ERROR #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test host simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_host_stack_hcd_transfer_request Test..................... ERROR #8\n"); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + +UINT status; +UX_DEVICE *device; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; + + /* Inform user. */ + printf("Running ux_host_stack_hcd_transfer_request Test..................... "); + + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Enumeration check. */ + if (dpump_slave == UX_NULL) + { + + printf("ERROR #%d: Enum fail\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Test normal requests */ + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_requested_length = 64; + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = UX_DEVICE_DESCRIPTOR_ITEM << 8; + transfer_request -> ux_transfer_request_index = 0; + status = _ux_host_stack_hcd_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: GetDeviceDescriptor(64) fail\n", __LINE__); + error_counter ++; + } + if (transfer_request->ux_transfer_request_actual_length != 18) + { + + printf("ERROR #%d: GetDeviceDescriptor(64) actual length is not 18\n", __LINE__); + error_counter ++; + } + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static VOID ux_test_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID ux_test_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_host_stack_hcd_unregister_test.c b/test/regression/usbx_ux_host_stack_hcd_unregister_test.c new file mode 100644 index 00000000..f53f7fb5 --- /dev/null +++ b/test/regression/usbx_ux_host_stack_hcd_unregister_test.c @@ -0,0 +1,632 @@ +/* This test is designed to test the ux_utility_memory_.... */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_device_class_dpump.h" +#include "ux_host_class_dpump.h" + +#include "ux_host_stack.h" +#include "ux_hcd_sim_host.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_MEMORY_SIZE (64*1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +static UCHAR bad_name[UX_MAX_HCD_NAME_LENGTH + 1]; + + +/* Define USBX test global variables. */ + + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50 +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00 +}; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60 +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00 +}; + +/* String Device Framework : + Byte 0 and 1 : Word containing the language ID : 0x0904 for US + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +#define STRING_FRAMEWORK_LENGTH 38 +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* 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 +}; + +/* Actions/callbacks hook. */ + +static UX_TEST_SETUP _SetCfgDescriptor = UX_TEST_SETUP_SetConfigure; + +static VOID ux_test_set_cfg_descriptor_invoked(UX_TEST_ACTION *action, VOID *params) +{ + /* Unregister HCD. */ + _ux_host_stack_hcd_unregister(_ux_system_host_hcd_simulator_name, 0, 0);; +} + +static UX_TEST_HCD_SIM_ACTION hcd_unregister_while_enum[] = { +/* 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, &_SetCfgDescriptor, + UX_FALSE, 0, + UX_TEST_SETUP_MATCH_REQ_V_I, 0, UX_NULL, 0, UX_SUCCESS, + UX_SUCCESS, ux_test_set_cfg_descriptor_invoked, + .no_return = UX_TRUE, + .do_after = UX_FALSE}, +{ 0 } +}; + + +/* Define prototypes for external Controller's (HCD/DCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_simulation_0; +static void ux_test_thread_simulation_0_entry(ULONG); + +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_1_entry(ULONG); + +static UX_SLAVE_CLASS_DPUMP *dpump_device = UX_NULL; +static VOID ux_test_dpump_instance_activate(VOID *dpump_instance); +static VOID ux_test_dpump_instance_deactivate(VOID *dpump_instance); + +/* 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); + } + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_stack_hcd_unregister_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +UCHAR *stack_pointer; +UCHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; + + + /* Inform user. */ + printf("Running ux_host_stack_hcd_unregister Test........................... "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = ux_test_dpump_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = ux_test_dpump_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +#define UX_TEST_CONN_PASS 0 +#define UX_TEST_CONN_WAIT 1 +#define UX_TEST_CONN_CHECK 2 +static void ux_test_hcd_register(char *s, int line, int connection_wait) +{ +UINT status; +INT i; +UX_DEVICE *device; +char *nothing = ""; + if (s == UX_NULL) + s = nothing; + 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 #%s%d.%d: 0x%x\n", s, line, __LINE__, status); + test_control_return(1); + } + if (!connection_wait) + return; + /* Wait for connection. */ + for (i = 0; i < 100; i ++) + { + tx_thread_sleep(UX_MS_TO_TICK_NON_ZERO(10)); + status = _ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS && dpump_device != UX_NULL) + break; + } + if (connection_wait > UX_TEST_CONN_WAIT) + { + if (dpump_device == UX_NULL) + { + printf("ERROR #%s%d.%d\n", s, line, __LINE__); + test_control_return(1); + } + if (status != UX_SUCCESS || device == UX_NULL) + { + printf("ERROR #%s%d.%d\n", s, line, __LINE__); + test_control_return(1); + } + } +} + +static UINT entry_function(UX_HCD* hcd, UINT function, VOID* parameter) +{ + return(UX_SUCCESS); + + +} + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + +UINT status; +ULONG rfree; +INT i, try; +char hdr[64]; +UX_DEVICE *device; + + + /* Initialize host stack. */ + status = ux_host_stack_initialize(UX_NULL); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /************************** Register & unregister (no device connected). */ + + /* Log memory level to check. */ + rfree = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + /* Provent HCD & ENUM thread to run. */ + _ux_utility_thread_suspend(&_ux_system_host -> ux_system_host_hcd_thread); + _ux_utility_thread_suspend(&_ux_system_host -> ux_system_host_enum_thread); + + /* Register. */ + ux_test_hcd_register(UX_NULL, __LINE__, UX_TEST_CONN_PASS); + + /* Unregister. */ + status = _ux_host_stack_hcd_unregister(_ux_system_host_hcd_simulator_name, 0, 0); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + if (rfree != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Clear semaphore by init. */ + _ux_utility_semaphore_get(&_ux_system_host -> ux_system_host_enum_semaphore, 0); + + /* Resume threads. */ + _ux_utility_thread_resume(&_ux_system_host -> ux_system_host_hcd_thread); + _ux_utility_thread_resume(&_ux_system_host -> ux_system_host_enum_thread); + + /************************** Register & unregister (device connected). */ + + /* Register HCD. */ + ux_test_hcd_register(UX_NULL, __LINE__, UX_TEST_CONN_CHECK); + + /* Error ignore, there should be UX_CONTROLLER_UNKNOWN. */ + error_callback_ignore = UX_TRUE; + + /* Unregister HCD. */ + status = _ux_host_stack_hcd_unregister(_ux_system_host_hcd_simulator_name, 0, 0); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Get host device. */ + status = _ux_host_stack_device_get(0, &device); + if (status != UX_DEVICE_HANDLE_UNKNOWN) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /************************** Unregister HCD not found. */ + + /* Unregister HCD. */ + status = _ux_host_stack_hcd_unregister(_ux_system_host_hcd_ehci_name, 0, 0); + if (status == UX_SUCCESS) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /************************** Unregister HCD bad name. */ + + /* Bad string (error callback reported). */ + _ux_utility_memory_set(bad_name, '0', UX_MAX_HCD_NAME_LENGTH + 1); + + /* Unregister HCD. */ + status = _ux_host_stack_hcd_unregister(bad_name, 0, 0); + if (status == UX_SUCCESS) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /************************** Unregister HCD other cases not tested. */ + /* E.g., HCD name match but parameters not, HCD parameters match but name not. */ + /* E.g., All connected devices are not rooted from the HCD to unregister. */ + + /* No error ignore. */ + error_callback_ignore = UX_FALSE; + + /************************** Register & unregister several times (not corrupted). */ + + // ux_test_dcd_sim_slave_disconnect(); + // ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + + for (try = 0; try < 4; try ++) + { + // printf("#%d.%d\n", try, __LINE__); + sprintf(hdr, "%i", try); + + /* Log memory level to check. */ + rfree = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + /* Register HCD. */ + ux_test_hcd_register(hdr, __LINE__, UX_TEST_CONN_CHECK); + + error_callback_ignore = UX_TRUE; + + if(try < 3) + /* Unregister HCD. */ + status = _ux_host_stack_hcd_unregister(_ux_system_host_hcd_simulator_name, 0, 0); + else + { + /* Test line 127 */ + _ux_host_stack_hcd_unregister(_ux_system_host_hcd_simulator_name, 1, 0); + + /* Test line 128 */ + _ux_host_stack_hcd_unregister(_ux_system_host_hcd_simulator_name, 0, 1); + + /* Test line 138 */ + _ux_host_stack_hcd_unregister("noname", 0, 0); + + /* ALl previous 3 calls would fail. Call the unregister again to properly + unregister this HCD. */ + status = _ux_host_stack_hcd_unregister(_ux_system_host_hcd_simulator_name, 0, 0); + + } + + if (status != UX_SUCCESS) + { + printf("ERROR #%d.%d: 0x%x\n", try, __LINE__, status); + test_control_return(1); + } + + + /* Get host device. */ + status = _ux_host_stack_device_get(0, &device); + if (status != UX_DEVICE_HANDLE_UNKNOWN) + { + printf("ERROR #%d.%d: 0x%x\n", try, __LINE__, status); + test_control_return(1); + } + + /* Check memory level. */ + if (rfree != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + printf("ERROR #%d.%d\n", try, __LINE__); + test_control_return(1); + } + + error_callback_ignore = UX_FALSE; + + // ux_test_dcd_sim_slave_disconnect(); + // ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + + } /* for (try = 0; try < 3; try ++) */ + + /************************** Register & unregister when enumeration in progress. */ + + /* Log memory level to check. */ + rfree = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + /* Capture GetDeviceDescriptor and unregister HCD at that time. */ + ux_test_hcd_sim_host_set_actions(hcd_unregister_while_enum); + + /* Register HCD. */ + error_callback_ignore = UX_TRUE; + ux_test_hcd_register(UX_NULL, __LINE__, UX_TEST_CONN_WAIT); + + /* Get host device. */ + status = _ux_host_stack_device_get(0, &device); + if (status != UX_DEVICE_HANDLE_UNKNOWN) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + error_callback_ignore = UX_FALSE; + + /* Check memory level. */ + if (rfree != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + +#if UX_MAX_HCD > 1 && UX_MAX_DEVICES > 1 + + /************************** Unregister all devices on HCD RH. */ + + /* Skip first slot, to use later device slots. */ + _ux_system_host->ux_system_host_device_array[0].ux_device_handle = UX_USED; + + /* Register several HCD. */ + ux_test_hcd_register("", __LINE__, UX_TEST_CONN_CHECK); + status = _ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize,1,0); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (_ux_system_host->ux_system_host_device_array[1].ux_device_handle == UX_UNUSED) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Mark slot free. */ + _ux_system_host->ux_system_host_device_array[0].ux_device_handle = UX_UNUSED; + + /* Unregister HCD, device on slot 1 is removed. */ + error_callback_ignore = UX_TRUE; + status = _ux_host_stack_hcd_unregister(_ux_system_host_hcd_simulator_name, 0, 0); + error_callback_ignore = UX_FALSE; + if (status != UX_SUCCESS) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Device should be removed. */ + if (_ux_system_host->ux_system_host_device_array[1].ux_device_handle != UX_UNUSED) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#endif + + { + UX_HCD* hcd; + UX_DEVICE* device; + + hcd = _ux_system_host->ux_system_host_hcd_array; + hcd->ux_hcd_status = UX_USED; + hcd->ux_hcd_io = 0; + hcd->ux_hcd_irq = 0; + hcd->ux_hcd_entry_function = entry_function; + strcpy(hcd->ux_hcd_name, _ux_system_host_hcd_simulator_name); + device = _ux_system_host->ux_system_host_device_array; + +#if UX_MAX_DEVICES>1 + device->ux_device_hcd = hcd; +#endif +#if UX_MAX_DEVICES>1 + if (_ux_system_host->ux_system_host_max_devices == 0) + { + printf("ERROR #%d: ux_system_host_max_devices= %ld errors\n", __LINE__, _ux_system_host->ux_system_host_max_devices); + test_control_return(1); + + } + device->ux_device_parent = device; + +#endif + device->ux_device_handle = 1; + + status = _ux_host_stack_hcd_unregister(_ux_system_host_hcd_simulator_name, 0, 0); + if(status) + error_counter++; + } + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } + + +} + + +static VOID ux_test_dpump_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_device = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID ux_test_dpump_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_device = UX_NULL; +} diff --git a/test/regression/usbx_ux_host_stack_interface_endpoint_get_test.c b/test/regression/usbx_ux_host_stack_interface_endpoint_get_test.c new file mode 100644 index 00000000..96ca2dc7 --- /dev/null +++ b/test/regression/usbx_ux_host_stack_interface_endpoint_get_test.c @@ -0,0 +1,476 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_stack.h" + +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +/* Define USBX demo constants. */ + +#define UX_DEMO_STACK_SIZE 4096 +#define UX_DEMO_BUFFER_SIZE 2048 +#define UX_DEMO_RUN 1 +#define UX_DEMO_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the demo application... */ + +static ULONG test_error_cases = UX_FALSE; +static ULONG test_error_counter = 0; + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +/* Define USBX demo global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x08, /* bMaxPacketSize0 */ + 0xec, 0x08, 0x10, 0x00, /* idVendor, idProduct */ + 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x01, /* bNumConfigurations */ + + /* Configuration descriptor */ + 0x09, 0x02, + 0x20, 0x00, /* wTotalLength */ + 0x01, 0x01, /* bNumInterfaces, bConfigurationValue */ + 0x00, + 0xc0, 0x32, /* bmAttributes, bMaxPower */ + + /* Interface descriptor */ + 0x09, 0x04, + 0x00, 0x00, 0x02, /* bInterfaceNumber, bAlternateSetting, bNumEndpoints */ + 0x99, 0x99, 0x99, /* bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00 +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 */ + 0x0a, 0x07, /* idVendor */ + 0x25, 0x40, /* idProduct */ + 0x01, 0x00, + 0x01, 0x02, 0x03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 */ + 0x01, /* bNumConfigurations */ + 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00 +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID tx_demo_instance_activate(VOID *dpump_instance); +static VOID tx_demo_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); +static void tx_demo_thread_slave_simulation_entry(ULONG); + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + test_error_counter ++; + + /* Failed test. */ + if (!test_error_cases) + { + + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + 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_stack_interface_endpoint_get_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; + + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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("Running ux_host_stack_interface_endpoint_get Test................... ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_interface_endpoint_get Test................... ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, _ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_interface_endpoint_get Test................... ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_interface_endpoint_get Test................... ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = tx_demo_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = tx_demo_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_interface_endpoint_get Test................... ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_interface_endpoint_get Test................... ERROR #7\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_interface_endpoint_get Test................... ERROR #4\n"); + 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("Running ux_host_stack_interface_endpoint_get Test................... ERROR #8\n"); + test_control_return(1); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_host_stack_interface_endpoint_get Test................... ERROR #9\n"); + test_control_return(1); + } +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +UX_ENDPOINT *endpoint; +ULONG interface_handler; + + /* Inform user. */ + printf("Running ux_host_stack_interface_endpoint_get Test................... "); + + /* Find the main data pump container. */ + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + /* DPUMP basic test error. */ + printf("ERROR #10\n"); + test_control_return(1); + } + + /* We get the first instance of the data pump device. */ + do + { + + status = ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump); + tx_thread_relinquish(); + } while (status != UX_SUCCESS); + + /* We still need to wait for the data pump status to be live. */ + while (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + { + + tx_thread_relinquish(); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: fail to get device instance\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_configuration_get(device, 0, &configuration); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: fail to get configuration instance\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_configuration_interface_get(configuration, 0, 0, &interface); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: fail to get interface instance\n", __LINE__); + test_control_return(1); + } + + /* Simulate _ux_host_stack_interface_endpoint_get error cases. */ + + /* Expecting errors. */ + test_error_cases = UX_TRUE; + + /* Simulate invalid interface. */ + interface_handler = interface->ux_interface_handle; + interface->ux_interface_handle = 0; + status = _ux_host_stack_interface_endpoint_get(interface, 0, &endpoint); + if (status != UX_INTERFACE_HANDLE_UNKNOWN) + { + + printf("ERROR #%d: expect interface error but got %x\n", __LINE__, status); + error_counter ++; + } + interface->ux_interface_handle = interface_handler; + + /* Simulate invalid endpoint index. */ + status = _ux_host_stack_interface_endpoint_get(interface, 10, &endpoint); + if (status != UX_ENDPOINT_HANDLE_UNKNOWN) + { + + printf("ERROR #%d: expect endpoint error but got %x\n", __LINE__, status); + error_counter ++; + } + + /* Break on errors. */ + test_error_cases = UX_FALSE; + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* DPUMP error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + + +static void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Ensure the dpump class on the device is still alive. */ + if (dpump_slave != UX_NULL) + { + + /* Increment thread counter. */ + thread_1_counter++; + } + + /* Let other thread run. */ + tx_thread_sleep(10); + } +} + +static VOID tx_demo_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID tx_demo_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_host_stack_interface_setting_select_test.c b/test/regression/usbx_ux_host_stack_interface_setting_select_test.c new file mode 100644 index 00000000..0b3e2bfe --- /dev/null +++ b/test/regression/usbx_ux_host_stack_interface_setting_select_test.c @@ -0,0 +1,613 @@ +/* This test is designed to test the ux_host_stack_interface_setting_select. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +/* HID mouse related descriptors */ + +static UCHAR hid_mouse_report[] = { + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x09, 0x38, // USAGE (Mouse Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#define HID_MOUSE_REPORT_LENGTH (sizeof(hid_mouse_report)/sizeof(hid_mouse_report[0])) + +#define LSB(x) (x & 0x00ff) +#define MSB(x) ((x & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors 9+7+7=23 bytes. */ +#define DPUMP_IFC0_DESC_ALL(ifc, bulk_in_epa, bulk_out_epa, bulk_eps) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x02, 0x99, 0x99, 0x99, 0x00,\ + /* Endpoint descriptor (Bulk Out) */\ + 0x07, 0x05, (bulk_out_epa), 0x02, LSB(bulk_eps), MSB(bulk_eps), 0x00,\ + /* Endpoint descriptor (Bulk In) */\ + 0x07, 0x05, (bulk_in_epa), 0x02, LSB(bulk_eps), MSB(bulk_eps), 0x00, +#define DPUMP_IFC0_DESC_ALL_LEN 23 + +/* DPUMP interface descriptors 9 bytes. */ +#define DPUMP_IFC1_DESC_ALL(ifc) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x01, 0x00, 0x99, 0x99, 0x99, 0x00, +#define DPUMP_IFC1_DESC_ALL_LEN 9 + +/* HID Mouse interface descriptors 9+9+7=25 bytes */ +#define HID_MOUSE_IFC0_DESC_ALL(ifc, interrupt_epa) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x00, 0x01, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH),\ + /* Endpoint descriptor (Interrupt) */\ + 0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08, +#define HID_MOUSE_IFC0_DESC_ALL_LEN 25 + +/* HID Mouse interface descriptors 9+9=18 bytes */ +#define HID_MOUSE_IFC1_DESC_ALL(ifc) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), 0x01, 0x00, 0x03, 0x00, 0x00, 0x00,\ + /* HID descriptor */\ + 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_MOUSE_REPORT_LENGTH),\ + MSB(HID_MOUSE_REPORT_LENGTH), +#define HID_MOUSE_IFC1_DESC_ALL_LEN 18 + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR expect_errors = UX_FALSE; + +static UCHAR skip_class_activations = UX_FALSE; + + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC0_DESC_ALL_LEN + DPUMP_IFC1_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN, 2, 1) + DPUMP_IFC0_DESC_ALL(0, 0x81, 0x02, 64) + DPUMP_IFC1_DESC_ALL(0) + HID_MOUSE_IFC0_DESC_ALL(1, 0x83) + HID_MOUSE_IFC1_DESC_ALL(1) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC(CFG_DESC_LEN + DPUMP_IFC0_DESC_ALL_LEN + DPUMP_IFC1_DESC_ALL_LEN + HID_MOUSE_IFC0_DESC_ALL_LEN + HID_MOUSE_IFC1_DESC_ALL_LEN, 2, 1) + DPUMP_IFC0_DESC_ALL(0, 0x81, 0x02, 64) + DPUMP_IFC1_DESC_ALL(0) + HID_MOUSE_IFC0_DESC_ALL(1, 0x83) + HID_MOUSE_IFC1_DESC_ALL(1) +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + +/* Simulation actions. */ + +static UX_TEST_SETUP _SetInterface = {0x01,UX_SET_INTERFACE,0x0000,0x0000}; + +static UX_TEST_SIM_ENTRY_ACTION hcd_set_interface_fail[] = { +/* 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, &_SetInterface, + UX_FALSE, 0, + UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ 0 } +}; + +static UX_TEST_SIM_ENTRY_ACTION hcd_create_endpoint_fail[] = { +/* 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_CREATE_ENDPOINT, UX_NULL, + UX_FALSE, 0, + 0, 0, UX_NULL, 0, 0, + UX_ERROR , UX_NULL}, +{ 0 } +}; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (!expect_errors) + { + + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %x\n", __LINE__, system_level, system_context, error_code); + test_control_return(1); + } +} + +UINT test_ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command) +{ + + if (skip_class_activations && command->ux_host_class_command_request != UX_HOST_CLASS_COMMAND_QUERY) + return UX_SUCCESS; + + return _ux_host_class_dpump_entry(command); +} + +static UINT test_ux_device_class_dpump_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + + if (skip_class_activations && command->ux_slave_class_command_request != UX_SLAVE_CLASS_COMMAND_QUERY) + return UX_SUCCESS; + + return _ux_device_class_dpump_entry(command); +} + +static UINT test_ux_device_class_hid_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + + if (skip_class_activations && command->ux_slave_class_command_request != UX_SLAVE_CLASS_COMMAND_QUERY) + return UX_SUCCESS; + + return _ux_device_class_hid_entry(command); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_stack_interface_setting_select_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; +UX_SLAVE_CLASS_HID_PARAMETER hid_parameter; + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_interface_setting_select Test................. ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_interface_setting_select Test................. ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, test_ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_interface_setting_select Test................. ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_interface_setting_select Test................. ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = ux_test_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = ux_test_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, test_ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Initialize the hid class parameters. */ + ux_utility_memory_set(&hid_parameter, 0, sizeof(UX_SLAVE_CLASS_HID_PARAMETER)); + hid_parameter.ux_device_class_hid_parameter_report_address = hid_mouse_report; + hid_parameter.ux_device_class_hid_parameter_report_length = HID_MOUSE_REPORT_LENGTH; + hid_parameter.ux_device_class_hid_parameter_callback = UX_NULL; + hid_parameter.ux_slave_class_hid_instance_activate = UX_NULL; + + status |= ux_device_stack_class_register(_ux_system_slave_class_hid_name, test_ux_device_class_hid_entry, + 1, 1, &hid_parameter); +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_interface_setting_select Test................. ERROR #6\n"); + test_control_return(1); + } +#endif + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_interface_setting_select Test................. ERROR #7\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_interface_setting_select Test................. ERROR #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test host simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_host_stack_interface_setting_select Test................. ERROR #8\n"); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + +UINT status; +INT i; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +UX_INTERFACE *interfaces[8]; + + + /* Inform user. */ + printf("Running ux_host_stack_interface_setting_select Test................. "); + + ux_test_dcd_sim_slave_connect(UX_HIGH_SPEED_DEVICE); + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + + /* Enumeration check. */ + if (dpump_slave == UX_NULL) + { + + printf("ERROR #%d: Enum fail\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_configuration_get(device, 0, &configuration); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: cfg_get fail\n", __LINE__); + test_control_return(1); + } + + interface = configuration->ux_configuration_first_interface; + for (i = 0; i < 8; i ++) + { + + if (interface == UX_NULL) + break; + + interfaces[i] = interface; + interface = interface->ux_interface_next_interface; + } + + /* Switch to interface 0.1 */ + status = ux_host_stack_interface_setting_select(interfaces[1]); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: ifc_set fail\n", __LINE__); + error_counter ++; + } + + /* Switch to interface 0.0 */ + status = ux_host_stack_interface_setting_select(interfaces[0]); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: ifc_set fail\n", __LINE__); + error_counter ++; + } + + /* Expect errors so skip them in error handler. */ + expect_errors = UX_TRUE; + + /* Test invalid interface handler. */ + interface = interfaces[0]; + interface->ux_interface_handle = 0; + + status = ux_host_stack_interface_setting_select(interface); + if (status != UX_INTERFACE_HANDLE_UNKNOWN) + { + + printf("ERROR #%d: expect UX_INTERFACE_HANDLE_UNKNOWN but get %x\n", __LINE__, status); + error_counter ++; + } + interface->ux_interface_handle = (ULONG)(ALIGN_TYPE)interface; + + /* Test interface instance creation failure. */ + /* Simulate endpoint creation fail. */ + status = ux_host_stack_interface_setting_select(interfaces[1]); + ux_test_hcd_sim_host_set_actions(hcd_create_endpoint_fail); + status |= ux_host_stack_interface_setting_select(interfaces[0]); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: expect error but get %x\n", __LINE__, status); + error_counter ++; + } + + /* Test SET_INTERFACE request error. */ + status = ux_host_stack_interface_setting_select(interfaces[1]); + ux_test_hcd_sim_host_set_actions(hcd_set_interface_fail); + status |= ux_host_stack_interface_setting_select(interfaces[0]); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: expect error but get %x\n", __LINE__, status); + error_counter ++; + } + + /* Break on errors. */ + expect_errors = UX_TRUE; + + /* Switch to interface 2 0 */ + UX_TEST_ASSERT(ux_test_check_actions_empty()); + status = ux_host_stack_interface_setting_select(interfaces[2]); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: ifc_set fail\n", __LINE__); + error_counter ++; + } + + /* Test Semphor get error */ + _ux_utility_semaphore_delete(&device -> ux_device_protection_semaphore); + status = ux_host_stack_interface_setting_select(interfaces[2]); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: expect error but get %x\n", __LINE__, status); + error_counter ++; + } + _ux_utility_semaphore_create(&device -> ux_device_protection_semaphore, "ux_device_protection_semaphore", 1); + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static VOID ux_test_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID ux_test_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_host_stack_interfaces_scan_test.c b/test/regression/usbx_ux_host_stack_interfaces_scan_test.c new file mode 100644 index 00000000..f809d68a --- /dev/null +++ b/test/regression/usbx_ux_host_stack_interfaces_scan_test.c @@ -0,0 +1,477 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_stack.h" + +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +/* Define USBX demo constants. */ + +#define UX_DEMO_STACK_SIZE 4096 +#define UX_DEMO_BUFFER_SIZE 2048 +#define UX_DEMO_RUN 1 +#define UX_DEMO_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the demo application... */ + +static ULONG test_error_cases = UX_FALSE; +static ULONG test_error_counter = 0; + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +/* Define USBX demo global variables. */ + +static unsigned char host_out_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; +static unsigned char host_in_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; +static unsigned char slave_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x08, /* bMaxPacketSize0 */ + 0xec, 0x08, 0x10, 0x00, /* idVendor, idProduct */ + 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x01, /* bNumConfigurations */ + + /* Configuration descriptor */ + 0x09, 0x02, + 0x20, 0x00, /* wTotalLength */ + 0x01, 0x01, /* bNumInterfaces, bConfigurationValue */ + 0x00, + 0xc0, 0x32, /* bmAttributes, bMaxPower */ + + /* Interface descriptor */ + 0x09, 0x04, + 0x00, 0x00, 0x02, /* bInterfaceNumber, bAlternateSetting, bNumEndpoints */ + 0x99, 0x99, 0x99, /* bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00 +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 */ + 0x0a, 0x07, /* idVendor */ + 0x25, 0x40, /* idProduct */ + 0x01, 0x00, + 0x01, 0x02, 0x03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 */ + 0x01, /* bNumConfigurations */ + 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00 +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID tx_demo_instance_activate(VOID *dpump_instance); +static VOID tx_demo_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); +static void tx_demo_thread_slave_simulation_entry(ULONG); + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + test_error_counter ++; + + /* Failed test. */ + if (!test_error_cases) + { + + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + 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_stack_interfaces_scan_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; + + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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("Running ux_host_stack_interfaces_scan Test.......................... ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_interfaces_scan Test.......................... ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, _ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_interfaces_scan Test.......................... ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_interfaces_scan Test.......................... ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = tx_demo_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = tx_demo_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_interfaces_scan Test.......................... ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_interfaces_scan Test.......................... ERROR #7\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_interfaces_scan Test.......................... ERROR #4\n"); + 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("Running ux_host_stack_interfaces_scan Test.......................... ERROR #8\n"); + test_control_return(1); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_host_stack_interfaces_scan Test.......................... ERROR #9\n"); + test_control_return(1); + } +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HOST_CLASS *class; +UX_DEVICE *device; + + /* Inform user. */ + printf("Running ux_host_stack_interfaces_scan Test.......................... "); + + /* Find the main data pump container. */ + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + /* DPUMP basic test error. */ + printf("ERROR #10\n"); + test_control_return(1); + } + + /* We get the first instance of the data pump device. */ + do + { + + status = ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump); + tx_thread_relinquish(); + } while (status != UX_SUCCESS); + + /* We still need to wait for the data pump status to be live. */ + while (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + { + + tx_thread_relinquish(); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: fail to get device instance\n", __LINE__); + test_control_return(1); + } + + /* Simulate _ux_host_stack_interfaces_scan error cases. */ + + /* Disconnect. */ + ux_test_hcd_sim_host_disconnect(); + + /* Test error cases. */ + test_error_cases = UX_TRUE; + test_error_counter = 0; + + /* Modify descriptor to generate errors. */ + device_framework_full_speed[18] = 0; /* bLength: 9 -> 0 */ + + /* Wait enum. */ + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + tx_thread_sleep(50); + + /* Expect error. */ + if (!test_error_counter) + { + + printf("ERROR #%d: expect configuration descriptor corrupt error\n", __LINE__); + error_counter ++; + } + /* Restore descriptor. */ + device_framework_full_speed[18] = 9; + + /* Disconnect. */ + ux_test_hcd_sim_host_disconnect(); + + /* Modify descriptor to generate errors. */ + device_framework_full_speed[18] = 99; /* bLength: 9 -> 99 */ + + /* Wait enum. */ + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + tx_thread_sleep(50); + + /* Expect error. */ + if (!test_error_counter) + { + + printf("ERROR #%d: expect configuration descriptor corrupt error\n", __LINE__); + error_counter ++; + } + /* Restore descriptor. */ + device_framework_full_speed[18] = 9; + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* DPUMP error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + + +static void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Ensure the dpump class on the device is still alive. */ + if (dpump_slave != UX_NULL) + { + + /* Increment thread counter. */ + thread_1_counter++; + } + + /* Let other thread run. */ + tx_thread_sleep(10); + } +} + +static VOID tx_demo_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID tx_demo_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_host_stack_new_configuration_create_test.c b/test/regression/usbx_ux_host_stack_new_configuration_create_test.c new file mode 100644 index 00000000..d5587c34 --- /dev/null +++ b/test/regression/usbx_ux_host_stack_new_configuration_create_test.c @@ -0,0 +1,622 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_device_stack.h" +#include "ux_host_stack.h" + +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +/* Define USBX demo constants. */ + +#define UX_DEMO_STACK_SIZE 4096 +#define UX_DEMO_BUFFER_SIZE 2048 +#define UX_DEMO_RUN 1 +#define UX_DEMO_MEMORY_SIZE (64*1024) + +#define LSB(x) (x & 0x00ff) +#define MSB(x) ((x & 0xff00) >> 8) + +/* CDC IAD 8 bytes */ +#define CDC_IAD_DESC(comm_ifc) \ + /* Interface association descriptor. 8 bytes. */\ + 0x08, 0x0b, (comm_ifc), 0x02, 0x02, 0x02, 0x00, 0x00, +#define CDC_IAD_DESC_LEN 8 + +/* CDC Communication interface descriptors 9+5+4+5+5+7=35 bytes */ +#define CDC_COMM_IFC_DESC_ALL(comm_ifc, data_ifc, interrupt_epa) \ + /* Communication Class Interface Descriptor. 9 bytes. */\ + 0x09, 0x04, (comm_ifc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\ + /* Header Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x00, 0x10, 0x01,\ + /* ACM Functional Descriptor 4 bytes */\ + 0x04, 0x24, 0x02, 0x0f,\ + /* Union Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x06,\ + (comm_ifc), /* Master interface */\ + (data_ifc), /* Slave interface */\ + /* Call Management Functional Descriptor 5 bytes */\ + 0x05, 0x24, 0x01, 0x03,\ + (data_ifc), /* Data interface */\ + /* Endpoint 0x83 descriptor 7 bytes */\ + 0x07, 0x05, (interrupt_epa),\ + 0x03,\ + 0x08, 0x00,\ + 0xFF, +#define CDC_COMM_IFC_DESC_ALL_LEN 35 + +/* CDC Data interface descriptors 9+7+7=23 bytes */ +#define CDC_DATA_IFC_DESC_ALL(ifc, bulk_in_epa, bulk_out_epa) \ + /* Data Class Interface Descriptor Requirement 9 bytes */\ + 0x09, 0x04, (ifc),\ + 0x00, /* bAlternateSetting */\ + 0x02, /* bNumEndpoints */\ + 0x0A, 0x00, 0x00,\ + 0x00,\ + /* Endpoint bulk IN descriptor 7 bytes */\ + 0x07, 0x05, (bulk_in_epa),\ + 0x02,\ + 0x40, 0x00,\ + 0x00,\ + /* Endpoint bulk OUT descriptor 7 bytes */\ + 0x07, 0x05, (bulk_out_epa),\ + 0x02,\ + 0x40, 0x00,\ + 0x00, +#define CDC_DATA_IFC_DESC_ALL_LEN 23 + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* Define the counters used in the demo application... */ + +static ULONG test_error_cases = UX_FALSE; +static ULONG test_error_counter; + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +/* Define USBX demo global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER cdc_acm_parameter; + +static UCHAR detect_insertion; +static UCHAR detect_extraction; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x03, + + /* Configuration 1 descriptor 9 bytes */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Endpoint 0x83 descriptor 7 bytes */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, /* @ 93 - 14 + 2 = 81 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, /* @ 93 - 7 + 2 = 88 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Configuration 2: CDC */ + CFG_DESC(CFG_DESC_LEN+(CDC_IAD_DESC_LEN+CDC_COMM_IFC_DESC_ALL_LEN+CDC_DATA_IFC_DESC_ALL_LEN), 2, 2) + CDC_IAD_DESC(0) + CDC_COMM_IFC_DESC_ALL(0, 1, 0x83) + CDC_DATA_IFC_DESC_ALL(1, 0x81, 0x02) + + /* Configuration 3: CDC */ + CFG_DESC(CFG_DESC_LEN+(CDC_IAD_DESC_LEN+CDC_COMM_IFC_DESC_ALL_LEN+CDC_DATA_IFC_DESC_ALL_LEN), 3, 2) + CDC_IAD_DESC(0) + CDC_COMM_IFC_DESC_ALL(0, 1, 0x83) + CDC_DATA_IFC_DESC_ALL(1, 0x81, 0x02) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor */ + 0x05, 0x24, 0x06, + 0x00, + 0x01, + + /* Call Management Functional Descriptor */ + 0x05, 0x24, 0x01, + 0x00, + 0x01, + + /* Endpoint 0x83 descriptor */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor */ + 0x07, 0x05, 0x02, /* @ 103 - 14 + 2 = 91 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor */ + 0x07, 0x05, 0x81, /* @ 103 - 7 + 2 = 98 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Configuration 2: CDC */ + CFG_DESC(CFG_DESC_LEN+(CDC_IAD_DESC_LEN+CDC_COMM_IFC_DESC_ALL_LEN+CDC_DATA_IFC_DESC_ALL_LEN), 2, 2) + CDC_IAD_DESC(0) + CDC_COMM_IFC_DESC_ALL(0, 1, 0x83) + CDC_DATA_IFC_DESC_ALL(1, 0x81, 0x02) + + /* Configuration 3: CDC */ + CFG_DESC(CFG_DESC_LEN+(CDC_IAD_DESC_LEN+CDC_COMM_IFC_DESC_ALL_LEN+CDC_DATA_IFC_DESC_ALL_LEN), 3, 2) + CDC_IAD_DESC(0) + CDC_COMM_IFC_DESC_ALL(0, 1, 0x83) + CDC_DATA_IFC_DESC_ALL(1, 0x81, 0x02) +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst); + +UINT ux_hcd_sim_initialize(UX_HCD *hcd); + +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static void tx_test_thread_host_simulation_entry(ULONG); +static void tx_test_thread_slave_simulation_entry(ULONG); + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + test_error_counter ++; + + /* Failed test. */ + if (!test_error_cases) + { + + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + 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_stack_new_configuration_create_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; + + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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("Running ux_host_stack_new_configuration_create Test................. ERROR #1\n"); + 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_host_change_function); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_new_configuration_create Test................. ERROR #2\n"); + test_control_return(1); + } + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_new_configuration_create Test................. ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_new_configuration_create Test................. ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + cdc_acm_parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + cdc_acm_parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + cdc_acm_parameter.ux_slave_class_cdc_acm_parameter_change = UX_NULL; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, &cdc_acm_parameter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_new_configuration_create Test................. ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_new_configuration_create Test................. ERROR #7\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_new_configuration_create Test................. ERROR #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx demo host simulation", tx_test_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("Running ux_host_stack_new_configuration_create Test................. ERROR #8\n"); + test_control_return(1); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx demo slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_host_stack_new_configuration_create Test................. ERROR #9\n"); + test_control_return(1); + } +} + + +static void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_DEVICE *device; + + /* Inform user. */ + printf("Running ux_host_stack_new_configuration_create Test................. "); + + /* Wait connect. */ + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + tx_thread_sleep(100); + if (cdc_acm_host_control == UX_NULL || cdc_acm_host_data == UX_NULL || cdc_acm_slave == UX_NULL) + { + + printf("ERROR #%d: connection not detected\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: fail to get device instance\n", __LINE__); + test_control_return(1); + } + + /* No other simulation. */ + + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* DPUMP error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + + +static void tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Ensure the dpump class on the device is still alive. */ + if (cdc_acm_slave != UX_NULL) + { + + /* Increment thread counter. */ + thread_1_counter++; + } + + /* Let other thread run. */ + tx_thread_sleep(10); + } +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} + +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + detect_insertion = UX_TRUE; + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + detect_extraction = UX_TRUE; + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + + default: + break; + } + return UX_SUCCESS; +} \ No newline at end of file diff --git a/test/regression/usbx_ux_host_stack_new_device_create_test.c b/test/regression/usbx_ux_host_stack_new_device_create_test.c new file mode 100644 index 00000000..c9587454 --- /dev/null +++ b/test/regression/usbx_ux_host_stack_new_device_create_test.c @@ -0,0 +1,587 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_device_stack.h" +#include "ux_host_stack.h" + +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +/* Define USBX demo constants. */ + +#define UX_DEMO_STACK_SIZE 4096 +#define UX_DEMO_BUFFER_SIZE 2048 +#define UX_DEMO_RUN 1 +#define UX_DEMO_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the demo application... */ + +static ULONG test_error_cases = UX_FALSE; +static ULONG test_error_counter; + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +/* Define USBX demo global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER cdc_acm_parameter; + +static UCHAR detect_insertion; +static UCHAR detect_extraction; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Configuration 1 descriptor 9 bytes */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Endpoint 0x83 descriptor 7 bytes */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, /* @ 93 - 14 + 2 = 81 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, /* @ 93 - 7 + 2 = 88 */ + 0x02, + 0x40, 0x00, + 0x00, +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor */ + 0x05, 0x24, 0x06, + 0x00, + 0x01, + + /* Call Management Functional Descriptor */ + 0x05, 0x24, 0x01, + 0x00, + 0x01, + + /* Endpoint 0x83 descriptor */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor */ + 0x07, 0x05, 0x02, /* @ 103 - 14 + 2 = 91 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor */ + 0x07, 0x05, 0x81, /* @ 103 - 7 + 2 = 98 */ + 0x02, + 0x40, 0x00, + 0x00, +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst); + +UINT ux_hcd_sim_initialize(UX_HCD *hcd); + +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static void tx_test_thread_host_simulation_entry(ULONG); +static void tx_test_thread_slave_simulation_entry(ULONG); + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + test_error_counter ++; + + /* Failed test. */ + if (!test_error_cases) + { + + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + 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_stack_new_device_create_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; + + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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("Running ux_host_stack_new_device_create Test........................ ERROR #1\n"); + 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_host_change_function); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_new_device_create Test........................ ERROR #2\n"); + test_control_return(1); + } + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_new_device_create Test........................ ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_new_device_create Test........................ ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + cdc_acm_parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + cdc_acm_parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + cdc_acm_parameter.ux_slave_class_cdc_acm_parameter_change = UX_NULL; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, &cdc_acm_parameter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_new_device_create Test........................ ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_new_device_create Test........................ ERROR #7\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_new_device_create Test........................ ERROR #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx demo host simulation", tx_test_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("Running ux_host_stack_new_device_create Test........................ ERROR #8\n"); + test_control_return(1); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx demo slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_host_stack_new_device_create Test........................ ERROR #9\n"); + test_control_return(1); + } +} + + +static void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HCD *hcd; +UX_DEVICE *device; +UX_DEVICE *created_device; +ULONG nb_devices; +UINT i; + + /* Inform user. */ + printf("Running ux_host_stack_new_device_create Test........................ "); + + /* Wait connect. */ + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + tx_thread_sleep(100); + if (cdc_acm_host_control == UX_NULL || cdc_acm_host_data == UX_NULL || cdc_acm_slave == UX_NULL) + { + + printf("ERROR #%d: connection not detected\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: fail to get device instance\n", __LINE__); + test_control_return(1); + } + + /* Simulate device creation errors. */ + + test_error_cases = UX_TRUE; + + hcd = &_ux_system_host -> ux_system_host_hcd_array[0]; + + /* Modify number of devices to generate error. */ + nb_devices = hcd->ux_hcd_nb_devices; + hcd -> ux_hcd_nb_devices = UX_MAX_USB_DEVICES + 1; + + status = _ux_host_stack_new_device_create(hcd, UX_NULL, 0, UX_FULL_SPEED_DEVICE, 50, &created_device); + if (status != UX_TOO_MANY_DEVICES) + { + + printf("ERROR #%d: expect error for too many devices\n", __LINE__); + error_counter ++; + } + /* Restore correct number of devices. */ + hcd -> ux_hcd_nb_devices = nb_devices; + + /* Get new devices until error. */ + for (i = 0; i < UX_MAX_USB_DEVICES; i ++) + { + + device = _ux_host_stack_new_device_get(); + + /* If we are not able to get new device, it's OK. */ + if (device == UX_NULL) + break; + } + + /* Expect UX_TOO_MANY_DEVICES error */ + status = _ux_host_stack_new_device_create(hcd, UX_NULL, 0, UX_FULL_SPEED_DEVICE, 50, &created_device); + if (status != UX_TOO_MANY_DEVICES) + { + + printf("ERROR #%d: expect error for too many devices\n", __LINE__); + error_counter ++; + } + if (hcd->ux_hcd_nb_devices != nb_devices) + { + + printf("ERROR #%d: number of devices should not be changed if get new device fail\n", __LINE__); + error_counter ++; + } + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* DPUMP error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + + +static void tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Ensure the dpump class on the device is still alive. */ + if (cdc_acm_slave != UX_NULL) + { + + /* Increment thread counter. */ + thread_1_counter++; + } + + /* Let other thread run. */ + tx_thread_sleep(10); + } +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} + +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + detect_insertion = UX_TRUE; + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + detect_extraction = UX_TRUE; + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + + default: + break; + } + return UX_SUCCESS; +} \ No newline at end of file diff --git a/test/regression/usbx_ux_host_stack_new_device_get_test.c b/test/regression/usbx_ux_host_stack_new_device_get_test.c new file mode 100644 index 00000000..ec4a1e52 --- /dev/null +++ b/test/regression/usbx_ux_host_stack_new_device_get_test.c @@ -0,0 +1,165 @@ +/* This test is designed to test the ux_host_stack_new_device_get. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + + +/* Define USBX test global variables. */ + +static unsigned char host_out_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; +static unsigned char host_in_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; +static unsigned char slave_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + + +static TX_THREAD ux_test_thread_host_simulation; +static TX_THREAD ux_test_thread_slave_simulation; +static void ux_test_thread_host_simulation_entry(ULONG); +static void ux_test_thread_slave_simulation_entry(ULONG); + +extern UX_DEVICE *_ux_host_stack_new_device_get(VOID); + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_stack_new_device_get_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_stack_new_device_get Test........................... "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #1\n"); + test_control_return(1); + } + + /* The code below is required for installing the host portion of USBX. */ + status = ux_host_stack_initialize(UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #2\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&ux_test_thread_host_simulation, "test host simulation", ux_test_thread_host_simulation_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #3\n"); + test_control_return(1); + } + + +} + + +static void ux_test_thread_host_simulation_entry(ULONG arg) +{ + +UX_DEVICE *new_device; +UINT i; + + + /* Test ux_host_stack_new_device_get. */ + for (i = UX_SYSTEM_HOST_MAX_DEVICES_GET(); i != 0; i--) + { + new_device = _ux_host_stack_new_device_get(); + if (new_device == UX_NULL) + { + + printf("ERROR #4\n"); + test_control_return(1); + } + } + + /* There is no device entry available now. Try to get new device again. */ + new_device = _ux_host_stack_new_device_get(); + + /* Check if UX_NULL is returned. */ + if (new_device != UX_NULL) + { + + printf("ERROR #5\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); +} \ No newline at end of file diff --git a/test/regression/usbx_ux_host_stack_new_interface_create_test.c b/test/regression/usbx_ux_host_stack_new_interface_create_test.c new file mode 100644 index 00000000..dced9788 --- /dev/null +++ b/test/regression/usbx_ux_host_stack_new_interface_create_test.c @@ -0,0 +1,596 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_device_stack.h" +#include "ux_host_stack.h" + +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +/* Define USBX demo constants. */ + +#define UX_DEMO_STACK_SIZE 4096 +#define UX_DEMO_BUFFER_SIZE 2048 +#define UX_DEMO_RUN 1 +#define UX_DEMO_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the demo application... */ + +static ULONG test_error_cases = UX_FALSE; +static ULONG test_error_counter; + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +/* Define USBX demo global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER cdc_acm_parameter; + +static UCHAR detect_insertion; +static UCHAR detect_extraction; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Configuration 1 descriptor 9 bytes */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Endpoint 0x83 descriptor 7 bytes */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, /* @ 93 - 14 + 2 = 81 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, /* @ 93 - 7 + 2 = 88 */ + 0x02, + 0x40, 0x00, + 0x00, +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor */ + 0x05, 0x24, 0x06, + 0x00, + 0x01, + + /* Call Management Functional Descriptor */ + 0x05, 0x24, 0x01, + 0x00, + 0x01, + + /* Endpoint 0x83 descriptor */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor */ + 0x07, 0x05, 0x02, /* @ 103 - 14 + 2 = 91 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor */ + 0x07, 0x05, 0x81, /* @ 103 - 7 + 2 = 98 */ + 0x02, + 0x40, 0x00, + 0x00, +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst); + +UINT ux_hcd_sim_initialize(UX_HCD *hcd); + +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static void tx_test_thread_host_simulation_entry(ULONG); +static void tx_test_thread_slave_simulation_entry(ULONG); + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + test_error_counter ++; + + /* Failed test. */ + if (!test_error_cases) + { + + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + 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_stack_new_interface_create_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; + + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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("Running ux_host_stack_new_interface_create Test..................... ERROR #1\n"); + 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_host_change_function); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_new_interface_create Test..................... ERROR #2\n"); + test_control_return(1); + } + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_new_interface_create Test..................... ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_new_interface_create Test..................... ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + cdc_acm_parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + cdc_acm_parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + cdc_acm_parameter.ux_slave_class_cdc_acm_parameter_change = UX_NULL; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, &cdc_acm_parameter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_new_interface_create Test..................... ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_new_interface_create Test..................... ERROR #7\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_new_interface_create Test..................... ERROR #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx demo host simulation", tx_test_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("Running ux_host_stack_new_interface_create Test..................... ERROR #8\n"); + test_control_return(1); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx demo slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_host_stack_new_interface_create Test..................... ERROR #9\n"); + test_control_return(1); + } +} + + +static void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_DEVICE *device; + + /* Inform user. */ + printf("Running ux_host_stack_new_interface_create Test..................... "); + + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait connect. */ + tx_thread_sleep(100); + if (cdc_acm_host_control == UX_NULL || cdc_acm_host_data == UX_NULL || cdc_acm_slave == UX_NULL) + { + + printf("ERROR #%d: connection not detected\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: fail to get device instance\n", __LINE__); + test_control_return(1); + } + + /* Simulate interface descriptor corruption. */ + + /* Header Functional Descriptor corrupted. */ + + /* Disconnect. */ + ux_test_hcd_sim_host_disconnect(); + + /* Modify descriptor and expect error (descriptor length too small). */ + device_framework_full_speed[44] = 0; /* bLength: 5 -> 0 */ + test_error_cases = UX_TRUE; + test_error_counter = 0; + /* Connect. */ + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + tx_thread_sleep(50); + if (!test_error_counter) + { + + printf("ERROR #%d: expect error but not happen\n", __LINE__); + error_counter ++; + } + device_framework_full_speed[44] = 5; + + /* Disconnect. */ + ux_test_hcd_sim_host_disconnect(); + + /* Modify descriptor and expect error (last descriptor length too large). */ + device_framework_full_speed[86] = 9; /* bLength: 7 -> 9 */ + test_error_cases = UX_TRUE; + test_error_counter = 0; + /* Connect. */ + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + tx_thread_sleep(50); + if (!test_error_counter) + { + + printf("ERROR #%d: expect error but not happen\n", __LINE__); + error_counter ++; + } + device_framework_full_speed[86] = 7; + + /* Disconnect. */ + ux_test_hcd_sim_host_disconnect(); + + /* Modify descriptor and expect error. */ + device_framework_full_speed[64] = 0; /* bType: 5 -> 0 */ + test_error_cases = UX_TRUE; + test_error_counter = 0; + /* Connect. */ + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + tx_thread_sleep(50); + if (!test_error_counter) + { + + printf("ERROR #%d: expect error but not happen\n", __LINE__); + error_counter ++; + } + device_framework_full_speed[64] = 5; + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* DPUMP error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + + +static void tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Ensure the dpump class on the device is still alive. */ + if (cdc_acm_slave != UX_NULL) + { + + /* Increment thread counter. */ + thread_1_counter++; + } + + /* Let other thread run. */ + tx_thread_sleep(10); + } +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} + +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + detect_insertion = UX_TRUE; + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + detect_extraction = UX_TRUE; + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + + default: + break; + } + return UX_SUCCESS; +} \ No newline at end of file diff --git a/test/regression/usbx_ux_host_stack_rh_change_process_test.c b/test/regression/usbx_ux_host_stack_rh_change_process_test.c new file mode 100644 index 00000000..ae24d084 --- /dev/null +++ b/test/regression/usbx_ux_host_stack_rh_change_process_test.c @@ -0,0 +1,588 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_device_stack.h" +#include "ux_host_stack.h" + +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +/* Define USBX demo constants. */ + +#define UX_DEMO_STACK_SIZE 4096 +#define UX_DEMO_BUFFER_SIZE 2048 +#define UX_DEMO_RUN 1 +#define UX_DEMO_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the demo application... */ + +static ULONG test_error_cases = UX_FALSE; + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +/* Define USBX demo global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_control; +static UX_HOST_CLASS_CDC_ACM *cdc_acm_host_data; +static UX_SLAVE_CLASS_CDC_ACM *cdc_acm_slave; +static UX_SLAVE_CLASS_CDC_ACM_PARAMETER cdc_acm_parameter; + +static UCHAR detect_insertion; +static UCHAR detect_extraction; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x10, 0x01, + 0xEF, 0x02, 0x01, + 0x08, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Configuration 1 descriptor 9 bytes */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. 8 bytes. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement. 9 bytes. */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor 4 bytes */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x06, + 0x00, /* Master interface */ + 0x01, /* Slave interface */ + + /* Call Management Functional Descriptor 5 bytes */ + 0x05, 0x24, 0x01, + 0x03, + 0x01, /* Data interface */ + + /* Endpoint 0x83 descriptor 7 bytes */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement 9 bytes */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor 7 bytes */ + 0x07, 0x05, 0x02, /* @ 93 - 14 + 2 = 81 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor 7 bytes */ + 0x07, 0x05, 0x81, /* @ 93 - 7 + 2 = 88 */ + 0x02, + 0x40, 0x00, + 0x00, +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor + 0x02 bDeviceClass: CDC class code + 0x00 bDeviceSubclass: CDC class sub code + 0x00 bDeviceProtocol: CDC Device protocol + + idVendor & idProduct - http://www.linux-usb.org/usb.ids + */ + 0x12, 0x01, 0x00, 0x02, + 0xEF, 0x02, 0x01, + 0x40, + 0x84, 0x84, 0x00, 0x00, + 0x00, 0x01, + 0x01, 0x02, 03, + 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x02, 0x00, 0x00, + 0x40, + 0x01, + 0x00, + + /* Configuration 1 descriptor */ + 0x09, 0x02, 0x4b, 0x00, + 0x02, 0x01, 0x00, + 0x40, 0x00, + + /* Interface association descriptor. */ + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + + /* Communication Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x00, + 0x00, + 0x01, + 0x02, 0x02, 0x01, + 0x00, + + /* Header Functional Descriptor */ + 0x05, 0x24, 0x00, + 0x10, 0x01, + + /* ACM Functional Descriptor */ + 0x04, 0x24, 0x02, + 0x0f, + + /* Union Functional Descriptor */ + 0x05, 0x24, 0x06, + 0x00, + 0x01, + + /* Call Management Functional Descriptor */ + 0x05, 0x24, 0x01, + 0x00, + 0x01, + + /* Endpoint 0x83 descriptor */ + 0x07, 0x05, 0x83, + 0x03, + 0x08, 0x00, + 0xFF, + + /* Data Class Interface Descriptor Requirement */ + 0x09, 0x04, 0x01, + 0x00, + 0x02, + 0x0A, 0x00, 0x00, + 0x00, + + /* Endpoint 0x02 descriptor */ + 0x07, 0x05, 0x02, /* @ 103 - 14 + 2 = 91 */ + 0x02, + 0x40, 0x00, + 0x00, + + /* Endpoint 0x81 descriptor */ + 0x07, 0x05, 0x81, /* @ 103 - 7 + 2 = 98 */ + 0x02, + 0x40, 0x00, + 0x00, +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID test_cdc_instance_activate(VOID *cdc_instance); +static VOID test_cdc_instance_deactivate(VOID *cdc_instance); + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst); + +UINT ux_hcd_sim_initialize(UX_HCD *hcd); + +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static void tx_test_thread_host_simulation_entry(ULONG); +static void tx_test_thread_slave_simulation_entry(ULONG); + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + if (!test_error_cases) + { +#ifdef UX_DEVICE_CLASS_CDC_ACM_TRANSMISSION_DISABLE + /* Generated on device deactivation. */ + if (error_code == UX_FUNCTION_NOT_SUPPORTED) + return; +#endif + printf("Error on line %d, system_level: %d, system_context: %d, error code: 0x%x\n", __LINE__, system_level, system_context, error_code); + 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_stack_rh_change_process_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; + + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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("Running ux_host_stack_rh_change_process Test........................ ERROR #1\n"); + 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_host_change_function); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_rh_change_process Test........................ ERROR #2\n"); + test_control_return(1); + } + + /* Register CDC-ACM class. */ + status = ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_rh_change_process Test........................ ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_rh_change_process Test........................ ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a CDC device. */ + cdc_acm_parameter.ux_slave_class_cdc_acm_instance_activate = test_cdc_instance_activate; + cdc_acm_parameter.ux_slave_class_cdc_acm_instance_deactivate = test_cdc_instance_deactivate; + cdc_acm_parameter.ux_slave_class_cdc_acm_parameter_change = UX_NULL; + + /* Initialize the device cdc class. This class owns both interfaces starting with 0. */ + status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry, + 1,0, &cdc_acm_parameter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_rh_change_process Test........................ ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_rh_change_process Test........................ ERROR #7\n"); + test_control_return(1); + } + +#if UX_MAX_HCD > 1 + 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 %x: 0x%x\n", __LINE__, status); + test_control_return(1); + } +#endif + + /* 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,1,0); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_rh_change_process Test........................ ERROR #4\n"); + test_control_return(1); + } + + /* Create the main host simulation thread. */ + status = tx_thread_create(&tx_test_thread_host_simulation, "tx demo host simulation", tx_test_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("Running ux_host_stack_rh_change_process Test........................ ERROR #8\n"); + test_control_return(1); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_test_thread_slave_simulation, "tx demo slave simulation", tx_test_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_host_stack_rh_change_process Test........................ ERROR #9\n"); + test_control_return(1); + } +} + + +static void tx_test_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HCD *hcd; +UX_DEVICE *device; + + /* Inform user. */ + printf("Running ux_host_stack_rh_change_process Test........................ "); + + ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE); + + /* Wait connect. */ + tx_thread_sleep(100); + if (cdc_acm_host_control == UX_NULL || cdc_acm_host_data == UX_NULL || cdc_acm_slave == UX_NULL) + { + + printf("ERROR #%d: connection not detected\n", __LINE__); + test_control_return(1); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: fail to get device instance\n", __LINE__); + test_control_return(1); + } + +#if UX_MAX_HCD > 1 + /* Unregister first registered HCD. */ + test_error_cases = UX_TRUE; + ux_host_stack_hcd_unregister(_ux_system_host_hcd_simulator_name, 0, 0); + + /* Simulate multiple RH signals. */ + hcd = &_ux_system_host -> ux_system_host_hcd_array[1]; + hcd->ux_hcd_root_hub_signal[0] ++; + hcd->ux_hcd_root_hub_signal[0] ++; +#else + + /* Simulate multiple RH signals. */ + hcd = &_ux_system_host -> ux_system_host_hcd_array[0]; + hcd->ux_hcd_root_hub_signal[0] ++; + hcd->ux_hcd_root_hub_signal[0] ++; +#endif + + /* Reset detects. */ + detect_insertion = UX_FALSE; + detect_extraction = UX_FALSE; + /* Trigger enumeration. */ + _ux_utility_semaphore_put(&_ux_system_host -> ux_system_host_enum_semaphore); + /* Wait enough time for enumeration done. */ + tx_thread_sleep(200); + /* Expects extraction and insertion. */ + if (!detect_extraction) + { + + printf("ERROR #%d: fail to detect extraction\n", __LINE__); + error_counter ++; + } + if (!detect_insertion) + { + + printf("ERROR #%d: fail to detect insertion\n", __LINE__); + error_counter ++; + } + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* DPUMP error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + + +static void tx_test_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Ensure the dpump class on the device is still alive. */ + if (cdc_acm_slave != UX_NULL) + { + + /* Increment thread counter. */ + thread_1_counter++; + } + + /* Let other thread run. */ + tx_thread_sleep(10); + } +} + +static VOID test_cdc_instance_activate(VOID *cdc_instance) +{ + + /* Save the CDC instance. */ + cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance; +} + +static VOID test_cdc_instance_deactivate(VOID *cdc_instance) +{ + + /* Reset the CDC instance. */ + cdc_acm_slave = UX_NULL; +} + +static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ +UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst; + + switch(event) + { + + case UX_DEVICE_INSERTION: + + detect_insertion = UX_TRUE; + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = cdc_acm; + else + cdc_acm_host_data = cdc_acm; + break; + + case UX_DEVICE_REMOVAL: + + detect_extraction = UX_TRUE; + + if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS) + cdc_acm_host_control = UX_NULL; + else + cdc_acm_host_data = UX_NULL; + break; + + default: + break; + } + return UX_SUCCESS; +} \ No newline at end of file diff --git a/test/regression/usbx_ux_host_stack_rh_device_insertion_test.c b/test/regression/usbx_ux_host_stack_rh_device_insertion_test.c new file mode 100644 index 00000000..7c7b923e --- /dev/null +++ b/test/regression/usbx_ux_host_stack_rh_device_insertion_test.c @@ -0,0 +1,548 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_stack.h" + +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + +/* Define USBX demo constants. */ + +#define UX_DEMO_STACK_SIZE 4096 +#define UX_DEMO_BUFFER_SIZE 2048 +#define UX_DEMO_RUN 1 +#define UX_DEMO_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the demo application... */ + +static ULONG test_error_cases = UX_FALSE; + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +/* Define USBX demo global variables. */ + +static unsigned char host_out_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; +static unsigned char host_in_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; +static unsigned char slave_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE]; + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave; + + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x08, /* bMaxPacketSize0 */ + 0xec, 0x08, 0x10, 0x00, /* idVendor, idProduct */ + 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x01, /* bNumConfigurations */ + + /* Configuration descriptor */ + 0x09, 0x02, + 0x20, 0x00, /* wTotalLength */ + 0x01, 0x01, /* bNumInterfaces, bConfigurationValue */ + 0x00, + 0xc0, 0x32, /* bmAttributes, bMaxPower */ + + /* Interface descriptor */ + 0x09, 0x04, + 0x00, 0x00, 0x02, /* bInterfaceNumber, bAlternateSetting, bNumEndpoints */ + 0x99, 0x99, 0x99, /* bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00 +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 */ + 0x0a, 0x07, /* idVendor */ + 0x25, 0x40, /* idProduct */ + 0x01, 0x00, + 0x01, 0x02, 0x03, + 0x01, /* bNumConfigurations */ + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, + 0x00, 0x00, 0x00, /* bDeviceClass, bDeviceSubClass, bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 */ + 0x01, /* bNumConfigurations */ + 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00 +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID tx_demo_instance_activate(VOID *dpump_instance); +static VOID tx_demo_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); +static void tx_demo_thread_slave_simulation_entry(ULONG); + +/* Action simulator */ + +static UX_TEST_HCD_SIM_ACTION enable_port_error[] = { +/* 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_ENABLE_PORT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_PORT_INDEX_UNKNOWN}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION reset_port_error[] = { +/* 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_RESET_PORT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_PORT_INDEX_UNKNOWN}, +{ UX_HCD_RESET_PORT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_PORT_INDEX_UNKNOWN}, +{ UX_HCD_RESET_PORT, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_PORT_INDEX_UNKNOWN}, +{ 0 } +}; + +static UX_TEST_HCD_SIM_ACTION get_port_status_error[] = { +/* 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_GET_PORT_STATUS, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_PORT_INDEX_UNKNOWN}, +{ UX_HCD_GET_PORT_STATUS, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_PORT_INDEX_UNKNOWN}, +{ UX_HCD_GET_PORT_STATUS, NULL, + UX_FALSE, 0, + 0 , 0, UX_NULL, 0, 0, + UX_PORT_INDEX_UNKNOWN}, +{ 0 } +}; + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + + /* Failed test. */ + if (!test_error_cases) + { + + printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code); + 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_stack_rh_device_insertion_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; + + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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("Running ux_host_stack_rh_device_insertion Test...................... ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_rh_device_insertion Test...................... ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, _ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_rh_device_insertion Test...................... ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_rh_device_insertion Test...................... ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = tx_demo_instance_activate; + parameter.ux_slave_class_dpump_instance_deactivate = tx_demo_instance_deactivate; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_rh_device_insertion Test...................... ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_rh_device_insertion Test...................... ERROR #7\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_rh_device_insertion Test...................... ERROR #4\n"); + 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("Running ux_host_stack_rh_device_insertion Test...................... ERROR #8\n"); + test_control_return(1); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_host_stack_rh_device_insertion Test...................... ERROR #9\n"); + test_control_return(1); + } +} + + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ + +UINT status; +UX_HCD *hcd; +UX_HOST_CLASS *class; +UX_DEVICE *device; +ULONG temp; + + /* Inform user. */ + printf("Running ux_host_stack_rh_device_insertion Test...................... "); + + /* Find the main data pump container. */ + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + /* DPUMP basic test error. */ + printf("ERROR #10\n"); + test_control_return(1); + } + + /* We get the first instance of the data pump device. */ + do + { + + status = ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump); + tx_thread_relinquish(); + } while (status != UX_SUCCESS); + + /* We still need to wait for the data pump status to be live. */ + while (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + { + + tx_thread_relinquish(); + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: fail to get device instance\n", __LINE__); + test_control_return(1); + } + + /* Wait until no enumeration in progress. */ + tx_thread_sleep(100); + + /* Simulate _ux_host_stack_rh_device_insertion error cases. */ + + /* Get HCD instance. */ + hcd = &_ux_system_host -> ux_system_host_hcd_array[0]; + + /* Test error. */ + test_error_cases = UX_TRUE; + + /* Simulate error: enable port. */ + ux_test_hcd_sim_host_set_actions(enable_port_error); + status = _ux_host_stack_rh_device_insertion(hcd, 0); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: Expects error (enable port)\n", __LINE__); + error_counter ++; + } + + /* Simulate error: reset port. */ + ux_test_hcd_sim_host_set_actions(reset_port_error); + status = _ux_host_stack_rh_device_insertion(hcd, 0); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: Expects error (reset port)\n", __LINE__); + error_counter ++; + } + + /* Simulate error: get port status. */ + ux_test_hcd_sim_host_set_actions(get_port_status_error); + status = _ux_host_stack_rh_device_insertion(hcd, 0); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: Expects error (get port status)\n", __LINE__); + error_counter ++; + } + ux_test_hcd_sim_host_set_actions(UX_NULL); + +#if UX_MAX_DEVICES > 1 + /* Simulate error: too many devices. */ + temp = _ux_system_host -> ux_system_host_max_devices; + _ux_system_host -> ux_system_host_max_devices = 1; + status = _ux_host_stack_rh_device_insertion(hcd, 0); + if (status != UX_DEVICE_ENUMERATION_FAILURE) + { + + printf("ERROR #%d: %x\n", __LINE__, status); + error_counter ++; + } + + /* Restore. */ + _ux_system_host -> ux_system_host_max_devices = temp; +#endif + + /* Stop test error. */ + test_error_cases = UX_FALSE; + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* DPUMP error. */ + printf("ERROR #14\n"); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + + +static void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + + while(1) + { + + /* Ensure the dpump class on the device is still alive. */ + if (dpump_slave != UX_NULL) + { + + /* Increment thread counter. */ + thread_1_counter++; + } + + /* Let other thread run. */ + tx_thread_sleep(10); + } +} + +static VOID tx_demo_instance_activate(VOID *dpump_instance) +{ + + /* Save the DPUMP instance. */ + dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance; +} + +static VOID tx_demo_instance_deactivate(VOID *dpump_instance) +{ + + /* Reset the DPUMP instance. */ + dpump_slave = UX_NULL; +} + diff --git a/test/regression/usbx_ux_host_stack_transfer_request_abort_test.c b/test/regression/usbx_ux_host_stack_transfer_request_abort_test.c new file mode 100644 index 00000000..a62af87c --- /dev/null +++ b/test/regression/usbx_ux_host_stack_transfer_request_abort_test.c @@ -0,0 +1,489 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_host_class_dummy.h" +#include "ux_device_class_dummy.h" +#include "ux_test.h" + + +/* Define USBX demo constants. */ + +#define UX_DEMO_STACK_SIZE 4096 +#define UX_DEMO_BUFFER_SIZE 2048 +#define UX_DEMO_RUN 1 +#define UX_DEMO_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the demo application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + + +/* Define USBX demo global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DUMMY *dummy; +static UX_TRANSFER *dummy_transfer; +static UX_DEVICE_CLASS_DUMMY *dummy_slave; + +static UINT expected_error; + +#define _W0(w) ( (w) & 0xFF) +#define _W1(w) (((w) >> 8) & 0xFF) + +#define _DEVICE_DESCRIPTOR(cls, sub, protocol, pktsize, vid, pid, n_cfg) \ + 0x12, 0x01, 0x10, 0x01, \ + (cls), (sub), (protocol), (pktsize), \ + _W0(vid), _W1(vid), _W0(pid), _W1(pid), \ + 0x00, 0x00, 0x00, 0x00, 0x00, (n_cfg), + +#define _QUALIFIER_DESCRIPTOR(cls, sub, protocol, n_cfg) \ + 0x0a, 0x06, 0x00, 0x02, \ + (cls), (sub), (protocol), 0x40, (n_cfg), 0x00, + +#define _CONFIGURATION_DESCRIPTOR(total_len, n_ifc, cfg_val) \ + 0x09, 0x02, _W0(total_len), _W1(total_len), (n_ifc), (cfg_val), \ + 0x00, 0xc0, 0x32, + +#define _INTERFACE_DESCRIPTOR(ifc_n, alt, n_ep, cls, sub, protocol) \ + 0x09, 0x04, (ifc_n), (alt), (n_ep), (cls), (sub), (protocol), 0x00, + +#define _ENDPOINT_DESCRIPTOR(addr, attr, pktsize, interval) \ + 0x07, 0x05, (addr), (attr), _W0(pktsize), _W1(pktsize), (interval), + +#define _CONFIGURATION_TOTAL_LENGTH (9+9+2*7) +#define _CONFIGURATION_DESCRIPTORS(hs) \ + _CONFIGURATION_DESCRIPTOR(_CONFIGURATION_TOTAL_LENGTH, 1, 1) \ + _INTERFACE_DESCRIPTOR(0, 0, 2, 0x99, 0x99, 0x99) \ + _ENDPOINT_DESCRIPTOR(0x01, 0x02, (hs) ? 512 : 64, 0x00) \ + _ENDPOINT_DESCRIPTOR(0x82, 0x02, (hs) ? 512 : 64, 0x00) + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +static UCHAR device_framework_full_speed[] = { + _DEVICE_DESCRIPTOR(0x00, 0x00, 0x00, 8, 0x08EC, 0x0001, 1) + _CONFIGURATION_DESCRIPTORS(0) +}; + + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) +static UCHAR device_framework_high_speed[] = { + _DEVICE_DESCRIPTOR(0x00, 0x00, 0x00, 64, 0x08EC, 0x0001, 1) + _QUALIFIER_DESCRIPTOR(0, 0, 0, 1) + _CONFIGURATION_DESCRIPTORS(1) +}; + +/* 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 sizeof(string_framework) +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* 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 sizeof(language_id_framework) +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID tx_demo_instance_activate(VOID *dummy_instance); +static VOID tx_demo_instance_deactivate(VOID *dummy_instance); +static VOID tx_demo_instance_change(UX_DEVICE_CLASS_DUMMY *dummy_instance); + +#if defined(UX_HOST_STANDALONE) +static UINT tx_demo_host_change_function(ULONG e, UX_HOST_CLASS *c, VOID *p); +#else +#define tx_demo_host_change_function UX_NULL +#endif + +UINT ux_hcd_sim_initialize(UX_HCD *hcd); + +static TX_THREAD tx_demo_thread_host_simulation; +static TX_THREAD tx_demo_thread_slave_simulation; +static void tx_demo_thread_host_simulation_entry(ULONG); +static void tx_demo_thread_slave_simulation_entry(ULONG); + +static TX_THREAD test_thread; +static void test_thread_entry(ULONG); +static TX_SEMAPHORE test_start_sem; +static TX_SEMAPHORE test_end_sem; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + if (expected_error == 0 || error_code != expected_error) + { + /* Failed test. */ + printf("Error on line %d, system_level: %d, system_context: %d, error code: %x\n", __LINE__, system_level, system_context, error_code); + // 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_stack_transfer_request_abort_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_DEVICE_CLASS_DUMMY_PARAMETER parameter; + + + printf("Running ux_host_stack_transfer_request_abort Test................... "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_memory; + memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 3); + + /* 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 #%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(tx_demo_host_change_function); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_host_class_dummy_name, _ux_host_class_dummy_entry); + + /* Check for error. */ + 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 */ + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + _ux_utility_memory_set((void *)¶meter, 0x00, sizeof(parameter)); + parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_instance_activate = tx_demo_instance_activate; + parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_instance_deactivate = tx_demo_instance_deactivate; + parameter.ux_device_class_dummy_parameter_callbacks.ux_device_class_dummy_change = tx_demo_instance_change; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_device_class_dummy_name, _ux_device_class_dummy_entry, + 1, 0, ¶meter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%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 #%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 #%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 #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the main demo thread. */ + status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the test thread. */ + status = tx_thread_create(&test_thread, "test thread", test_thread_entry, 0, + stack_pointer + UX_DEMO_STACK_SIZE * 2, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +static UINT ux_demo_dummy_instance_check(VOID) +{ +UINT status; +UX_HOST_CLASS *cls; + status = ux_host_stack_class_get(_ux_host_class_dummy_name, &cls); + if (status != UX_SUCCESS) + return(status); + status = ux_host_stack_class_instance_get(cls, 0, (VOID **) &dummy); + if (status != UX_SUCCESS) + return(status); + if (dummy -> ux_host_class_dummy_state != UX_HOST_CLASS_INSTANCE_LIVE) + return(UX_NO_CLASS_MATCH); + return(UX_SUCCESS); +} + +static UINT ux_demo_dummy_instance_connect_wait(ULONG wait_ticks) +{ +ULONG t0 = tx_time_get(), t1; + while(1) + { +#if defined(UX_HOST_STANDALONE) + ux_system_tasks_run(); +#endif + if (UX_SUCCESS == ux_demo_dummy_instance_check()) + return(UX_SUCCESS); + tx_thread_relinquish(); + + /* Wait forever. */ + if (wait_ticks == 0xFFFFFFFFul) + continue; + + /* No wait. */ + if (wait_ticks == 0) + break; + + /* Check timeout. */ + t1 = tx_time_get(); + if (t1 >= t0) + t1 = t1 - t0; + else + t1 = 0xFFFFFFFFul - t0 + t1; + if (t1 > wait_ticks) + break; + } + return(UX_ERROR); +} + +static void tx_demo_thread_host_simulation_entry(ULONG arg) +{ +UINT status; +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +UCHAR buffer[64]; + + stepinfo(">>>> Dummy Class Connection Wait\n"); + status = ux_demo_dummy_instance_connect_wait(1000); + if (status != UX_SUCCESS) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + stepinfo(">>>> Dummy Class Transfer Abort Test\n"); + dummy_transfer = _ux_host_class_dummy_get_transfer_request(dummy, 0x82, 0); + UX_TEST_ASSERT(dummy_transfer != UX_NULL); + dummy_transfer -> ux_transfer_request_requested_length = 64; + dummy_transfer -> ux_transfer_request_data_pointer = buffer; + + tx_semaphore_put(&test_start_sem); + + status = tx_semaphore_get(&test_end_sem, 2); + UX_TEST_ASSERT(status != TX_SUCCESS); + + status = ux_host_stack_transfer_request_abort(dummy_transfer); + UX_TEST_CHECK_SUCCESS(status); + + status = tx_semaphore_get(&test_end_sem, 100); + UX_TEST_ASSERT(status == TX_SUCCESS); + + status = ux_host_stack_transfer_request_abort(dummy_transfer); + UX_TEST_CHECK_SUCCESS(status); + + expected_error = 0; + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* DPUMP error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + + +static void tx_demo_thread_slave_simulation_entry(ULONG arg) +{ + +UINT status; +ULONG actual_length; + + + while(1) + { +#if defined(UX_DEVICE_STANDALONE) + + /* Run device tasks. */ + ux_system_tasks_run(); +#endif + /* Increment thread counter. */ + thread_1_counter++; + + /* Relinquish to other thread. */ + tx_thread_relinquish(); + } +} + +static void test_thread_entry(ULONG arg) +{ +UINT status; + + tx_semaphore_create(&test_start_sem, "Test Start SEM", 0); + tx_semaphore_create(&test_end_sem, "Test End SEM", 0); + while(1) + { + tx_semaphore_get(&test_start_sem, TX_WAIT_FOREVER); + status = ux_host_stack_transfer_request(dummy_transfer); + UX_TEST_CHECK_SUCCESS(status); + _ux_host_semaphore_get(&dummy_transfer->ux_transfer_request_semaphore, UX_WAIT_FOREVER); + tx_semaphore_put(&test_end_sem); + } +} + +static VOID tx_demo_instance_activate(VOID *inst) +{ + dummy_slave = (UX_DEVICE_CLASS_DUMMY *)inst; +} + +static VOID tx_demo_instance_deactivate(VOID *inst) +{ + dummy_slave = UX_NULL; +} + +static VOID tx_demo_instance_change(UX_DEVICE_CLASS_DUMMY *dummy) +{ + UX_PARAMETER_NOT_USED(dummy); +} + +#if defined(UX_HOST_STANDALONE) +static UINT tx_demo_host_change_function(ULONG e, UX_HOST_CLASS *c, VOID *p) +{ + if (e == UX_STANDALONE_WAIT_BACKGROUND_TASK) + { + tx_thread_relinquish(); + } +} +#endif diff --git a/test/regression/usbx_ux_host_stack_transfer_request_test.c b/test/regression/usbx_ux_host_stack_transfer_request_test.c new file mode 100644 index 00000000..4d934c6e --- /dev/null +++ b/test/regression/usbx_ux_host_stack_transfer_request_test.c @@ -0,0 +1,671 @@ +/* This test is designed to test the ux_host_stack_transfer_request. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors. */ +#define DPUMP_IFC_DESC(ifc, alt, nb_ep) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), (alt), (nb_ep), 0x99, 0x99, 0x99, 0x00, + +#define DPUMP_IFC_EP_DESC(epaddr, eptype, epsize) \ + /* Endpoint descriptor */\ + 0x07, 0x05, (epaddr), (eptype), LSB(epsize), MSB(epsize), 0x01, + +#define DPUMP_IFC_DESC_ALL_LEN(nb_ep) (9 + (nb_ep) * 7) + +#define CFG_DESC_ALL_LEN (CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN(4)) + +#define CFG_DESC_ALL \ + CFG_DESC(CFG_DESC_ALL_LEN, 1, 1)\ + DPUMP_IFC_DESC(0, 0, 4)\ + DPUMP_IFC_EP_DESC(0x81, 2, 64)\ + DPUMP_IFC_EP_DESC(0x02, 2, 64)\ + DPUMP_IFC_EP_DESC(0x83, 1, 64)\ + DPUMP_IFC_EP_DESC(0x84, 3, 64)\ + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +static UCHAR thread_1_state; + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC_ALL +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC_ALL +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +/* Simulator actions. */ + +static UX_TEST_HCD_SIM_ACTION endpoint0x83_create_del_skip[] = { +/* 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_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x83, UX_NULL, 0, 0, + UX_SUCCESS}, +{ UX_HCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x83, UX_NULL, 0, 0, + UX_SUCCESS}, +{ 0 } +}; + +static VOID test_action_abort(UX_TEST_ACTION *action, VOID *params) +{ + + ux_host_stack_transfer_request_abort(&dpump->ux_host_class_dpump_bulk_in_endpoint->ux_endpoint_transfer_request); +} + +static UX_TEST_HCD_SIM_ACTION preempt_abort_on_abort[] = { +/* 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_ABORT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x81, UX_NULL, 0, 0, + UX_SUCCESS, test_action_abort, + UX_TRUE}, +{ 0 } +}; + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 break_on_dpump_ready(VOID) +{ + +UINT status; +UX_HOST_CLASS *class; + + /* Find the main data pump container. */ + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class); + if (status != UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + /* Find the instance. */ + status = ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump); + if (status != UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + if (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + + +static UINT test_ux_device_class_dpump_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + switch(command->ux_slave_class_command_request) + { + case UX_SLAVE_CLASS_COMMAND_INITIALIZE: + case UX_SLAVE_CLASS_COMMAND_QUERY: + case UX_SLAVE_CLASS_COMMAND_CHANGE: + return UX_SUCCESS; + + default: + return UX_NO_CLASS_MATCH; + } +} + +static UINT test_ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command) +{ + switch (command -> ux_host_class_command_request) + { + case UX_HOST_CLASS_COMMAND_QUERY: + default: + return _ux_host_class_dpump_entry(command); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_stack_transfer_request_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +UX_SLAVE_CLASS_DPUMP_PARAMETER parameter; + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_transfer_request Test......................... ERROR #1\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_transfer_request Test......................... ERROR #2\n"); + test_control_return(1); + } + + /* Register all the host class drivers for this USBX implementation. */ + status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, test_ux_host_class_dpump_entry); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_transfer_request Test......................... ERROR #3\n"); + test_control_return(1); + } + + /* The code below is required for installing the device portion of USBX */ + status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, + device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, + string_framework, STRING_FRAMEWORK_LENGTH, + language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_transfer_request Test......................... ERROR #5\n"); + test_control_return(1); + } + + /* Set the parameters for callback when insertion/extraction of a Data Pump device. */ + parameter.ux_slave_class_dpump_instance_activate = UX_NULL; + parameter.ux_slave_class_dpump_instance_deactivate = UX_NULL; + + /* Initialize the device dpump class. The class is connected with interface 0 */ + status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, test_ux_device_class_dpump_entry, + 1, 0, ¶meter); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_transfer_request Test......................... ERROR #6\n"); + test_control_return(1); + } + + /* Initialize the simulated device controller. */ + status = _ux_test_dcd_sim_slave_initialize(); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_transfer_request Test......................... ERROR #7\n"); + 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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("Running ux_host_stack_transfer_request Test......................... ERROR #4\n"); + test_control_return(1); + } + + /* Create the main simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation 0", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_host_stack_transfer_request Test......................... ERROR #8\n"); + test_control_return(1); + } + + /* Create the test simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_1, "test simulation 1", ux_test_thread_simulation_1_entry, 0, + stack_pointer + UX_TEST_STACK_SIZE, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_NO_ACTIVATE); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("Running ux_host_stack_transfer_request Test......................... ERROR #8\n"); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ +UINT status; +UX_DEVICE *device; +UX_ENDPOINT *control_endpoint; +UX_TRANSFER *transfer_request; +INT i; + + /* Inform user. */ + printf("Running ux_host_stack_transfer_request Test......................... "); + + /* Skip ISO EP create/delete. */ + ux_test_hcd_sim_host_set_actions(endpoint0x83_create_del_skip); + + /* Connect. */ + ux_test_hcd_sim_host_connect(UX_HIGH_SPEED_DEVICE); + ux_test_breakable_sleep(100, break_on_dpump_ready); + + if (dpump == UX_NULL || dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + { + + printf("ERROR #%d: dpump not ready\n", __LINE__); + error_counter ++; + } + + status = ux_host_stack_device_get(0, &device); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: device_get fail\n", __LINE__); + test_control_return(1); + } + control_endpoint = &device->ux_device_control_endpoint; + transfer_request = &control_endpoint->ux_endpoint_transfer_request; + + /* Send transfer request when device is not addressed. */ + + transfer_request -> ux_transfer_request_data_pointer = buffer; + transfer_request -> ux_transfer_request_requested_length = 64; + transfer_request -> ux_transfer_request_index = 0; + + /* SetAddress(0). */ + transfer_request -> ux_transfer_request_function = UX_SET_ADDRESS; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = 0; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: SetAddress(0) code 0x%x\n", __LINE__, status); + test_control_return(1); + } + device->ux_device_state = UX_DEVICE_ATTACHED; + + /* GetDeviceDescriptor. */ + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = UX_DEVICE_DESCRIPTOR_ITEM << 8; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: GetDeviceDescriptor() code 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* SetAddress(x). */ + transfer_request -> ux_transfer_request_function = UX_SET_ADDRESS; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = device->ux_device_address; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: SetAddress(x) code 0x%x\n", __LINE__, status); + test_control_return(1); + } + device->ux_device_state = UX_DEVICE_ADDRESSED; + + /* SetConfigure(1). */ + transfer_request -> ux_transfer_request_function = UX_SET_CONFIGURATION; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = 1; + status = ux_host_stack_transfer_request(transfer_request); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: SetConfigure(1) code 0x%x\n", __LINE__, status); + test_control_return(1); + } + device->ux_device_state = UX_DEVICE_CONFIGURED; + + /* Simulate semaphore error. */ + ux_test_utility_sim_sem_get_error_generation_start(0); + /* GetDeviceDescriptor. */ + transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE; + transfer_request -> ux_transfer_request_value = UX_DEVICE_DESCRIPTOR_ITEM << 8; + status = ux_host_stack_transfer_request(transfer_request); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: GetDeviceDescriptor() code 0x%x\n", __LINE__, status); + test_control_return(1); + } + ux_test_utility_sim_sem_get_error_generation_stop(); + + /* Start transfer in another thread and abort it. */ + thread_1_state = 0; + + tx_thread_resume(&ux_test_thread_simulation_1); + for (i = 0; i < 20; i ++) + { + if (thread_1_state > 0) + break; + tx_thread_sleep(1); + } + if (thread_1_state == 0) + { + printf("ERROR #%d: fail to resume thread\n", __LINE__); + test_control_return(1); + } + + /* Transfer started, check if it's pending. */ + for (i = 0; i < 20; i ++) + { + if (thread_1_state > 1) + break; + tx_thread_sleep(1); + } + if (thread_1_state > 1) + { + printf("ERROR #%d: thread not pending\n", __LINE__); + test_control_return(1); + } + if (dpump->ux_host_class_dpump_bulk_in_endpoint->ux_endpoint_transfer_request.ux_transfer_request_completion_code != UX_TRANSFER_STATUS_PENDING) + { + printf("ERROR #%d: transfer request status not UX_TRANSFER_STATUS_PENDING but 0x%x\n", __LINE__, dpump->ux_host_class_dpump_bulk_in_endpoint->ux_endpoint_transfer_request.ux_transfer_request_completion_code); + error_counter ++; + } + + /* Abort it. */ + status = ux_host_stack_transfer_request_abort(&dpump->ux_host_class_dpump_bulk_in_endpoint->ux_endpoint_transfer_request); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: abort error\n", __LINE__); + error_counter ++; + } + else + { + for (i = 0; i < 20; i ++) + { + if (thread_1_state > 1) + break; + tx_thread_sleep(1); + } + if (thread_1_state == 0) + { + printf("ERROR #%d: thread not progressing\n", __LINE__); + error_counter ++; + } + } + + /* Disconnect on transfer abort. */ + ux_test_hcd_sim_host_set_actions(preempt_abort_on_abort); + thread_1_state = 0; + tx_thread_resume(&ux_test_thread_simulation_1); + for (i = 0; i < 20; i ++) + { + if (thread_1_state > 0) + break; + tx_thread_sleep(1); + } + status = ux_host_stack_transfer_request_abort(&dpump->ux_host_class_dpump_bulk_in_endpoint->ux_endpoint_transfer_request); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: abort error\n", __LINE__); + error_counter ++; + } + + /* Disconnect. */ + ux_test_hcd_sim_host_disconnect(); + ux_test_breakable_sleep(100, break_on_removal); + + /* Simulate transfer request when device is disconnected. */ + status = ux_host_stack_transfer_request(transfer_request); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: GetDeviceDescriptor() should fail\n", __LINE__); + test_control_return(1); + } + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static void ux_test_thread_simulation_1_entry(ULONG arg) +{ +UINT status; +ULONG actual_length; + + while(1) + { + thread_1_state ++; + + /* Start transfer. */ + status = ux_host_class_dpump_read(dpump, buffer, 128, &actual_length); + + thread_1_state ++; + + if (dpump->ux_host_class_dpump_bulk_in_endpoint->ux_endpoint_transfer_request.ux_transfer_request_completion_code != UX_TRANSFER_STATUS_ABORT) + { + printf("ERROR #%d: expect UX_TRANSFER_STATUS_ABORT but got 0x%x\n", __LINE__, dpump->ux_host_class_dpump_bulk_in_endpoint->ux_endpoint_transfer_request.ux_transfer_request_completion_code); + error_counter ++; + } + + tx_thread_suspend(&ux_test_thread_simulation_1); + } +} \ No newline at end of file diff --git a/test/regression/usbx_ux_host_stack_uninitialize_test.c b/test/regression/usbx_ux_host_stack_uninitialize_test.c new file mode 100644 index 00000000..30e90dd4 --- /dev/null +++ b/test/regression/usbx_ux_host_stack_uninitialize_test.c @@ -0,0 +1,155 @@ +/* This test is designed to test the ux_utility_memory_.... */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_MEMORY_SIZE (64*1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +/* Define USBX test global variables. */ + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + +/* 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); + } + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_host_stack_uninitialize_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +UCHAR *stack_pointer; +UCHAR *memory_pointer; + + + /* Inform user. */ + printf("Running ux_host_stack_uninitialize Test............................. "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } +} + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + +UINT status; +ULONG rfree; + + rfree = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + status = _ux_host_stack_initialize(UX_NULL); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (rfree <= _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + status = _ux_host_stack_uninitialize(); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: 0x%x\n", __LINE__, status); + test_control_return(1); + } + if (rfree != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} \ No newline at end of file diff --git a/test/regression/usbx_ux_test_cdc_ecm.h b/test/regression/usbx_ux_test_cdc_ecm.h new file mode 100644 index 00000000..60dedc68 --- /dev/null +++ b/test/regression/usbx_ux_test_cdc_ecm.h @@ -0,0 +1,772 @@ +#ifndef USBX_UX_TEST_CDC_ECM_H +#define USBX_UX_TEST_CDC_ECM_H + +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_network_driver.h" +#include "ux_host_class_cdc_ecm.h" +#include "ux_device_class_cdc_ecm.h" +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" +#include "ux_test.h" +#include "ux_test_actions.h" + +//#define LOCAL_MACHINE + +typedef struct DEVICE_INIT_DATA +{ + UCHAR *framework; + ULONG framework_length; + UCHAR *string_framework; + ULONG string_framework_length; + UCHAR dont_register_hcd; + UCHAR dont_connect_to_host; +} DEVICE_INIT_DATA; + +#define DEMO_IP_THREAD_STACK_SIZE (8*1024) +#define HOST_IP_ADDRESS IP_ADDRESS(192,168,1,176) +#define HOST_SOCKET_PORT_UDP 45054 +#define HOST_SOCKET_PORT_TCP 45056 +#define DEVICE_IP_ADDRESS IP_ADDRESS(192,168,1,175) +#define DEVICE_SOCKET_PORT_UDP 45055 +#define DEVICE_SOCKET_PORT_TCP 45057 + +#ifndef TEST_NX_PACKET_CHAIN +#define TCP_WINDOW 1600 +#define PACKET_PAYLOAD 1600 +#define WRITE_APPEND_SIZE (0) +#define PACKET_POOL_SIZE (PACKET_PAYLOAD*10000) +#define HOST_IP_POOL_SIZE (PACKET_PAYLOAD*UX_HOST_CLASS_CDC_ECM_NX_PKPOOL_ENTRIES) +#define DEVICE_IP_POOL_SIZE (PACKET_PAYLOAD*UX_DEVICE_CLASS_CDC_ECM_NX_PKPOOL_ENTRIES) +#else +#define TCP_WINDOW 1400 +#define PACKET_PAYLOAD (256) +#define WRITE_APPEND_SIZE (300) +#define PACKET_POOL_SIZE (PACKET_PAYLOAD*10000) +#define HOST_IP_POOL_SIZE (PACKET_PAYLOAD*UX_HOST_CLASS_CDC_ECM_NX_PKPOOL_ENTRIES) +#define DEVICE_IP_POOL_SIZE (PACKET_PAYLOAD*UX_DEVICE_CLASS_CDC_ECM_NX_PKPOOL_ENTRIES) +#endif +#define ARP_MEMORY_SIZE 1024 + +/* Define local constants. */ + +#define UX_DEMO_STACK_SIZE (4*1024) +#define UX_USBX_MEMORY_SIZE (128*1024) + +/* Define basic test constants. */ + +#ifndef BASIC_TEST_NUM_ITERATIONS +#define BASIC_TEST_NUM_ITERATIONS 10 +#endif +#ifndef BASIC_TEST_NUM_PACKETS_PER_ITERATION +#define BASIC_TEST_NUM_PACKETS_PER_ITERATION 10 +#endif +#define BASIC_TEST_NUM_TOTAL_PACKETS (BASIC_TEST_NUM_ITERATIONS*BASIC_TEST_NUM_PACKETS_PER_ITERATION) +#define BASIC_TEST_HOST 0 +#define BASIC_TEST_DEVICE 1 +#define BASIC_TEST_TCP 0 +#define BASIC_TEST_UDP 1 + +/* Host */ + +static UX_HOST_CLASS *class_driver_host; +static UX_HOST_CLASS_CDC_ECM *cdc_ecm_host; +static UX_HOST_CLASS_CDC_ECM *cdc_ecm_host_from_system_change_function; +static TX_THREAD thread_host; +static UCHAR thread_stack_host[UX_DEMO_STACK_SIZE]; +static NX_IP nx_ip_host; +static NX_PACKET_POOL ip_pool_host; +static UCHAR ip_pool_host_name[] = "NetX Host IP Pool"; +static NX_PACKET_POOL packet_pool_host; +static NX_PACKET_POOL *packet_pool_host_ptr = &packet_pool_host; +static NX_UDP_SOCKET udp_socket_host; +static NX_TCP_SOCKET tcp_socket_host; +static CHAR *packet_pool_memory_host; +static CHAR ip_thread_stack_host[DEMO_IP_THREAD_STACK_SIZE]; +static CHAR arp_memory_host[ARP_MEMORY_SIZE]; + +/* Device */ + +static TX_THREAD thread_device; +static UX_HOST_CLASS *class_driver_device; +static UX_SLAVE_CLASS_CDC_ECM *cdc_ecm_device; +static UX_SLAVE_CLASS_CDC_ECM_PARAMETER cdc_ecm_parameter; +static UCHAR thread_stack_device[UX_DEMO_STACK_SIZE]; +static NX_IP nx_ip_device; +static NX_PACKET_POOL ip_pool_device; +static NX_PACKET_POOL packet_pool_device; +static NX_UDP_SOCKET udp_socket_device; +static NX_TCP_SOCKET tcp_socket_device; +static CHAR *packet_pool_memory_device; +static CHAR ip_thread_stack_device[DEMO_IP_THREAD_STACK_SIZE]; +static CHAR arp_memory_device[ARP_MEMORY_SIZE]; + +static UCHAR global_is_device_initialized; +static UCHAR global_host_ready_for_application; + +static ULONG global_basic_test_num_writes_host; +static ULONG global_basic_test_num_reads_host; +static ULONG global_basic_test_num_writes_device; +static ULONG global_basic_test_num_reads_device; + +/* Define local prototypes and definitions. */ +static void thread_entry_host(ULONG arg); +static void thread_entry_device(ULONG arg); +static void post_init_host(); +static void post_init_device(); + +#define DEFAULT_FRAMEWORK_LENGTH sizeof(default_device_framework) +static unsigned char default_device_framework[] = { + + /* Device Descriptor */ + 0x12, /* bLength */ + 0x01, /* bDescriptorType */ + 0x10, 0x01, /* bcdUSB */ + 0xef, /* bDeviceClass - Depends on bDeviceSubClass */ + 0x02, /* bDeviceSubClass - Depends on bDeviceProtocol */ + 0x01, /* bDeviceProtocol - There's an IAD */ + 0x40, /* bMaxPacketSize0 */ + 0x70, 0x07, /* idVendor */ + 0x42, 0x10, /* idProduct */ + 0x00, 0x01, /* bcdDevice */ + 0x01, /* iManufacturer */ + 0x02, /* iProduct */ + 0x03, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ + + /* Configuration Descriptor @ 18 */ + 0x09, /* bLength */ + 0x02, /* bDescriptorType */ + 0x58, 0x00, /* wTotalLength */ + 0x02, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xc0, /* bmAttributes - Self-powered */ + 0x00, /* bMaxPower */ + + /* Interface Association Descriptor @ 18+9=27 */ + 0x08, /* bLength */ + 0x0b, /* bDescriptorType */ + 0x00, /* bFirstInterface */ + 0x02, /* bInterfaceCount */ + 0x02, /* bFunctionClass - CDC - Communication */ + 0x06, /* bFunctionSubClass - ECM */ + 0x00, /* bFunctionProtocol - No class specific protocol required */ + 0x00, /* iFunction */ + + /* Interface Descriptor @ 27+8=35 */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x02, /* bInterfaceClass - CDC - Communication */ + 0x06, /* bInterfaceSubClass - ECM */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* CDC Header Functional Descriptor @ 35+9=44 */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x00, /* bDescriptorSubType */ + 0x10, 0x01, /* bcdCDC */ + + /* CDC ECM Functional Descriptor @ 44+5=49 */ + 0x0d, /* bLength */ + 0x24, /* bDescriptorType */ + 0x0f, /* bDescriptorSubType */ + 0x04, /* iMACAddress */ + 0x00, 0x00, 0x00, 0x00, /* bmEthernetStatistics */ + 0xea, 0x05, /* wMaxSegmentSize */ + 0x00, 0x00, /* wNumberMCFilters */ + 0x00, /* bNumberPowerFilters */ + + /* CDC Union Functional Descriptor @ 49+13=62 */ + 0x05, /* bLength */ + 0x24, /* bDescriptorType */ + 0x06, /* bDescriptorSubType */ + 0x00, /* bmMasterInterface */ + 0x01, /* bmSlaveInterface0 */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x83, /* bEndpointAddress */ + 0x03, /* bmAttributes - Interrupt */ + 0x08, 0x00, /* wMaxPacketSize */ + 0x08, /* bInterval */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x01, /* bAlternateSetting */ + 0x02, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass - CDC - Data */ + 0x00, /* bInterfaceSubClass - Should be 0x00 */ + 0x00, /* bInterfaceProtocol - No class specific protocol required */ + 0x00, /* iInterface */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x02, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x81, /* bEndpointAddress */ + 0x02, /* bmAttributes - Bulk */ + 0x40, 0x00, /* wMaxPacketSize */ + 0x00, /* bInterval */ + +}; + +static unsigned char default_string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL CDCECM Device" */ + 0x09, 0x04, 0x02, 0x10, + 0x45, 0x4c, 0x20, 0x43, 0x44, 0x43, 0x45, 0x43, + 0x4d, 0x20, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31, + + /* MAC Address string descriptor : Index 4 - "001E5841B879" */ + 0x09, 0x04, 0x04, 0x0C, + 0x30, 0x30, 0x31, 0x45, 0x35, 0x38, + 0x34, 0x31, 0x42, 0x38, 0x37, 0x39, + +}; + + /* 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 + }; + +static DEVICE_INIT_DATA default_device_init_data = { + .framework = default_device_framework, + .framework_length = sizeof(default_device_framework), + .string_framework = default_string_framework, + .string_framework_length = sizeof(default_string_framework) +}; + +static void ux_test_cdc_ecm_initialize_use_framework(void *first_unused_memory, DEVICE_INIT_DATA *device_init_data) +{ + +CHAR *memory_pointer = first_unused_memory; + + /* Initialize possible uninitialized device init values. */ + + if (device_init_data->framework == NULL) + { + device_init_data->framework = default_device_framework; + device_init_data->framework_length = sizeof(default_device_framework); + } + + if (device_init_data->string_framework == NULL) + { + device_init_data->string_framework = default_string_framework; + device_init_data->string_framework_length = sizeof(default_string_framework); + } + + /* Initialize USBX Memory. */ + ux_system_initialize(memory_pointer, UX_USBX_MEMORY_SIZE, UX_NULL, 0); + memory_pointer += UX_USBX_MEMORY_SIZE; + + /* It looks weird if this doesn't have a comment! */ + ux_utility_error_callback_register(ux_test_error_callback); + + /* Perform the initialization of the network driver. */ + UX_TEST_CHECK_SUCCESS(ux_network_driver_init()); + + /* Initialize the NetX system. */ + nx_system_initialize(); + + /* Now allocate memory for the packet pools. Note that using the memory passed + to us by ThreadX is mucho bettero than putting it in global memory because + we can reuse the memory for each test. So no more having to worry about + running out of memory! */ + packet_pool_memory_host = memory_pointer; + memory_pointer += PACKET_POOL_SIZE + HOST_IP_POOL_SIZE; + packet_pool_memory_device = memory_pointer; + memory_pointer += PACKET_POOL_SIZE + DEVICE_IP_POOL_SIZE; + + /* Create the host thread. */ + UX_TEST_CHECK_SUCCESS(tx_thread_create(&thread_host, "host thread", thread_entry_host, (ULONG)(ALIGN_TYPE)device_init_data, + thread_stack_host, UX_DEMO_STACK_SIZE, + 30, 30, 1, TX_DONT_START)); + UX_THREAD_EXTENSION_PTR_SET(&thread_host, device_init_data) + tx_thread_resume(&thread_host); + + /* Create the slave thread. */ + UX_TEST_CHECK_SUCCESS(tx_thread_create(&thread_device, "device thread", thread_entry_device, (ULONG)(ALIGN_TYPE)device_init_data, + thread_stack_device, UX_DEMO_STACK_SIZE, + 30, 30, 1, TX_DONT_START)); + UX_THREAD_EXTENSION_PTR_SET(&thread_device, device_init_data) + tx_thread_resume(&thread_device); +} + +static void ux_test_cdc_ecm_initialize(void *first_unused_memory) +{ + + ux_test_cdc_ecm_initialize_use_framework(first_unused_memory, &default_device_init_data); +} + +static UINT system_change_function(ULONG event, UX_HOST_CLASS *class, VOID *instance) +{ + if (event == UX_DEVICE_INSERTION) + {printf("hINS\n"); + cdc_ecm_host_from_system_change_function = instance; + } + else if (event == UX_DEVICE_REMOVAL) + {printf("hRM\n"); + cdc_ecm_host_from_system_change_function = UX_NULL; + } + return(UX_SUCCESS); +} + +static void class_cdc_ecm_get_host(void) +{ + +UX_HOST_CLASS *class; + + /* Find the main storage container */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_class_get(_ux_system_host_class_cdc_ecm_name, &class)); + + /* We get the first instance of the storage device */ + UX_TEST_CHECK_SUCCESS(ux_test_host_stack_class_instance_get(class, 0, (void **) &cdc_ecm_host)); + + /* We still need to wait for the cdc-ecm status to be live */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uint(&cdc_ecm_host -> ux_host_class_cdc_ecm_state, UX_HOST_CLASS_INSTANCE_LIVE)); + + /* Now wait for the link to be up. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_ulong(&cdc_ecm_host->ux_host_class_cdc_ecm_link_state, UX_HOST_CLASS_CDC_ECM_LINK_STATE_UP)); +} + +static VOID demo_cdc_ecm_instance_activate(VOID *cdc_ecm_instance) +{ + + /* Save the CDC instance. */ + cdc_ecm_device = (UX_SLAVE_CLASS_CDC_ECM *) cdc_ecm_instance; +} + +static VOID demo_cdc_ecm_instance_deactivate(VOID *cdc_ecm_instance) +{ + + /* Reset the CDC instance. */ + cdc_ecm_device = UX_NULL; +} + +/* Copied and pasted from ux_device_class_cdc_ecm_change.c. */ +static void ux_test_device_class_cdc_ecm_set_link_state(UX_SLAVE_CLASS_CDC_ECM *cdc_ecm, UCHAR new_link_state) +{ + + /* Declare the link to be down. */ + cdc_ecm_device -> ux_slave_class_cdc_ecm_link_state = new_link_state; + + /* We have a thread waiting for an event, we wake it up with a NETWORK NOTIFICATION CHANGE event. + In turn they will release the NetX resources used and suspend. */ + UX_TEST_CHECK_SUCCESS(_ux_utility_event_flags_set(&cdc_ecm_device -> ux_slave_class_cdc_ecm_event_flags_group, UX_DEVICE_CLASS_CDC_ECM_NETWORK_NOTIFICATION_EVENT, TX_OR)); +} + +static void read_packet_tcp(NX_TCP_SOCKET *tcp_socket, ULONG num_reads, CHAR *name) +{ + +NX_PACKET *rcv_packet; +ULONG num_writes_from_peer; + +#ifndef LOCAL_MACHINE + if (num_reads % 100 == 0) +#endif + stepinfo("%s reading tcp packet# %lu\n", name, num_reads); + + UX_TEST_CHECK_SUCCESS(nx_tcp_socket_receive(tcp_socket, &rcv_packet, NX_WAIT_FOREVER)); + + num_writes_from_peer = *(ULONG *)rcv_packet->nx_packet_prepend_ptr; + UX_TEST_ASSERT(num_writes_from_peer == num_reads); + + UX_TEST_CHECK_SUCCESS(nx_packet_release(rcv_packet)); +} + +static void write_packet_tcp(NX_TCP_SOCKET *tcp_socket, NX_PACKET_POOL *packet_pool, ULONG num_writes, CHAR *name) +{ + +NX_PACKET *out_packet; + + UX_TEST_CHECK_SUCCESS(nx_packet_allocate(packet_pool, &out_packet, NX_TCP_PACKET, NX_WAIT_FOREVER)); + + *(ULONG *)out_packet->nx_packet_prepend_ptr = num_writes; + out_packet->nx_packet_length = sizeof(ULONG); + out_packet->nx_packet_append_ptr = out_packet->nx_packet_prepend_ptr + out_packet->nx_packet_length; +#if WRITE_APPEND_SIZE > 0 + /* Append data until packet chain created. */ + for (int i = 0, remain = WRITE_APPEND_SIZE; i < WRITE_APPEND_SIZE; i += 10) + { + remain = WRITE_APPEND_SIZE - i; + if (remain < 10) + { + nx_packet_data_append(out_packet, "0123456789", remain, packet_pool, NX_WAIT_FOREVER); + break; + } + else + { + nx_packet_data_append(out_packet, "0123456789", 10, packet_pool, NX_WAIT_FOREVER); + } + } +#endif + +#ifndef LOCAL_MACHINE + if (num_writes % 100 == 0) +#endif + stepinfo("%s writing tcp packet# %lu\n", name, num_writes); + + UX_TEST_CHECK_SUCCESS(nx_tcp_socket_send(tcp_socket, out_packet, NX_WAIT_FOREVER)); +} + +static void read_packet_udp(NX_UDP_SOCKET *udp_socket, ULONG num_reads, CHAR *name) +{ + +NX_PACKET *rcv_packet; +ULONG num_writes_from_peer; + +#ifndef LOCAL_MACHINE + if (num_reads % 100 == 0) +#endif + stepinfo("%s reading udp packet# %lu\n", name, num_reads); + + UX_TEST_CHECK_SUCCESS(nx_udp_socket_receive(udp_socket, &rcv_packet, NX_WAIT_FOREVER)); + + num_writes_from_peer = *(ULONG *)rcv_packet->nx_packet_prepend_ptr; + UX_TEST_ASSERT(num_writes_from_peer == num_reads); + + UX_TEST_CHECK_SUCCESS(nx_packet_release(rcv_packet)); +} + +static void write_udp(NX_UDP_SOCKET *udp_socket, NX_PACKET_POOL *packet_pool, ULONG ip_address, ULONG port, ULONG num_writes, CHAR *name, ULONG len) +{ + +NX_PACKET *out_packet; +ULONG i, remain; + + UX_TEST_CHECK_SUCCESS(nx_packet_allocate(packet_pool, &out_packet, NX_UDP_PACKET, NX_WAIT_FOREVER)); + + *(ULONG *)out_packet->nx_packet_prepend_ptr = num_writes; + out_packet->nx_packet_length = sizeof(ULONG); + out_packet->nx_packet_append_ptr = out_packet->nx_packet_prepend_ptr + out_packet->nx_packet_length; + if (len > 4) + { + + /* Append packet data. */ + for (i = 0, remain = len - 4; i < len - 4; i += 10) + { + remain = len - 4 - i; + if (remain < 10) + { + nx_packet_data_append(out_packet, "0123456789", remain, packet_pool, NX_WAIT_FOREVER); + break; + } + else + { + nx_packet_data_append(out_packet, "0123456789", 10, packet_pool, NX_WAIT_FOREVER); + } + } + } + +#ifndef LOCAL_MACHINE + if (num_writes % 100 == 0) +#endif + stepinfo("%s writing udp packet# %lu, %ld\n", name, num_writes, out_packet->nx_packet_length); + + UX_TEST_CHECK_SUCCESS(nx_udp_socket_send(udp_socket, out_packet, ip_address, port)); +} + +static void write_packet_udp(NX_UDP_SOCKET *udp_socket, NX_PACKET_POOL *packet_pool, ULONG ip_address, ULONG port, ULONG num_writes, CHAR *name) +{ + write_udp(udp_socket, packet_pool, ip_address, port, num_writes, name, 4 + WRITE_APPEND_SIZE); +} + +static void cdc_ecm_basic_test(UCHAR host_or_device, UCHAR socket_type) +{ + +UINT i; +UINT num_iters; + + if (host_or_device == BASIC_TEST_HOST) + { + + if (socket_type == BASIC_TEST_TCP) + { + + for (num_iters = 0; num_iters < BASIC_TEST_NUM_ITERATIONS; num_iters++) + { + + for (i = 0; i < BASIC_TEST_NUM_PACKETS_PER_ITERATION; i++) + write_packet_tcp(&tcp_socket_host, &packet_pool_host, global_basic_test_num_writes_host++, "host"); + + for (i = 0; i < BASIC_TEST_NUM_PACKETS_PER_ITERATION; i++) + read_packet_tcp(&tcp_socket_host, global_basic_test_num_reads_host++, "host"); + } + } + else + { + + for (num_iters = 0; num_iters < BASIC_TEST_NUM_ITERATIONS; num_iters++) + { + + for (i = 0; i < BASIC_TEST_NUM_PACKETS_PER_ITERATION; i++) + write_packet_udp(&udp_socket_host, &packet_pool_host, DEVICE_IP_ADDRESS, DEVICE_SOCKET_PORT_UDP, global_basic_test_num_writes_host++, "host"); + + for (i = 0; i < BASIC_TEST_NUM_PACKETS_PER_ITERATION; i++) + read_packet_udp(&udp_socket_host, global_basic_test_num_reads_host++, "host"); + } + } + + /* Wait for all transfers to complete. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_ulong(&global_basic_test_num_writes_host, BASIC_TEST_NUM_TOTAL_PACKETS)); + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_ulong(&global_basic_test_num_reads_host, BASIC_TEST_NUM_TOTAL_PACKETS)); + + if (socket_type == BASIC_TEST_TCP) + + /* Wait for all ACKs to complete. */ + /* TODO: find better way. */ + tx_thread_sleep(MS_TO_TICK(1000)); + + /* Reset for next test. */ + global_basic_test_num_reads_host = 0; + global_basic_test_num_writes_host = 0; + } + else + { + + if (socket_type == BASIC_TEST_TCP) + { + + for (num_iters = 0; num_iters < BASIC_TEST_NUM_ITERATIONS; num_iters++) + { + + for (i = 0; i < BASIC_TEST_NUM_PACKETS_PER_ITERATION; i++) + write_packet_tcp(&tcp_socket_device, &packet_pool_device, global_basic_test_num_writes_device++, "device"); + + for (i = 0; i < BASIC_TEST_NUM_PACKETS_PER_ITERATION; i++) + read_packet_tcp(&tcp_socket_device, global_basic_test_num_reads_device++, "device"); + } + } + else + { + + for (num_iters = 0; num_iters < BASIC_TEST_NUM_ITERATIONS; num_iters++) + { + + for (i = 0; i < BASIC_TEST_NUM_PACKETS_PER_ITERATION; i++) + write_packet_udp(&udp_socket_device, &packet_pool_device, HOST_IP_ADDRESS, HOST_SOCKET_PORT_UDP, global_basic_test_num_writes_device++, "device"); + + for (i = 0; i < BASIC_TEST_NUM_PACKETS_PER_ITERATION; i++) + read_packet_udp(&udp_socket_device, global_basic_test_num_reads_device++, "device"); + } + } + + /* Wait for all transfers to complete. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_ulong(&global_basic_test_num_writes_device, BASIC_TEST_NUM_TOTAL_PACKETS)); + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_ulong(&global_basic_test_num_reads_device, BASIC_TEST_NUM_TOTAL_PACKETS)); + + /* Reset for next test. */ + global_basic_test_num_reads_device = 0; + global_basic_test_num_writes_device = 0; + } +} + +static void thread_entry_host(ULONG device_init_data_ptr) +{ + +DEVICE_INIT_DATA *device_init_data; + + UX_THREAD_EXTENSION_PTR_GET(device_init_data, DEVICE_INIT_DATA, device_init_data_ptr); + + /* Wait for device to initialize. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uchar(&global_is_device_initialized, 1)); + + /* Create the IP instance. */ + + UX_TEST_CHECK_SUCCESS(nx_packet_pool_create(&packet_pool_host, "NetX Host Packet Pool", PACKET_PAYLOAD, packet_pool_memory_host, PACKET_POOL_SIZE)); + UX_TEST_CHECK_SUCCESS(nx_packet_pool_create(&ip_pool_host, ip_pool_host_name, PACKET_PAYLOAD, packet_pool_memory_host+PACKET_POOL_SIZE, HOST_IP_POOL_SIZE)); + UX_TEST_CHECK_SUCCESS(nx_ip_create(&nx_ip_host, "NetX Host Thread", HOST_IP_ADDRESS, 0xFF000000UL, + &ip_pool_host, _ux_network_driver_entry, ip_thread_stack_host, DEMO_IP_THREAD_STACK_SIZE, 1)); + + /* Setup ARP. */ + + UX_TEST_CHECK_SUCCESS(nx_arp_enable(&nx_ip_host, (void *)arp_memory_host, ARP_MEMORY_SIZE)); + UX_TEST_CHECK_SUCCESS(nx_arp_static_entry_create(&nx_ip_host, DEVICE_IP_ADDRESS, 0x0000001E, 0x80032CD8)); + + /* Setup UDP. */ + + UX_TEST_CHECK_SUCCESS(nx_udp_enable(&nx_ip_host)); + UX_TEST_CHECK_SUCCESS(nx_udp_socket_create(&nx_ip_host, &udp_socket_host, "USB HOST UDP SOCKET", NX_IP_NORMAL, NX_DONT_FRAGMENT, 20, 20)); + UX_TEST_CHECK_SUCCESS(nx_udp_socket_bind(&udp_socket_host, HOST_SOCKET_PORT_UDP, NX_NO_WAIT)); + + /* Setup TCP. */ + + UX_TEST_CHECK_SUCCESS(nx_tcp_enable(&nx_ip_host)); + UX_TEST_CHECK_SUCCESS(nx_tcp_socket_create(&nx_ip_host, &tcp_socket_host, "USB HOST TCP SOCKET", NX_IP_NORMAL, NX_DONT_FRAGMENT, NX_IP_TIME_TO_LIVE, TCP_WINDOW, NX_NULL, NX_NULL)); + UX_TEST_CHECK_SUCCESS(nx_tcp_server_socket_listen(&nx_ip_host, HOST_SOCKET_PORT_TCP, &tcp_socket_host, 5, NX_NULL)); + + /* The code below is required for installing the host portion of USBX. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_initialize(system_change_function)); + + /* Register cdc_ecm class. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_class_register(_ux_system_host_class_cdc_ecm_name, ux_host_class_cdc_ecm_entry)); + + if (!device_init_data->dont_register_hcd) + { + + /* Register all the USB host controllers available in this system. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + + /* Find the storage class. */ + class_cdc_ecm_get_host(); + + if (!device_init_data->dont_connect_to_host) + { + + /* Connect to device TCP socket. */ + UX_TEST_CHECK_SUCCESS(nx_tcp_server_socket_accept(&tcp_socket_host, NX_WAIT_FOREVER)); + } + } + global_host_ready_for_application = 1; + + /* Call test code. */ + post_init_host(); + + /* We need to disconnect the host and device. This is because the NetX cleaning + process (in usbxtestcontrol.c) includes disconnect the device, which tries + to send a RST packet to the peer (or something). By disconnecting here, + we ensure the deactivate routines notify the network driver so that the + packet tranmissiong is stopped there. */ + ux_test_disconnect_slave(); + ux_test_disconnect_host_wait_for_enum_completion(); + + /* And finally the usbx system resources. */ + _ux_system_uninitialize(); + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + +static void thread_entry_device(ULONG device_init_data_ptr) +{ + +DEVICE_INIT_DATA *device_init_data; + + UX_THREAD_EXTENSION_PTR_GET(device_init_data, DEVICE_INIT_DATA, device_init_data_ptr) + + /* Create the IP instance. */ + + UX_TEST_CHECK_SUCCESS(nx_packet_pool_create(&packet_pool_device, "NetX Device Packet Pool", PACKET_PAYLOAD, packet_pool_memory_device, PACKET_POOL_SIZE)); + UX_TEST_CHECK_SUCCESS(nx_packet_pool_create(&ip_pool_device, "NetX Device IP Pool", PACKET_PAYLOAD, packet_pool_memory_device+PACKET_POOL_SIZE, DEVICE_IP_POOL_SIZE)); + + UX_TEST_CHECK_SUCCESS(nx_ip_create(&nx_ip_device, "NetX Device Thread", DEVICE_IP_ADDRESS, 0xFF000000L, &ip_pool_device, + _ux_network_driver_entry, ip_thread_stack_device, DEMO_IP_THREAD_STACK_SIZE, 1)); + + /* Setup ARP. */ + + UX_TEST_CHECK_SUCCESS(nx_arp_enable(&nx_ip_device, (void *)arp_memory_device, ARP_MEMORY_SIZE)); + UX_TEST_CHECK_SUCCESS(nx_arp_static_entry_create(&nx_ip_device, HOST_IP_ADDRESS, 0x0000001E, 0x5841B878)); + + /* Setup UDP. */ + + UX_TEST_CHECK_SUCCESS(nx_udp_enable(&nx_ip_device)); + UX_TEST_CHECK_SUCCESS(nx_udp_socket_create(&nx_ip_device, &udp_socket_device, "USB DEVICE UDP SOCKET", NX_IP_NORMAL, NX_DONT_FRAGMENT, 20, 20)); + UX_TEST_CHECK_SUCCESS(nx_udp_socket_bind(&udp_socket_device, DEVICE_SOCKET_PORT_UDP, NX_NO_WAIT)); + + /* Setup TCP. */ + + UX_TEST_CHECK_SUCCESS(nx_tcp_enable(&nx_ip_device)); + UX_TEST_CHECK_SUCCESS(nx_tcp_socket_create(&nx_ip_device, &tcp_socket_device, "USB DEVICE TCP SOCKET", NX_IP_NORMAL, NX_DONT_FRAGMENT, NX_IP_TIME_TO_LIVE, 100, NX_NULL, NX_NULL)); + UX_TEST_CHECK_SUCCESS(nx_tcp_client_socket_bind(&tcp_socket_device, DEVICE_SOCKET_PORT_TCP, NX_WAIT_FOREVER)); + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + UX_TEST_CHECK_SUCCESS(ux_device_stack_initialize(device_init_data->framework, device_init_data->framework_length, + device_init_data->framework, device_init_data->framework_length, + device_init_data->string_framework, device_init_data->string_framework_length, + language_id_framework, sizeof(language_id_framework), + UX_NULL)); + + /* Set the parameters for callback when insertion/extraction of a CDC device. Set to NULL.*/ + cdc_ecm_parameter.ux_slave_class_cdc_ecm_instance_activate = demo_cdc_ecm_instance_activate; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_instance_deactivate = demo_cdc_ecm_instance_deactivate; + + /* Define a NODE ID. */ + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_local_node_id[0] = 0x00; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_local_node_id[1] = 0x1e; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_local_node_id[2] = 0x58; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_local_node_id[3] = 0x41; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_local_node_id[4] = 0xb8; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_local_node_id[5] = 0x78; + + /* Define a remote NODE ID. */ + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_remote_node_id[0] = 0x00; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_remote_node_id[1] = 0x1e; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_remote_node_id[2] = 0x58; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_remote_node_id[3] = 0x41; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_remote_node_id[4] = 0xb8; + cdc_ecm_parameter.ux_slave_class_cdc_ecm_parameter_remote_node_id[5] = 0x79; + + /* Initialize the device cdc_ecm class. */ + UX_TEST_CHECK_SUCCESS(ux_device_stack_class_register(_ux_system_slave_class_cdc_ecm_name, ux_device_class_cdc_ecm_entry, 1, 0, &cdc_ecm_parameter)); + + /* Initialize the simulated device controller. */ + UX_TEST_CHECK_SUCCESS(_ux_test_dcd_sim_slave_initialize()); + + global_is_device_initialized = UX_TRUE; + + if (!device_init_data->dont_connect_to_host) + { + + if (!device_init_data->dont_register_hcd) + { + + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_non_null((VOID **)&cdc_ecm_device)); + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_ulong(&cdc_ecm_device->ux_slave_class_cdc_ecm_link_state, UX_DEVICE_CLASS_CDC_ECM_LINK_STATE_UP)); + + /* Connect to host TCP socket. */ + UX_TEST_CHECK_SUCCESS(nx_tcp_client_socket_connect(&tcp_socket_device, HOST_IP_ADDRESS, HOST_SOCKET_PORT_TCP, NX_WAIT_FOREVER)); + } + + /* Wait for host - believe this is so that we know host is always first... gives us some 'determinism'. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uchar(&global_host_ready_for_application, 1)); + } + + /* Call test code. */ + post_init_device(); +} + +#endif \ No newline at end of file diff --git a/test/regression/usbx_ux_test_hub.h b/test/regression/usbx_ux_test_hub.h new file mode 100644 index 00000000..2e674fcc --- /dev/null +++ b/test/regression/usbx_ux_test_hub.h @@ -0,0 +1,632 @@ +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_device_stack.h" +#include "ux_host_class_hub.h" +#include "ux_host_class_dpump.h" +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" +#include "ux_test.h" +#include "ux_test_actions.h" +#include "ux_device_class_dummy.h" +#include "ux_dcd_sim_slave.h" +#include "ux_device_class_dummy_hub.h" + +/* Define local constants. */ + +#define UX_TEST_HUB_PORT_STATUS_FULL_SPEED 0x0000 + +#define UX_DEMO_STACK_SIZE (4*1024) +#define UX_USBX_MEMORY_SIZE (128*1024) + +/* Define structs. */ + +typedef struct DEVICE_INIT_DATA_STRUCT +{ + UCHAR *framework; + ULONG framework_length; + UCHAR *hub_descriptor; + ULONG hub_descriptor_length; + UCHAR dont_enumerate; +} DEVICE_INIT_DATA; + +/* Host */ + +static TX_THREAD g_thread_host; +static UCHAR g_thread_stack_host[UX_DEMO_STACK_SIZE]; +static UX_HOST_CLASS *g_class_driver_host; +static UX_HOST_CLASS_HUB *g_hub_host; +static UX_HOST_CLASS_HUB *g_hub_host_from_system_change_function; +static UX_HOST_CLASS_DPUMP *g_dpump_host; +static UX_HOST_CLASS_DPUMP *g_dpump_host_from_system_change_function; + +static TX_THREAD g_thread_cmd; +static UCHAR g_thread_cmd_stack[UX_DEMO_STACK_SIZE]; +static ULONG g_thread_cmd_cmd = 0; +#define CMD_SET_AND_SEND_PORT_EVENT_1 0 /* 1 byte port 1 change. */ +#define CMD_SET_AND_SEND_PORT_EVENT_2 1 /* 2 bytes port 1 change. */ +#define CMD_SET_AND_SEND_PORT_EVENT_3 2 /* 2 bytes device change | port 1 change. */ + +#define UX_TEST_HOST_CHANGE_LOG_N 16 +static struct { + ULONG event; + UX_HOST_CLASS *class; + VOID *instance; +} g_host_change_logs[UX_TEST_HOST_CHANGE_LOG_N]; +static ULONG g_host_change_count; + +/* Device */ + +static TX_THREAD g_thread_device; +static UCHAR g_thread_stack_device[UX_DEMO_STACK_SIZE]; +static UX_DEVICE_CLASS_HUB *g_hub_device; +static UX_DEVICE_CLASS_HUB_PARAMS g_hub_device_parameter; + +static UCHAR g_device_can_go; + +/* Define local prototypes and definitions. */ + +static void thread_entry_host(ULONG arg); +static void thread_entry_device(ULONG arg); +static void thread_entry_cmd(ULONG arg); +static void post_init_host(); +static void post_init_device(); + +/* Define device framework. */ + +static unsigned char default_device_framework[] = { + + /* Device Descriptor */ + 0x12, /* bLength */ + 0x01, /* bDescriptorType */ + 0x00, 0x02, /* bcdUSB */ + 0x09, /* bDeviceClass - Hub */ + 0x00, /* bDeviceSubClass */ + 0x01, /* bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 */ + 0x24, 0x04, /* idVendor */ + 0x12, 0x24, /* idProduct */ + 0xb2, 0x0b, /* bcdDevice */ + 0x00, /* iManufacturer */ + 0x00, /* iProduct */ + 0x00, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ + + /* Configuration Descriptor */ + 0x09, /* bLength */ + 0x02, /* bDescriptorType */ + 0x19, 0x00, /* wTotalLength */ + 0x01, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xe0, /* bmAttributes - Self-powered */ + 0x01, /* bMaxPower */ + + /* Interface Descriptor */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x09, /* bInterfaceClass - Hub */ + 0x00, /* bInterfaceSubClass */ + 0x00, /* bInterfaceProtocol */ + 0x00, /* iInterface */ + + /* Endpoint Descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x81, /* bEndpointAddress */ + 0x03, /* bmAttributes - Interrupt */ + 0x02, 0x00, /* wMaxPacketSize */ + 0x0c, /* bInterval */ + +}; + +static unsigned char default_hub_descriptor[] = { + + /* Hub Descriptor */ + 0x09, /* bLength */ + 0x29, /* bDescriptorType */ + 0x02, /* bNbrPorts */ + 0x09, 0x00, /* wHubCharacteristics */ + 0x32, /* bPwrOn2PwrGood */ + 0x01, /* bHubContrCurrent */ + 0x00, /* DeviceRemovable */ + 0xff, /* PortPwrCtrlMask */ + +}; + +static unsigned char string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + + /* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + + /* Serial Number string descriptor : Index 3 - "0001" */ + 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. */ +static unsigned char language_id_framework[] = { + + /* English. */ + 0x09, 0x04 + }; + +static UCHAR dpump_framework[] = { + + /* 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, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99, + 0x00, + + /* Endpoint descriptor (Bulk Out) */ + 0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00, + + /* Endpoint descriptor (Bulk In) */ + 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00 + }; + +/* This function is invoked by the simulator when the control transfer is meant + for a device on the hub. */ +static UINT hub_control_request_handler(UX_SLAVE_TRANSFER *transfer_request) +{ + +UX_SLAVE_DCD *dcd; +UX_SLAVE_DEVICE *device; +ULONG request_type; +ULONG request; +ULONG request_value; +ULONG request_index; +ULONG request_length; +UINT status = UX_ERROR; +UCHAR *original_framework; +ULONG original_framework_length; + + /* Get the pointer to the DCD. */ + dcd = &_ux_system_slave -> ux_system_slave_dcd; + + /* Get the pointer to the device. */ + device = &_ux_system_slave -> ux_system_slave_device; + + /* Ensure that the Setup request has been received correctly. */ + if (transfer_request -> ux_slave_transfer_request_completion_code == UX_SUCCESS) + { + + /* Seems so far, the Setup request is valid. Extract all fields of + the request. */ + request_type = *transfer_request -> ux_slave_transfer_request_setup; + request = *(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_REQUEST); + request_value = _ux_utility_short_get(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_VALUE); + request_index = _ux_utility_short_get(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_INDEX); + request_length = _ux_utility_short_get(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_LENGTH); + + /* Filter for GET_DESCRIPTOR/SET_DESCRIPTOR commands. If the descriptor to be returned is not a standard descriptor, + treat the command as a CLASS command. */ + if ((request == UX_GET_DESCRIPTOR || request == UX_SET_DESCRIPTOR) && (((request_value >> 8) & UX_REQUEST_TYPE) != UX_REQUEST_TYPE_STANDARD)) + { + + /* This request is to be handled by the class layer. */ + request_type &= (UINT)~UX_REQUEST_TYPE; + request_type |= UX_REQUEST_TYPE_CLASS; + } + + /* Ensure it's not vendor. */ + UX_TEST_ASSERT((request_type & UX_REQUEST_TYPE) != UX_REQUEST_TYPE_VENDOR); + + /* We don't support any class commands right now. */ + UX_TEST_ASSERT((request_type & UX_REQUEST_TYPE) != UX_REQUEST_TYPE_CLASS); + + /* Here we proceed only the standard request we know of at the device level. */ + switch (request) + { + + case UX_GET_STATUS: + + UX_TEST_ASSERT(0); + break; + + case UX_CLEAR_FEATURE: + + UX_TEST_ASSERT(0); + break; + + case UX_SET_FEATURE: + + UX_TEST_ASSERT(0); + break; + + case UX_SET_ADDRESS: + + /* Don't do anything. */ + break; + + case UX_GET_DESCRIPTOR: + + /* We need to trick USBX into sending a different framework than + the hub's. */ + + original_framework = _ux_system_slave->ux_system_slave_device_framework; + original_framework_length = _ux_system_slave->ux_system_slave_device_framework_length; + + /* USBX sends looks here for the framework, so just change it do + our liking. */ + _ux_system_slave->ux_system_slave_device_framework = dpump_framework; + _ux_system_slave->ux_system_slave_device_framework_length = sizeof(dpump_framework); + + /* Kindly ask USBX to send our descriptor. */ + UX_TEST_CHECK_SUCCESS(_ux_device_stack_descriptor_send(request_value, request_index, request_length)); + + _ux_system_slave->ux_system_slave_device_framework = original_framework; + _ux_system_slave->ux_system_slave_device_framework_length = original_framework_length; + + break; + + case UX_SET_DESCRIPTOR: + + UX_TEST_ASSERT(0); + break; + + case UX_GET_CONFIGURATION: + + UX_TEST_ASSERT(0); + break; + + case UX_SET_CONFIGURATION: + + /* Do nothing. */ + break; + + case UX_GET_INTERFACE: + + UX_TEST_ASSERT(0); + break; + + case UX_SET_INTERFACE: + + /* Do nothing. */ + break; + + case UX_SYNCH_FRAME: + + UX_TEST_ASSERT(0); + break; + + default: + + UX_TEST_ASSERT(0); + return(UX_ERROR); + } + return(UX_SUCCESS); + } + return(UX_ERROR); +} + +static UINT class_dpump_get(void) +{ + +UX_HOST_CLASS *class; + + /* Find the main dpump container. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class)); + + /* Get the class. */ + UX_TEST_CHECK_SUCCESS(ux_test_host_stack_class_instance_get(class, 0, (void **) &g_dpump_host)); + + /* We still need to wait for the dpump status to be live. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uint(&g_dpump_host -> ux_host_class_dpump_state, UX_HOST_CLASS_INSTANCE_LIVE)); + + /* In virtually all cases, we want the enumeration thread to be finished. */ + ux_test_wait_for_enum_thread_completion(); + + /* Return success. */ + return(UX_SUCCESS); +} + +/* Leave all the fields null. */ +static DEVICE_INIT_DATA default_device_init_data; + +/* Define what the initial system looks like. */ + +static void initialize_hub_with_device_init_data(void *first_unused_memory, DEVICE_INIT_DATA *device_init_data) +{ + +UCHAR *memory_pointer = (UCHAR *)first_unused_memory; + + stepinfo("\n"); + + if (device_init_data->framework == UX_NULL) + { + device_init_data->framework = default_device_framework; + device_init_data->framework_length = sizeof(default_device_framework); + } + + if (device_init_data->hub_descriptor == UX_NULL) + { + device_init_data->hub_descriptor = default_hub_descriptor; + device_init_data->hub_descriptor_length = sizeof(default_hub_descriptor); + } + + /* Initialize USBX Memory. */ + ux_system_initialize(memory_pointer, UX_USBX_MEMORY_SIZE, UX_NULL, 0); + memory_pointer += UX_USBX_MEMORY_SIZE; + + /* It looks weird if this doesn't have a comment! */ + ux_utility_error_callback_register(ux_test_error_callback); + + /* Create the host thread. */ + UX_TEST_CHECK_SUCCESS(tx_thread_create(&g_thread_host, "host thread", thread_entry_host, (ULONG)(ALIGN_TYPE)device_init_data, + g_thread_stack_host, UX_DEMO_STACK_SIZE, + 30, 30, 1, TX_DONT_START)); + UX_THREAD_EXTENSION_PTR_SET(&g_thread_host, device_init_data) + tx_thread_resume(&g_thread_host); + + /* Create the slave thread. */ + UX_TEST_CHECK_SUCCESS(tx_thread_create(&g_thread_device, "device thread", thread_entry_device, (ULONG)(ALIGN_TYPE)device_init_data, + g_thread_stack_device, UX_DEMO_STACK_SIZE, + 30, 30, 1, TX_DONT_START)); + UX_THREAD_EXTENSION_PTR_SET(&g_thread_device, device_init_data) + tx_thread_resume(&g_thread_device); + + /* Create the command thread. */ + UX_TEST_CHECK_SUCCESS(tx_thread_create(&g_thread_cmd, "cmd thread", thread_entry_cmd, 0, + g_thread_cmd_stack, UX_DEMO_STACK_SIZE, + 30, 30, 1, TX_DONT_START)); +} + +static void initialize_hub(void *first_unused_memory) +{ + + initialize_hub_with_device_init_data(first_unused_memory, &default_device_init_data); +} + +static UINT class_hub_get(void) +{ + +UX_HOST_CLASS *class; + + + /* Find the main dpump container. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_class_get(_ux_system_host_class_hub_name, &class)); + + /* Get the class. */ + UX_TEST_CHECK_SUCCESS(ux_test_host_stack_class_instance_get(class, 0, (void **) &g_hub_host)); + + /* We still need to wait for the dpump status to be live. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uint(&g_hub_host -> ux_host_class_hub_state, UX_HOST_CLASS_INSTANCE_LIVE)); + + /* Return success. */ + return(UX_SUCCESS); +} + +static VOID device_hub_instance_activate(VOID *instance) +{ + g_hub_device = (UX_DEVICE_CLASS_HUB *)instance; +} + +static VOID device_hub_instance_deactivate(VOID *instance) +{ + g_hub_device = (UX_DEVICE_CLASS_HUB *)UX_NULL; +} + +static UINT system_change_function(ULONG event, UX_HOST_CLASS *class, VOID *instance) +{ + if (g_host_change_count < UX_TEST_HOST_CHANGE_LOG_N) + { + g_host_change_logs[g_host_change_count].event = event; + g_host_change_logs[g_host_change_count].class = class; + g_host_change_logs[g_host_change_count].instance = instance; + g_host_change_count ++; + } + + if (class == UX_NULL) + return(UX_SUCCESS); + + if (!memcmp(class->ux_host_class_name, _ux_system_host_class_hub_name, strlen(_ux_system_host_class_hub_name))) + { + if (event == UX_DEVICE_INSERTION) + { + g_hub_host_from_system_change_function = instance; + } + else if (event == UX_DEVICE_REMOVAL) + { + g_hub_host_from_system_change_function = UX_NULL; + } + } + else if (!memcmp(class->ux_host_class_name, _ux_system_host_class_dpump_name, strlen(_ux_system_host_class_dpump_name))) + { + if (event == UX_DEVICE_INSERTION) + { + g_dpump_host_from_system_change_function = instance; + } + else if (event == UX_DEVICE_REMOVAL) + { + g_dpump_host_from_system_change_function = UX_NULL; + } + } + return(UX_SUCCESS); +} +static void thread_entry_cmd(ULONG arg) +{ +ULONG temp; + while(1) + { + if (g_hub_device) + { + switch(g_thread_cmd_cmd) + { + case CMD_SET_AND_SEND_PORT_EVENT_1: + _ux_device_class_hub_notify_change(g_hub_device, 1, 1); + break; + case CMD_SET_AND_SEND_PORT_EVENT_2: + _ux_device_class_hub_notify_change(g_hub_device, 1, 2); + break; + case CMD_SET_AND_SEND_PORT_EVENT_3: + temp = 0x3u; + _ux_device_class_hub_notify_changes(g_hub_device, (UCHAR*)&temp, 2); + break; + default: + break; + } + } + tx_thread_suspend(&g_thread_cmd); + } +} +static VOID set_and_send_port_event(UINT port_status, UINT port_change) +{ + + /* Setup the approriate fields in the hub instance. */ + g_hub_device->port_status = port_status; + g_hub_device->port_change = port_change; + + g_thread_cmd_cmd = CMD_SET_AND_SEND_PORT_EVENT_1; + tx_thread_resume(&g_thread_cmd); +} + +static VOID connect_device_to_hub_speed(UINT speed) +{ + + set_and_send_port_event(speed | UX_HOST_CLASS_HUB_PORT_STATUS_CONNECTION | UX_HOST_CLASS_HUB_PORT_STATUS_POWER, + UX_HOST_CLASS_HUB_PORT_CHANGE_CONNECTION); +} + +static VOID connect_device_to_hub() +{ + connect_device_to_hub_speed(UX_HOST_CLASS_HUB_PORT_STATUS_HIGH_SPEED); +} + +static VOID connect_device_to_hub_short_with_hub() +{ + + /* Setup the approriate fields in the hub instance. */ + g_hub_device->port_status = UX_HOST_CLASS_HUB_PORT_STATUS_CONNECTION | UX_HOST_CLASS_HUB_PORT_STATUS_POWER; + g_hub_device->port_change = UX_HOST_CLASS_HUB_PORT_CHANGE_CONNECTION; + + g_thread_cmd_cmd = CMD_SET_AND_SEND_PORT_EVENT_3; + tx_thread_resume(&g_thread_cmd); +} + +static VOID disconnect_device_from_hub() +{ + + /* Setup the approriate fields in the hub instance. */ + g_hub_device->port_status = 0; /* Make sure the connection bit is off. */ + g_hub_device->port_change = UX_HOST_CLASS_HUB_PORT_CHANGE_CONNECTION; + + g_thread_cmd_cmd = CMD_SET_AND_SEND_PORT_EVENT_1; + tx_thread_resume(&g_thread_cmd); +} + +static void thread_entry_host(ULONG device_init_data_ptr) +{ + +UX_DCD_SIM_SLAVE *dcd_sim_slave; +DEVICE_INIT_DATA *device_init_data; + + UX_THREAD_EXTENSION_PTR_GET(device_init_data, DEVICE_INIT_DATA, device_init_data_ptr) + + /* The code below is required for installing the device portion of USBX. + In this demo, DFU is possible and we have a call back for state change. */ + UX_TEST_CHECK_SUCCESS(ux_device_stack_initialize(device_init_data->framework, device_init_data->framework_length, + device_init_data->framework, device_init_data->framework_length, + string_framework, sizeof(string_framework), + language_id_framework, sizeof(language_id_framework), + UX_NULL)); + + g_hub_device_parameter.instance_activate = device_hub_instance_activate; + g_hub_device_parameter.instance_deactivate = device_hub_instance_deactivate; + g_hub_device_parameter.descriptor = device_init_data->hub_descriptor; + g_hub_device_parameter.descriptor_length = device_init_data->hub_descriptor_length; + + /* Initialize the device hub class. */ + UX_TEST_CHECK_SUCCESS(ux_device_stack_class_register(_ux_device_class_hub_name, _ux_device_class_hub_entry, 1, 0, &g_hub_device_parameter)); + + /* The code below is required for installing the host portion of USBX. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_initialize(system_change_function)); + + /* Register hub class. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_class_register(_ux_system_host_class_hub_name, ux_host_class_hub_entry)); + +#if UX_MAX_CLASS_DRIVER > 1 + /* Register dpump class. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry)); +#endif + + /* Initialize the simulated device controller. */ + UX_TEST_CHECK_SUCCESS(_ux_test_dcd_sim_slave_initialize()); + + /* Get the DCD sim slave. */ + dcd_sim_slave = (UX_DCD_SIM_SLAVE *)_ux_system_slave->ux_system_slave_dcd.ux_slave_dcd_controller_hardware; + + /* Set the hub control request handler. */ + dcd_sim_slave->ux_dcd_sim_slave_dcd_control_request_process_hub = hub_control_request_handler; + + if (!device_init_data->dont_enumerate) + { + + /* Register all the USB host controllers available in this system. */ + UX_TEST_CHECK_SUCCESS(ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize, 0, 0)); + + /* Sim HCD init will put() the enum thread semaphore. */ + ux_test_wait_for_enum_thread_completion(); + + /* Get the hub instance. */ + class_hub_get(); + } + + /* Inform device. */ + g_device_can_go = 1; + + /* Call application. */ + post_init_host(); + + /* Disconnect. */ + ux_test_disconnect_slave_and_host_wait_for_enum_completion(); + + UX_TEST_ASSERT(ux_test_check_actions_empty() == UX_TRUE); + + /* And finally the usbx system resources. */ + _ux_system_uninitialize(); + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); +} + +static void thread_entry_device(ULONG input) +{ + + /* Wait for host to give us the go ahead. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uchar(&g_device_can_go, 1)); + + /* Call the application. */ + post_init_device(); +} diff --git a/test/regression/usbx_ux_utility_basic_memory_management_test.c b/test/regression/usbx_ux_utility_basic_memory_management_test.c new file mode 100644 index 00000000..5fe01c5d --- /dev/null +++ b/test/regression/usbx_ux_utility_basic_memory_management_test.c @@ -0,0 +1,352 @@ +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" +#include "ux_test.h" +#include "ux_test_utility_sim.h" + +#define UX_DEMO_STACK_SIZE 2048 +#define UX_DEMO_MEMORY_SIZE (256*1024) +#define UX_DEMO_BUFFER_SIZE 2048 + +UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_utility_basic_memory_management_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status = 0; +CHAR *stack_pointer; +CHAR *memory_pointer; +CHAR *pointer_1; +CHAR *pointer_2; +CHAR *pointer_3; +CHAR *pointer_4; +ULONG memory_size; +ULONG array[20]; +UX_MEMORY_BYTE_POOL *pool_ptr; + + + /* Inform user. */ + printf("Running USB Utility Basic Memory Management Converge Coverage 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); + if (status != UX_SUCCESS) + { + printf("Line:%s, ux_utility_memory_allocate failed!\n", __LINE__); + test_control_return(status); + return; + } + + pool_ptr = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR]; +#ifdef UX_ENFORCE_SAFE_ALIGNMENT + memory_size = UX_ALIGN_8 - 1; + pointer_1 = ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_REGULAR_MEMORY, memory_size); + if ((pointer_1 == UX_NULL) || (((ULONG)pointer_1) & memory_size)) + { + printf("Line:%s, ux_utility_memory_allocate failed!\n", __LINE__); + test_control_return(1); + return; + } + ux_utility_memory_free(pointer_1); + + memory_size = UX_ALIGN_8; + pointer_1 = ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_REGULAR_MEMORY, memory_size); + if ((pointer_1 == UX_NULL) || (((ULONG)pointer_1) & memory_size)) + { + printf("Line:%s, ux_utility_memory_allocate failed!\n", __LINE__); + test_control_return(1); + return; + } + ux_utility_memory_free(pointer_1); + + memory_size = UX_ALIGN_16; + pointer_1 = ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_REGULAR_MEMORY, memory_size); + + if ((pointer_1 == UX_NULL) || (((ULONG)pointer_1) & memory_size)) + { + printf("Line:%s, ux_utility_memory_allocate failed!\n", __LINE__); + test_control_return(1); + return; + } + ux_utility_memory_free(pointer_1); + + memory_size = UX_ALIGN_32; + pointer_1 = ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_REGULAR_MEMORY, memory_size); + + if ((pointer_1 == UX_NULL) || (((ULONG)pointer_1) & memory_size)) + { + printf("Line:%s, ux_utility_memory_allocate failed!\n", __LINE__); + test_control_return(1); + return; + } + ux_utility_memory_free(pointer_1); + + memory_size = UX_ALIGN_64; + pointer_1 = ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_REGULAR_MEMORY, memory_size); + + if ((pointer_1 == UX_NULL) || (((ULONG)pointer_1) & memory_size)) + { + printf("Line:%s, ux_utility_memory_allocate failed!\n", __LINE__); + test_control_return(1); + return; + } + ux_utility_memory_free(pointer_1); + + memory_size = UX_ALIGN_128; + pointer_1 = ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_REGULAR_MEMORY, memory_size); + + if ((pointer_1 == UX_NULL) || (((ULONG)pointer_1) & memory_size)) + { + printf("Line:%s, ux_utility_memory_allocate failed!\n", __LINE__); + test_control_return(1); + return; + } + ux_utility_memory_free(pointer_1); + + memory_size = UX_ALIGN_256; + pointer_1 = ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_REGULAR_MEMORY, memory_size); + + if ((pointer_1 == UX_NULL) || (((ULONG)pointer_1) & memory_size)) + { + printf("Line:%s, ux_utility_memory_allocate failed!\n", __LINE__); + test_control_return(1); + return; + } + ux_utility_memory_free(pointer_1); + + memory_size = UX_ALIGN_512; + pointer_1 = ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_REGULAR_MEMORY, memory_size); + + if ((pointer_1 == UX_NULL) || (((ULONG)pointer_1) & memory_size)) + { + printf("Line:%s, ux_utility_memory_allocate failed!\n", __LINE__); + test_control_return(1); + return; + } + ux_utility_memory_free(pointer_1); + + memory_size = UX_ALIGN_1024; + pointer_1 = ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_REGULAR_MEMORY, memory_size); + + if ((pointer_1 == UX_NULL) || (((ULONG)pointer_1) & memory_size)) + { + printf("Line:%s, ux_utility_memory_allocate failed!\n", __LINE__); + test_control_return(1); + return; + } + ux_utility_memory_free(pointer_1); + + memory_size = UX_ALIGN_2048; + pointer_1 = ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_REGULAR_MEMORY, memory_size); + + if ((pointer_1 == UX_NULL) || (((ULONG)pointer_1) & memory_size)) + { + printf("Line:%s, ux_utility_memory_allocate failed!\n", __LINE__); + test_control_return(1); + return; + } + ux_utility_memory_free(pointer_1); + + memory_size = UX_ALIGN_2048 + 1; + pointer_1 = ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_REGULAR_MEMORY, memory_size); + + if ((pointer_1 == UX_NULL) || (((ULONG)pointer_1) & UX_ALIGN_4096)) + { + printf("Line:%s, ux_utility_memory_allocate failed!\n", __LINE__); + test_control_return(1); + return; + } + ux_utility_memory_free(pointer_1); + + memory_size = UX_MAX_SCATTER_GATHER_ALIGNMENT + 1; + pointer_1 = ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_REGULAR_MEMORY, memory_size); + + if ((pointer_1 == UX_NULL) || (((ULONG)pointer_1) & (UX_MAX_SCATTER_GATHER_ALIGNMENT-1))) + { + printf("Line:%s, ux_utility_memory_allocate failed!\n", __LINE__); + test_control_return(1); + return; + } + ux_utility_memory_free(pointer_1); +#endif + + /* Test NULL pointer release. */ + ux_utility_memory_free(TX_NULL); + + /* Test another bad block release... no pool pointer! */ + array[0] = 0; + array[1] = 0; + array[2] = 0; + ux_utility_memory_free(&array[2]); + + /* Test another bad block release.... pool pointer is not a valid pool! */ + array[0] = 0; + array[1] = (ULONG) &array[3]; + array[2] = 0; + array[3] = 0; + ux_utility_memory_free(&array[2]); + + /* Re-Release the same block */ + memory_size = UX_ALIGN_8 - 1; + pointer_1 = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size); + if ((pointer_1 == UX_NULL) || (((ULONG)pointer_1) & memory_size)) + { + printf("Line:%s, ux_utility_memory_allocate failed!\n", __LINE__); + test_control_return(1); + return; + } + ux_utility_memory_free(pointer_1); + ux_utility_memory_free(pointer_1); + + /* Allocate each block again to make sure everything still + works. */ + + /* Allocate memory from the pool. */ + memory_size = 24; + pointer_1 = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size); + + /* Check status. */ + if ((pointer_1 == UX_NULL) || (((ULONG)pointer_1) & UX_ALIGN_MIN)) + { + printf("Line:%s, ux_utility_memory_allocate failed!\n", __LINE__); + test_control_return(1); + return; + } + /* Allocate second memory area from the pool. */ + memory_size = 24; + pointer_2 = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size); + + /* Check status. */ + if ((pointer_2 == UX_NULL) || (((ULONG)pointer_2) & UX_ALIGN_MIN)) + { + printf("Line:%s, ux_utility_memory_allocate failed!\n", __LINE__); + test_control_return(1); + return; + } + + /* Allocate third memory area from the pool. */ + memory_size = 24; + pointer_3 = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size); + + /* Check status. */ + if ((pointer_3 == UX_NULL) || (((ULONG)pointer_3) & UX_ALIGN_MIN)) + { + printf("Line:%s, ux_utility_memory_allocate failed!\n", __LINE__); + test_control_return(1); + return; + } + + /* Attempt to allocate fourth memory area from the pool. This should fail because + there should be not enough bytes in the pool. */ + memory_size = 24; + pointer_4 = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size); + + /* Check status. */ + if ((pointer_4 == UX_NULL) || (((ULONG)pointer_4) & UX_ALIGN_MIN)) + { + printf("Line:%s, ux_utility_memory_allocate failed!\n", __LINE__); + test_control_return(1); + return; + } + + /* Now release each of the blocks. */ + ux_utility_memory_free(pointer_1); + ux_utility_memory_free(pointer_2); + ux_utility_memory_free(pointer_3); + + /* Now allocate a block that should cause all of the blocks to merge + together. */ + memory_size = 88; + pointer_3 = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size); + + /* Check status. */ + if ((pointer_3 == UX_NULL) || (((ULONG)pointer_3) & UX_ALIGN_MIN)) + { + printf("Line:%s, ux_utility_memory_allocate failed!\n", __LINE__); + test_control_return(1); + return; + } + ux_utility_memory_free(pointer_3); + ux_utility_memory_free(pointer_4); + + /* Check the allocated address is the same */ + /* Allocate memory from the pool. */ + memory_size = 24; + pointer_1 = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size); + + /* Check status. */ + if ((pointer_1 == UX_NULL) || (((ULONG)pointer_1) & UX_ALIGN_MIN)) + { + printf("Line:%s, ux_utility_memory_allocate failed!\n", __LINE__); + test_control_return(1); + return; + } + + /* Allocate second memory area from the pool. */ + memory_size = 24; + pointer_2 = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size); + + /* Check status. */ + if ((pointer_2 == UX_NULL) || (((ULONG)pointer_2) & UX_ALIGN_MIN)) + { + printf("Line:%s, ux_utility_memory_allocate failed!\n", __LINE__); + test_control_return(1); + return; + } + + /* Allocate second memory area from the pool. */ + memory_size = 24; + pointer_3 = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size); + + /* Check status. */ + if ((pointer_3 == UX_NULL) || (((ULONG)pointer_3) & UX_ALIGN_MIN)) + { + printf("Line:%s, ux_utility_memory_allocate failed!\n", __LINE__); + test_control_return(1); + return; + } + + /* Release the middle block. */ + ux_utility_memory_free(pointer_1); + + /* Now allocate the block again. */ + memory_size = 24; + pointer_4 = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size); + + /* Check status. */ + if ((pointer_4 == UX_NULL) || (((ULONG)pointer_4) & UX_ALIGN_MIN)) + { + printf("Line:%s, ux_utility_memory_allocate failed!\n", __LINE__); + test_control_return(1); + return; + } + + if (pointer_1 != pointer_4) + { + printf("Line:%s, Allocated address is not the same!\n", __LINE__); + test_control_return(1); + return; + } + + /* Now release the blocks are test the merge with the update of the search pointer. */ + ux_utility_memory_free(pointer_3); + ux_utility_memory_free(pointer_2); + ux_utility_memory_free(pointer_4); + + printf("SUCCESS!\n"); + + test_control_return(0); + return; +} diff --git a/test/regression/usbx_ux_utility_descriptor_pack_test.c b/test/regression/usbx_ux_utility_descriptor_pack_test.c new file mode 100644 index 00000000..e81da535 --- /dev/null +++ b/test/regression/usbx_ux_utility_descriptor_pack_test.c @@ -0,0 +1,388 @@ +/* This test is designed to test the ux_utility_descriptor_pack. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors. */ +#define DPUMP_IFC_DESC(ifc, alt, nb_ep) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), (alt), (nb_ep), 0x99, 0x99, 0x99, 0x00, + +#define DPUMP_IFC_EP_DESC(epaddr, eptype, epsize) \ + /* Endpoint descriptor */\ + 0x07, 0x05, (epaddr), (eptype), LSB(epsize), MSB(epsize), 0x01, + +#define DPUMP_IFC_DESC_ALL_LEN(nb_ep) (9 + (nb_ep) * 7) + +#define CFG_DESC_ALL_LEN (CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN(4)) + +#define CFG_DESC_ALL \ + CFG_DESC(CFG_DESC_ALL_LEN, 1, 1)\ + DPUMP_IFC_DESC(0, 0, 4)\ + DPUMP_IFC_EP_DESC(0x81, 2, 64)\ + DPUMP_IFC_EP_DESC(0x02, 2, 64)\ + DPUMP_IFC_EP_DESC(0x83, 1, 64)\ + DPUMP_IFC_EP_DESC(0x84, 3, 64)\ + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC_ALL +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC_ALL +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +/* Simulator actions. */ + +static UX_TEST_HCD_SIM_ACTION endpoint0x83_create_del_skip[] = { +/* 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_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x83, UX_NULL, 0, 0, + UX_SUCCESS}, +{ UX_HCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x83, UX_NULL, 0, 0, + UX_SUCCESS}, +{ 0 } +}; + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 break_on_dpump_ready(VOID) +{ + +UINT status; +UX_HOST_CLASS *class; + + /* Find the main data pump container. */ + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class); + if (status != UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + /* Find the instance. */ + status = ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump); + if (status != UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + if (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + + +static UINT test_ux_device_class_dpump_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + switch(command->ux_slave_class_command_request) + { + case UX_SLAVE_CLASS_COMMAND_INITIALIZE: + case UX_SLAVE_CLASS_COMMAND_QUERY: + case UX_SLAVE_CLASS_COMMAND_CHANGE: + return UX_SUCCESS; + + default: + return UX_NO_CLASS_MATCH; + } +} + +static UINT test_ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command) +{ + switch (command -> ux_host_class_command_request) + { + case UX_HOST_CLASS_COMMAND_QUERY: + default: + return _ux_host_class_dpump_entry(command); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_utility_descriptor_pack_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; + + /* Inform user. */ + printf("Running ux_utility_descriptor_pack Test............................. "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + +ULONG i; +UCHAR structure[] = {4,2,1,2,4}; +UCHAR output[16]; +#if 1 +struct _input { + ULONG f1; + USHORT f2; + UCHAR f3; + UCHAR _align_f4[1]; + USHORT f4; + UCHAR _align_f5[2]; + ULONG f5; +} input = {0x03020100, 0x0504, 0x6, {0}, 0x0807, {0,0}, 0x0c0b0a09}; + _ux_utility_memory_set(output, 0xFF, sizeof(output)); + _ux_utility_descriptor_pack((UCHAR *)&input, structure, 5, output); +#else +ULONG input[] = {0x03020100, 0x0504, 0x6, 0x0807, 0x0c0b0a09, 0x0}; + + _ux_utility_memory_set(output, 0xFF, sizeof(output)); + _ux_utility_descriptor_pack((UCHAR *)input, structure, 5, output); +#endif + for (i = 0; i <= 0x0c; i ++) + { + if (output[i] != i) + { + printf("ERROR #%d: expect 0x%lx but got 0x%x\n", __LINE__, i, output[i]); + error_counter ++; + } + } + for(;i < sizeof(output); i ++) + { + if (output[i] != 0xFF) + { + printf("ERROR #%d: expect 0x%x but got 0x%x\n", __LINE__, 0xFF, output[i]); + error_counter ++; + } + } + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_ux_utility_descriptor_parse_test.c b/test/regression/usbx_ux_utility_descriptor_parse_test.c new file mode 100644 index 00000000..b1985302 --- /dev/null +++ b/test/regression/usbx_ux_utility_descriptor_parse_test.c @@ -0,0 +1,436 @@ +/* This test is designed to test the ux_utility_descriptor_parse. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors. */ +#define DPUMP_IFC_DESC(ifc, alt, nb_ep) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), (alt), (nb_ep), 0x99, 0x99, 0x99, 0x00, + +#define DPUMP_IFC_EP_DESC(epaddr, eptype, epsize) \ + /* Endpoint descriptor */\ + 0x07, 0x05, (epaddr), (eptype), LSB(epsize), MSB(epsize), 0x01, + +#define DPUMP_IFC_DESC_ALL_LEN(nb_ep) (9 + (nb_ep) * 7) + +#define CFG_DESC_ALL_LEN (CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN(4)) + +#define CFG_DESC_ALL \ + CFG_DESC(CFG_DESC_ALL_LEN, 1, 1)\ + DPUMP_IFC_DESC(0, 0, 4)\ + DPUMP_IFC_EP_DESC(0x81, 2, 64)\ + DPUMP_IFC_EP_DESC(0x02, 2, 64)\ + DPUMP_IFC_EP_DESC(0x83, 1, 64)\ + DPUMP_IFC_EP_DESC(0x84, 3, 64)\ + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC_ALL +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC_ALL +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +/* Simulator actions. */ + +static UX_TEST_HCD_SIM_ACTION endpoint0x83_create_del_skip[] = { +/* 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_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x83, UX_NULL, 0, 0, + UX_SUCCESS}, +{ UX_HCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x83, UX_NULL, 0, 0, + UX_SUCCESS}, +{ 0 } +}; + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 break_on_dpump_ready(VOID) +{ + +UINT status; +UX_HOST_CLASS *class; + + /* Find the main data pump container. */ + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class); + if (status != UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + /* Find the instance. */ + status = ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump); + if (status != UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + if (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + + +static UINT test_ux_device_class_dpump_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + switch(command->ux_slave_class_command_request) + { + case UX_SLAVE_CLASS_COMMAND_INITIALIZE: + case UX_SLAVE_CLASS_COMMAND_QUERY: + case UX_SLAVE_CLASS_COMMAND_CHANGE: + return UX_SUCCESS; + + default: + return UX_NO_CLASS_MATCH; + } +} + +static UINT test_ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command) +{ + switch (command -> ux_host_class_command_request) + { + case UX_HOST_CLASS_COMMAND_QUERY: + default: + return _ux_host_class_dpump_entry(command); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_utility_descriptor_parse_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; + + /* Inform user. */ + printf("Running ux_utility_descriptor_parse Test............................ "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ +UCHAR input[] = {0,1,2,3,4,5,6,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf}; +UCHAR structure[] = {4,2,1,2,4}; + +#if 1 +struct _output { + ULONG f1; + USHORT f2; + UCHAR f3; + UCHAR _align_f4[1]; + USHORT f4; + UCHAR _align_f5[2]; + ULONG f5; +} output; + + _ux_utility_descriptor_parse(input, structure, 5, (UCHAR *)&output); + if (output.f1 != 0x03020100) + { + + printf("ERROR #%d: expect 0x%x but got 0x%lx\n", __LINE__, 0x03020100, output.f1); + error_counter ++; + } + if (output.f2 != 0x0504) + { + + printf("ERROR #%d: expect 0x%x but got 0x%x\n", __LINE__, 0x0504, output.f2); + error_counter ++; + } + if (output.f3 != 0x06) + { + + printf("ERROR #%d: expect 0x%x but got 0x%x\n", __LINE__, 6, output.f3); + error_counter ++; + } + if (output.f4 != 0x0807) + { + + printf("ERROR #%d: expect 0x%x but got 0x%x\n", __LINE__, 7, output.f4); + error_counter ++; + } + if (output.f5 != 0x0c0b0a09) + { + + printf("ERROR #%d: expect 0x%x but got 0x%lx\n", __LINE__, 0x0f0e0d0c, output.f5); + error_counter ++; + } +#else +ULONG output[8] = {0,0,0,0,0, 0,0,0}; + + _ux_utility_descriptor_parse(input, structure, 5, (UCHAR *)output); + if (output[0] != 0x03020100) + { + + printf("ERROR #%d: expect 0x%x but got 0x%lx\n", __LINE__, 0x03020100, output[0]); + error_counter ++; + } + if (output[1] != 0x0504) + { + + printf("ERROR #%d: expect 0x%x but got 0x%lx\n", __LINE__, 0x0504, output[1]); + error_counter ++; + } + if (output[2] != 6) + { + + printf("ERROR #%d: expect 0x%x but got 0x%lx\n", __LINE__, 6, output[2]); + error_counter ++; + } + if (output[3] != 0x0807) + { + + printf("ERROR #%d: expect 0x%x but got 0x%lx\n", __LINE__, 0x0807, output[3]); + error_counter ++; + } + if (output[4] != 0x0c0b0a09) + { + + printf("ERROR #%d: expect 0x%x but got 0x%lx\n", __LINE__, 0x0c0b0a09, output[4]); + error_counter ++; + } + if (output[5] != 0) + { + + printf("ERROR #%d: expect 0x%x but got 0x%lx\n", __LINE__, 0, output[5]); + error_counter ++; + } +#endif + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_ux_utility_descriptor_struct_test.c b/test/regression/usbx_ux_utility_descriptor_struct_test.c new file mode 100644 index 00000000..e821abcf --- /dev/null +++ b/test/regression/usbx_ux_utility_descriptor_struct_test.c @@ -0,0 +1,192 @@ +/* This test is designed to test the ux_utility_descriptor_parse. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_test.h" + +#include "ux_device_class_dfu.h" +#include "ux_host_class_audio.h" +#include "ux_host_class_cdc_ecm.h" +#include "ux_host_class_hid.h" +#include "ux_host_class_hub.h" +#include "ux_host_class_pima.h" +#include "ux_host_class_video.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + + +/* Define USBX test global variables. */ + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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); + } + } +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_utility_descriptor_struct_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; + + /* Inform user. */ + printf("Running ux_utility_descriptor_ structures Test...................... "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + + /* Print STD framework descriptor's sizes */ + printf("\n"); + printf("Descriptor %7s %7s %7s\n", "nFields", "Size4", "SizeNew"); + printf("Device %7d %7d %7u\n", UX_DEVICE_DESCRIPTOR_ENTRIES, UX_DEVICE_DESCRIPTOR_ENTRIES * 4, (unsigned)_ux_utility_descriptor_parse_size(_ux_system_device_descriptor_structure, UX_DEVICE_DESCRIPTOR_ENTRIES, 0x3u)); + printf("Configuration %7d %7d %7u\n", UX_CONFIGURATION_DESCRIPTOR_ENTRIES, UX_CONFIGURATION_DESCRIPTOR_ENTRIES * 4, (unsigned)_ux_utility_descriptor_parse_size(_ux_system_configuration_descriptor_structure, UX_CONFIGURATION_DESCRIPTOR_ENTRIES, 0x3u)); + printf("Interface %7d %7d %7u\n", UX_INTERFACE_DESCRIPTOR_ENTRIES, UX_INTERFACE_DESCRIPTOR_ENTRIES * 4, (unsigned)_ux_utility_descriptor_parse_size(_ux_system_interface_descriptor_structure, UX_INTERFACE_DESCRIPTOR_ENTRIES, 0x3u)); + printf("Endpoint %7d %7d %7u\n", UX_ENDPOINT_DESCRIPTOR_ENTRIES, UX_ENDPOINT_DESCRIPTOR_ENTRIES * 4, (unsigned)_ux_utility_descriptor_parse_size(_ux_system_endpoint_descriptor_structure, UX_ENDPOINT_DESCRIPTOR_ENTRIES, 0x3u)); + + /* Test struct parse sizes. */ + UX_TEST_ASSERT((_ux_utility_descriptor_parse_size(_ux_system_endpoint_descriptor_structure, UX_ENDPOINT_DESCRIPTOR_ENTRIES, 0x3u)) == sizeof(UX_ENDPOINT_DESCRIPTOR)); + UX_TEST_ASSERT((_ux_utility_descriptor_parse_size(_ux_system_device_descriptor_structure, UX_DEVICE_DESCRIPTOR_ENTRIES, 0x3u)) == sizeof(UX_DEVICE_DESCRIPTOR)); + UX_TEST_ASSERT((_ux_utility_descriptor_parse_size(_ux_system_configuration_descriptor_structure, UX_CONFIGURATION_DESCRIPTOR_ENTRIES, 0x3u)) == sizeof(UX_CONFIGURATION_DESCRIPTOR)); + UX_TEST_ASSERT((_ux_utility_descriptor_parse_size(_ux_system_interface_descriptor_structure, UX_INTERFACE_DESCRIPTOR_ENTRIES, 0x3u)) == sizeof(UX_INTERFACE_DESCRIPTOR)); + UX_TEST_ASSERT((_ux_utility_descriptor_parse_size(_ux_system_interface_association_descriptor_structure, UX_INTERFACE_ASSOCIATION_DESCRIPTOR_ENTRIES, 0x3u)) == sizeof(UX_INTERFACE_ASSOCIATION_DESCRIPTOR)); + UX_TEST_ASSERT((_ux_utility_descriptor_parse_size(_ux_system_string_descriptor_structure, UX_STRING_DESCRIPTOR_ENTRIES, 0x3u)) == sizeof(UX_STRING_DESCRIPTOR)); + + UX_TEST_ASSERT((_ux_utility_descriptor_parse_size(_ux_system_dfu_functional_descriptor_structure, UX_DFU_FUNCTIONAL_DESCRIPTOR_ENTRIES, 0x3u)) == sizeof(UX_DFU_FUNCTIONAL_DESCRIPTOR)); + + UX_TEST_ASSERT((_ux_utility_descriptor_parse_size(_ux_system_bos_descriptor_structure, UX_BOS_DESCRIPTOR_ENTRIES, 0x3u)) == sizeof(UX_BOS_DESCRIPTOR)); + UX_TEST_ASSERT((_ux_utility_descriptor_parse_size(_ux_system_usb_2_0_extension_descriptor_structure, UX_USB_2_0_EXTENSION_DESCRIPTOR_ENTRIES, 0x3u)) == sizeof(UX_USB_2_0_EXTENSION_DESCRIPTOR)); + UX_TEST_ASSERT((_ux_utility_descriptor_parse_size(_ux_system_container_id_descriptor_structure, UX_CONTAINER_ID_DESCRIPTOR_ENTRIES, 0x3u)) == sizeof(UX_CONTAINER_ID_DESCRIPTOR)); + + UX_TEST_ASSERT((_ux_utility_descriptor_parse_size(_ux_system_class_audio_interface_descriptor_structure, UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_ENTRIES, 0x3u)) == sizeof(UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR)); + UX_TEST_ASSERT((_ux_utility_descriptor_parse_size(_ux_system_class_audio_input_terminal_descriptor_structure, UX_HOST_CLASS_AUDIO_INPUT_TERMINAL_DESCRIPTOR_ENTRIES, 0x3u)) == sizeof(UX_HOST_CLASS_AUDIO_INPUT_TERMINAL_DESCRIPTOR)); + UX_TEST_ASSERT((_ux_utility_descriptor_parse_size(_ux_system_class_audio_output_terminal_descriptor_structure, UX_HOST_CLASS_AUDIO_OUTPUT_TERMINAL_DESCRIPTOR_ENTRIES, 0x3u)) == sizeof(UX_HOST_CLASS_AUDIO_OUTPUT_TERMINAL_DESCRIPTOR)); + UX_TEST_ASSERT((_ux_utility_descriptor_parse_size(_ux_system_class_audio_feature_unit_descriptor_structure, UX_HOST_CLASS_AUDIO_FEATURE_UNIT_DESCRIPTOR_ENTRIES, 0x3u)) == sizeof(UX_HOST_CLASS_AUDIO_FEATURE_UNIT_DESCRIPTOR)); + UX_TEST_ASSERT((_ux_utility_descriptor_parse_size(_ux_system_class_audio_streaming_interface_descriptor_structure, UX_HOST_CLASS_AUDIO_STREAMING_INTERFACE_DESCRIPTOR_ENTRIES, 0x3u)) == sizeof(UX_HOST_CLASS_AUDIO_STREAMING_INTERFACE_DESCRIPTOR)); + UX_TEST_ASSERT((_ux_utility_descriptor_parse_size(_ux_system_class_audio_streaming_endpoint_descriptor_structure, UX_HOST_CLASS_AUDIO_STREAMING_ENDPOINT_DESCRIPTOR_ENTRIES, 0x3u)) == sizeof(UX_HOST_CLASS_AUDIO_STREAMING_ENDPOINT_DESCRIPTOR)); + + UX_TEST_ASSERT((_ux_utility_descriptor_parse_size(_ux_system_hid_descriptor_structure, UX_HID_DESCRIPTOR_ENTRIES, 0x3u)) == sizeof(UX_HID_DESCRIPTOR)); + + UX_TEST_ASSERT((_ux_utility_descriptor_parse_size(_ux_system_class_pima_storage_structure, 8, 0x3u)) == 4*7); + UX_TEST_ASSERT((_ux_utility_descriptor_parse_size(_ux_system_class_pima_object_structure, 15, 0x3u)) == 4*14); + + UX_TEST_ASSERT((_ux_utility_descriptor_parse_size(_ux_system_ecm_interface_descriptor_structure, UX_HOST_CLASS_CDC_ECM_INTERFACE_DESCRIPTOR_ENTRIES, 0x3u)) == sizeof(UX_HOST_CLASS_ECM_INTERFACE_DESCRIPTOR)); + + UX_TEST_ASSERT((_ux_utility_descriptor_parse_size(_ux_system_hub_descriptor_structure, UX_HUB_DESCRIPTOR_ENTRIES, 0x3u)) == sizeof(UX_HUB_DESCRIPTOR)); + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_ux_utility_event_flags_test.c b/test/regression/usbx_ux_utility_event_flags_test.c new file mode 100644 index 00000000..33d3df82 --- /dev/null +++ b/test/regression/usbx_ux_utility_event_flags_test.c @@ -0,0 +1,169 @@ +/* This test is designed to test the ux_utility_event_flags. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +/* Define the counters used in the test application... */ + +static CHAR *stack_pointer; +static CHAR *memory_pointer; + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +/* Define USBX test global variables. */ + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +/* Simulator actions. */ + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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); + } + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_utility_event_flags_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; + + /* Inform user. */ + printf("Running ux_utility_event_flags... Test.............................. "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation 0", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d: thread create fail 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Reset threads. */ + _ux_utility_memory_set(&ux_test_thread_simulation_1, 0, sizeof(ux_test_thread_simulation_1)); +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ +UINT status; +TX_EVENT_FLAGS_GROUP test_flags; + + error_callback_ignore = UX_TRUE; + + status = _ux_utility_event_flags_create(&test_flags, "test flags"); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: error 0x%x\n", __LINE__, status); + error_counter ++; + } + + status = _ux_utility_event_flags_create(&test_flags, "test flags"); + if (status == UX_SUCCESS) + { + printf("ERROR #%d: expect fail\n", __LINE__); + error_counter ++; + } + + /* Check for errors. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static void ux_test_thread_simulation_1_entry(ULONG arg) +{ + while(1) + { + _ux_utility_delay_ms(100); + } +} diff --git a/test/regression/usbx_ux_utility_memory_safe_test.c b/test/regression/usbx_ux_utility_memory_safe_test.c new file mode 100644 index 00000000..52bb04bb --- /dev/null +++ b/test/regression/usbx_ux_utility_memory_safe_test.c @@ -0,0 +1,458 @@ +/* This test is designed to test the ux_utility_memory_.... */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors. */ +#define DPUMP_IFC_DESC(ifc, alt, nb_ep) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), (alt), (nb_ep), 0x99, 0x99, 0x99, 0x00, + +#define DPUMP_IFC_EP_DESC(epaddr, eptype, epsize) \ + /* Endpoint descriptor */\ + 0x07, 0x05, (epaddr), (eptype), LSB(epsize), MSB(epsize), 0x01, + +#define DPUMP_IFC_DESC_ALL_LEN(nb_ep) (9 + (nb_ep) * 7) + +#define CFG_DESC_ALL_LEN (CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN(4)) + +#define CFG_DESC_ALL \ + CFG_DESC(CFG_DESC_ALL_LEN, 1, 1)\ + DPUMP_IFC_DESC(0, 0, 4)\ + DPUMP_IFC_EP_DESC(0x81, 2, 64)\ + DPUMP_IFC_EP_DESC(0x02, 2, 64)\ + DPUMP_IFC_EP_DESC(0x83, 1, 64)\ + DPUMP_IFC_EP_DESC(0x84, 3, 64)\ + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC_ALL +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC_ALL +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +/* Simulator actions. */ + +static UX_TEST_HCD_SIM_ACTION endpoint0x83_create_del_skip[] = { +/* 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_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x83, UX_NULL, 0, 0, + UX_SUCCESS}, +{ UX_HCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x83, UX_NULL, 0, 0, + UX_SUCCESS}, +{ 0 } +}; + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 break_on_dpump_ready(VOID) +{ + +UINT status; +UX_HOST_CLASS *class; + + /* Find the main data pump container. */ + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class); + if (status != UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + /* Find the instance. */ + status = ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump); + if (status != UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + if (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + + +static UINT test_ux_device_class_dpump_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + switch(command->ux_slave_class_command_request) + { + case UX_SLAVE_CLASS_COMMAND_INITIALIZE: + case UX_SLAVE_CLASS_COMMAND_QUERY: + case UX_SLAVE_CLASS_COMMAND_CHANGE: + return UX_SUCCESS; + + default: + return UX_NO_CLASS_MATCH; + } +} + +static UINT test_ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command) +{ + switch (command -> ux_host_class_command_request) + { + case UX_HOST_CLASS_COMMAND_QUERY: + default: + return _ux_host_class_dpump_entry(command); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_utility_memory_safe_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +CHAR *rpool_start; +CHAR *cpool_start; +ULONG rpool_size; +ULONG cpool_size; +VOID *ptr; +ULONG base_pool_free; +ULONG ref_pool_free; +VOID *ref_mem_ptr; + + /* Inform user. */ + printf("Running ux_utility_memory_xxx_safe Test............................. "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_memory; + memory_pointer = stack_pointer + (UX_TEST_STACK_SIZE * 2); + + rpool_start = memory_pointer; + rpool_size = UX_TEST_MEMORY_SIZE; + cpool_start = memory_pointer + UX_TEST_MEMORY_SIZE; + cpool_size = UX_TEST_MEMORY_SIZE; + + /* Initialize USBX Memory. */ + status = ux_system_initialize(rpool_start, rpool_size, cpool_start, cpool_size); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Log base free level. */ + base_pool_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + + /* Allocate regular. */ + ref_mem_ptr = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, 16); + if (ref_mem_ptr == UX_NULL) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + ref_pool_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + ux_utility_memory_free(ref_mem_ptr); + if (base_pool_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Allocate safe. */ + ptr = _ux_utility_memory_allocate_add_safe(UX_NO_ALIGN, UX_REGULAR_MEMORY, 3, 13); + if (ptr != ref_mem_ptr || + ref_pool_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + ux_utility_memory_free(ptr); + if (base_pool_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + ptr = _ux_utility_memory_allocate_mulc_safe(UX_NO_ALIGN, UX_REGULAR_MEMORY, 2, 8); + if (ptr != ref_mem_ptr || + ref_pool_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + ux_utility_memory_free(ptr); + if (base_pool_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + ptr = _ux_utility_memory_allocate_mulv_safe(UX_NO_ALIGN, UX_REGULAR_MEMORY, 16, 1); + if (ptr != ref_mem_ptr || + ref_pool_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + ux_utility_memory_free(ptr); + if (base_pool_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Allocate safe overflow. */ + ptr = _ux_utility_memory_allocate_add_safe(UX_NO_ALIGN, UX_REGULAR_MEMORY, 0xFFFFFFFFul - 13 + 1, 13); + if (ptr != UX_NULL || + base_pool_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + ptr = _ux_utility_memory_allocate_mulc_safe(UX_NO_ALIGN, UX_REGULAR_MEMORY, 0xFFFFFFFFul / 8 + 1, 8); + if (ptr != UX_NULL || + base_pool_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + ptr = _ux_utility_memory_allocate_mulv_safe(UX_NO_ALIGN, UX_REGULAR_MEMORY, 0xFFFFFFFFul / 16 + 1, 16); + if (ptr != UX_NULL || + base_pool_free != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Uninitialize */ + ux_system_uninitialize(); + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} \ No newline at end of file diff --git a/test/regression/usbx_ux_utility_memory_test.c b/test/regression/usbx_ux_utility_memory_test.c new file mode 100644 index 00000000..72be3d97 --- /dev/null +++ b/test/regression/usbx_ux_utility_memory_test.c @@ -0,0 +1,570 @@ +/* This test is designed to test the ux_utility_memory_.... */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors. */ +#define DPUMP_IFC_DESC(ifc, alt, nb_ep) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), (alt), (nb_ep), 0x99, 0x99, 0x99, 0x00, + +#define DPUMP_IFC_EP_DESC(epaddr, eptype, epsize) \ + /* Endpoint descriptor */\ + 0x07, 0x05, (epaddr), (eptype), LSB(epsize), MSB(epsize), 0x01, + +#define DPUMP_IFC_DESC_ALL_LEN(nb_ep) (9 + (nb_ep) * 7) + +#define CFG_DESC_ALL_LEN (CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN(4)) + +#define CFG_DESC_ALL \ + CFG_DESC(CFG_DESC_ALL_LEN, 1, 1)\ + DPUMP_IFC_DESC(0, 0, 4)\ + DPUMP_IFC_EP_DESC(0x81, 2, 64)\ + DPUMP_IFC_EP_DESC(0x02, 2, 64)\ + DPUMP_IFC_EP_DESC(0x83, 1, 64)\ + DPUMP_IFC_EP_DESC(0x84, 3, 64)\ + +extern UCHAR ux_test_speed_up_mem_allocate_until_flagged; + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC_ALL +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC_ALL +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +/* Simulator actions. */ + +static UX_TEST_HCD_SIM_ACTION endpoint0x83_create_del_skip[] = { +/* 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_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x83, UX_NULL, 0, 0, + UX_SUCCESS}, +{ UX_HCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x83, UX_NULL, 0, 0, + UX_SUCCESS}, +{ 0 } +}; + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 break_on_dpump_ready(VOID) +{ + +UINT status; +UX_HOST_CLASS *class; + + /* Find the main data pump container. */ + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class); + if (status != UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + /* Find the instance. */ + status = ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump); + if (status != UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + if (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + + +static UINT test_ux_device_class_dpump_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + switch(command->ux_slave_class_command_request) + { + case UX_SLAVE_CLASS_COMMAND_INITIALIZE: + case UX_SLAVE_CLASS_COMMAND_QUERY: + case UX_SLAVE_CLASS_COMMAND_CHANGE: + return UX_SUCCESS; + + default: + return UX_NO_CLASS_MATCH; + } +} + +static UINT test_ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command) +{ + switch (command -> ux_host_class_command_request) + { + case UX_HOST_CLASS_COMMAND_QUERY: + default: + return _ux_host_class_dpump_entry(command); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_utility_memory_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +CHAR *rpool_start; +CHAR *cpool_start; +ULONG rpool_size; +ULONG cpool_size; +ULONG rpool_free[2]; +ULONG cpool_free[2]; +VOID *ptr; +UINT n, i, j; +const CHAR flags[] = { + UX_REGULAR_MEMORY, UX_CACHE_SAFE_MEMORY, 0xFF +}; +const CHAR expect_error[] = { + UX_FALSE, UX_FALSE, UX_TRUE +}; +const ULONG aligns[] = { + UX_NO_ALIGN, /* 0 */ + UX_ALIGN_MIN, /* 0xf */ + UX_SAFE_ALIGN, /* 0xffffffff */ + UX_ALIGN_32, + UX_ALIGN_64, + UX_ALIGN_128, + UX_ALIGN_256, + UX_ALIGN_512, + UX_ALIGN_1024, + UX_ALIGN_2048, + UX_ALIGN_4096, + UX_MAX_SCATTER_GATHER_ALIGNMENT, +}; + + /* Inform user. */ + printf("Running ux_utility_memory_... Test.................................. "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_memory; + memory_pointer = stack_pointer + (UX_TEST_STACK_SIZE * 2); + + for (n = 0; n < 3; n ++) + { + + switch(n) + { + case 0: + rpool_start = memory_pointer; + rpool_size = UX_TEST_MEMORY_SIZE; + cpool_start = memory_pointer + UX_TEST_MEMORY_SIZE; + cpool_size = UX_TEST_MEMORY_SIZE; + break; + case 1: + rpool_start = memory_pointer + UX_TEST_MEMORY_SIZE; + rpool_size = UX_TEST_MEMORY_SIZE; + cpool_start = memory_pointer; + cpool_size = UX_TEST_MEMORY_SIZE; + break; + default: + rpool_start = memory_pointer; + rpool_size = UX_TEST_MEMORY_SIZE * 2; + cpool_start = UX_NULL; + cpool_size = 0; + } + + /* Initialize USBX Memory. */ + status = ux_system_initialize(rpool_start, rpool_size, cpool_start, cpool_size); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d.%d\n", __LINE__, n); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + for (j = 0; j < sizeof(aligns)/sizeof(aligns[0]); j ++) + { + /* Save memory level. */ + rpool_free[0] = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + cpool_free[0] = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available; + + error_callback_ignore = UX_TRUE; + + /* Allocate all. */ + ux_test_utility_sim_mem_allocate_until_align_flagged(0, aligns[j], UX_REGULAR_MEMORY); + ux_test_utility_sim_mem_allocate_until_align_flagged(0, aligns[j], UX_CACHE_SAFE_MEMORY); + + rpool_free[1] = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + cpool_free[1] = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available; + + /* Check. */ + if (rpool_free[0] <= rpool_free[1]) + { + + printf("ERROR #%d.%d.%d: Expect regular pool level down\n", __LINE__, n, j); + error_counter ++; + } + + if (cpool_free[0] <= cpool_free[1] && cpool_start) + { + + printf("ERROR #%d.%d.%d: Expect cache safe pool level down\n", __LINE__, n, j); + error_counter ++; + } + + error_callback_ignore = UX_FALSE; + + /* Free All. */ + ux_test_utility_sim_mem_free_all_flagged(UX_REGULAR_MEMORY); + ux_test_utility_sim_mem_free_all_flagged(UX_CACHE_SAFE_MEMORY); + + rpool_free[1] = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + cpool_free[1] = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available; + + /* Check. */ + if (rpool_free[0] != rpool_free[1]) + { + + printf("ERROR #%d.%d.%d: Regular pool level diff %lu -> %lu\n", __LINE__, n, j, rpool_free[0], rpool_free[1]); + error_counter ++; + } + if (cpool_free[0] != cpool_free[1]) + { + + printf("ERROR #%d.%d.%d: Cache safe pool level diff %lu -> %lu\n", __LINE__, n, j, cpool_free[0], cpool_free[1]); + error_counter ++; + } + + for (i = 0; i < sizeof(flags); i ++) + { + + /* Save pool level. */ + rpool_free[0] = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + cpool_free[0] = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available; + + /* Error callback setting. */ + error_callback_ignore = expect_error[i]; + + /* Allocate. */ + ptr = ux_utility_memory_allocate(aligns[j], flags[i], 8); + + /* Error case. */ + if (expect_error[i]) + { + + if (ptr != UX_NULL) + { + + printf("ERROR #%d.%d.%d.%d: Expect fail\n", __LINE__, n, j, i); + error_counter ++; + } + } + else + { + + /* No error. */ + if (ptr == UX_NULL) + { + + printf("ERROR #%d.%d.%d.%d: memory allocate fail\n", __LINE__, n, j, i); + error_counter ++; + } + + /* Save pool level. */ + rpool_free[1] = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + cpool_free[1] = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available; + + if (!(rpool_free[1] < rpool_free[0] || cpool_free[1] < cpool_free[0])) + { + + printf("ERROR #%d.%d.%d.%d: Expect pool level down\n", __LINE__, n, j, i); + error_counter ++; + } + + ux_utility_memory_free(ptr); + } + + /* Save pool level. */ + rpool_free[1] = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + cpool_free[1] = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available; + + if (rpool_free[0] != rpool_free[1]) + { + + printf("ERROR #%d.%d.%d.%d: Expect no regular pool change but %lu -> %lu\n", __LINE__, n, j, i, rpool_free[0], rpool_free[1]); + error_counter ++; + } + if (cpool_free[0] != cpool_free[1]) + { + + printf("ERROR #%d.%d.%d.%d: Expect no cache safe pool change but %lu -> %lu\n", __LINE__, n, j, i, cpool_free[0], cpool_free[1]); + error_counter ++; + } + + } + } + + /* Uninitialize */ + ux_system_uninitialize(); + + } + + /* Test the case where there isn't enough left over memory for a new memory block after needing to do an alignment. */ + { + static UCHAR dummy_memory[1024]; + + ALIGN_TYPE int_ptr = (ALIGN_TYPE) dummy_memory; + + int_ptr += 2*sizeof(UX_MEMORY_BLOCK); + + int_ptr += 31; + int_ptr &= ~(31); + + int_ptr += 1; + int_ptr -= sizeof(UX_MEMORY_BLOCK); + + UX_MEMORY_BLOCK *dummy_block = (UX_MEMORY_BLOCK *) (int_ptr - sizeof(UX_MEMORY_BLOCK)); + // dummy_block->ux_memory_block_next = UX_NULL; + // dummy_block->ux_memory_block_previous = UX_NULL; + // dummy_block->ux_memory_block_size = (16 + 8 + 31 + ((sizeof(UCHAR *)) + (sizeof(ALIGN_TYPE))) + 1; + // dummy_block->ux_memory_block_status = UX_MEMORY_UNUSED; + + // _ux_system->ux_system_regular_memory_pool_start = dummy_block; + // _ux_system->ux_system_regular_memory_pool_size = dummy_block->ux_memory_block_size + sizeof(UX_MEMORY_BLOCK); + ULONG dummy_block_size = (16 + 8 + 31 + sizeof(UX_MEMORY_BLOCK)) + 1; + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start = (UCHAR*)dummy_block; + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available = dummy_block_size; + + ux_utility_memory_allocate(31, UX_REGULAR_MEMORY, 16); + } + + /* Test allocate memory of size 0. */ + rpool_free[0] = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + ptr = _ux_utility_memory_allocate_mulc_safe(UX_NO_ALIGN, UX_REGULAR_MEMORY, 1, 0); + if (ptr) + { + _ux_utility_memory_free(ptr); + } + if (rpool_free[0] != _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available) + { + printf("ERROR %d : expect no pool level change but %ld -> %ld\n", __LINE__, rpool_free[0], _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + error_counter ++; + } + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} \ No newline at end of file diff --git a/test/regression/usbx_ux_utility_mutex_test.c b/test/regression/usbx_ux_utility_mutex_test.c new file mode 100644 index 00000000..545bf18d --- /dev/null +++ b/test/regression/usbx_ux_utility_mutex_test.c @@ -0,0 +1,424 @@ +/* This test is designed to test the ux_utility_mutex_.... */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors. */ +#define DPUMP_IFC_DESC(ifc, alt, nb_ep) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), (alt), (nb_ep), 0x99, 0x99, 0x99, 0x00, + +#define DPUMP_IFC_EP_DESC(epaddr, eptype, epsize) \ + /* Endpoint descriptor */\ + 0x07, 0x05, (epaddr), (eptype), LSB(epsize), MSB(epsize), 0x01, + +#define DPUMP_IFC_DESC_ALL_LEN(nb_ep) (9 + (nb_ep) * 7) + +#define CFG_DESC_ALL_LEN (CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN(4)) + +#define CFG_DESC_ALL \ + CFG_DESC(CFG_DESC_ALL_LEN, 1, 1)\ + DPUMP_IFC_DESC(0, 0, 4)\ + DPUMP_IFC_EP_DESC(0x81, 2, 64)\ + DPUMP_IFC_EP_DESC(0x02, 2, 64)\ + DPUMP_IFC_EP_DESC(0x83, 1, 64)\ + DPUMP_IFC_EP_DESC(0x84, 3, 64)\ + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +static TX_MUTEX test_mutex; + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC_ALL +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC_ALL +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +/* Simulator actions. */ + +static UX_TEST_HCD_SIM_ACTION endpoint0x83_create_del_skip[] = { +/* 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_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x83, UX_NULL, 0, 0, + UX_SUCCESS}, +{ UX_HCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x83, UX_NULL, 0, 0, + UX_SUCCESS}, +{ 0 } +}; + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 break_on_dpump_ready(VOID) +{ + +UINT status; +UX_HOST_CLASS *class; + + /* Find the main data pump container. */ + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class); + if (status != UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + /* Find the instance. */ + status = ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump); + if (status != UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + if (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + + +static UINT test_ux_device_class_dpump_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + switch(command->ux_slave_class_command_request) + { + case UX_SLAVE_CLASS_COMMAND_INITIALIZE: + case UX_SLAVE_CLASS_COMMAND_QUERY: + case UX_SLAVE_CLASS_COMMAND_CHANGE: + return UX_SUCCESS; + + default: + return UX_NO_CLASS_MATCH; + } +} + +static UINT test_ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command) +{ + switch (command -> ux_host_class_command_request) + { + case UX_HOST_CLASS_COMMAND_QUERY: + default: + return _ux_host_class_dpump_entry(command); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_utility_mutex_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +CHAR *rpool_start; +CHAR *cpool_start; +const CHAR flags[] = { + UX_REGULAR_MEMORY, UX_CACHE_SAFE_MEMORY, 0xFF +}; +const CHAR expect_error[] = { + UX_FALSE, UX_FALSE, UX_TRUE +}; + + /* Inform user. */ + printf("Running ux_utility_mutex_... Test................................... "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_memory; + memory_pointer = stack_pointer + (UX_TEST_STACK_SIZE * 2); + + rpool_start = memory_pointer; + cpool_start = memory_pointer + UX_TEST_MEMORY_SIZE; + + /* Initialize USBX Memory. */ + status = ux_system_initialize(rpool_start, UX_TEST_MEMORY_SIZE, cpool_start, UX_TEST_MEMORY_SIZE); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ +UINT status; + + /* Ignore errors. */ + error_callback_ignore = UX_TRUE; + + /* Mutex create. */ + status = ux_utility_mutex_create(&test_mutex, "test_mutex"); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: mutex create fail\n", __LINE__); + test_control_return(1); + } + + /* Mutex on, expect no error. */ + error_callback_counter = 0; + ux_utility_mutex_on(&test_mutex); + if (error_callback_counter > 0) + { + + printf("ERROR #%d: mutex on fail\n", __LINE__); + error_counter ++; + } + + /* Mutex off, expect no error. */ + error_callback_counter = 0; + ux_utility_mutex_off(&test_mutex); + if (error_callback_counter > 0) + { + + printf("ERROR #%d: mutex off fail\n", __LINE__); + error_counter ++; + } + + /* Mutex create again, expect error. */ + status = ux_utility_mutex_create(&test_mutex, "test_mutex"); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: mutex create must fail\n", __LINE__); + test_control_return(1); + } + + /* Mutex delete. */ + error_callback_counter = 0; + ux_utility_mutex_delete(&test_mutex); + if (error_callback_counter > 0) + { + + printf("ERROR #%d: mutex delete fail\n", __LINE__); + test_control_return(1); + } + + /* Mutex on, expect error. */ + error_callback_counter = 0; + ux_utility_mutex_on(&test_mutex); + if (error_callback_counter == 0) + { + + printf("ERROR #%d: expect mutex on error\n", __LINE__); + error_counter ++; + } + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} \ No newline at end of file diff --git a/test/regression/usbx_ux_utility_pci_class_scan_test.c b/test/regression/usbx_ux_utility_pci_class_scan_test.c new file mode 100644 index 00000000..81e00895 --- /dev/null +++ b/test/regression/usbx_ux_utility_pci_class_scan_test.c @@ -0,0 +1,385 @@ +/* This test is designed to test the _ux_utility_pci_class_scan. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors. */ +#define DPUMP_IFC_DESC(ifc, alt, nb_ep) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), (alt), (nb_ep), 0x99, 0x99, 0x99, 0x00, + +#define DPUMP_IFC_EP_DESC(epaddr, eptype, epsize) \ + /* Endpoint descriptor */\ + 0x07, 0x05, (epaddr), (eptype), LSB(epsize), MSB(epsize), 0x01, + +#define DPUMP_IFC_DESC_ALL_LEN(nb_ep) (9 + (nb_ep) * 7) + +#define CFG_DESC_ALL_LEN (CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN(4)) + +#define CFG_DESC_ALL \ + CFG_DESC(CFG_DESC_ALL_LEN, 1, 1)\ + DPUMP_IFC_DESC(0, 0, 4)\ + DPUMP_IFC_EP_DESC(0x81, 2, 64)\ + DPUMP_IFC_EP_DESC(0x02, 2, 64)\ + DPUMP_IFC_EP_DESC(0x83, 1, 64)\ + DPUMP_IFC_EP_DESC(0x84, 3, 64)\ + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC_ALL +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC_ALL +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +/* Simulator actions. */ + +static UX_TEST_HCD_SIM_ACTION endpoint0x83_create_del_skip[] = { +/* 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_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x83, UX_NULL, 0, 0, + UX_SUCCESS}, +{ UX_HCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x83, UX_NULL, 0, 0, + UX_SUCCESS}, +{ 0 } +}; + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 break_on_dpump_ready(VOID) +{ + +UINT status; +UX_HOST_CLASS *class; + + /* Find the main data pump container. */ + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class); + if (status != UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + /* Find the instance. */ + status = ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump); + if (status != UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + if (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + + +static UINT test_ux_device_class_dpump_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + switch(command->ux_slave_class_command_request) + { + case UX_SLAVE_CLASS_COMMAND_INITIALIZE: + case UX_SLAVE_CLASS_COMMAND_QUERY: + case UX_SLAVE_CLASS_COMMAND_CHANGE: + return UX_SUCCESS; + + default: + return UX_NO_CLASS_MATCH; + } +} + +static UINT test_ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command) +{ + switch (command -> ux_host_class_command_request) + { + case UX_HOST_CLASS_COMMAND_QUERY: + default: + return _ux_host_class_dpump_entry(command); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_utility_pci_class_scan_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; + + /* Inform user. */ + printf("Running ux_utility_pci_class_scan Test ............................. "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + + +ULONG outp_log[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +ULONG inp_seq[] = {0x12345678}; +ULONG dev_n, bus_n, func_n; +UINT status; + + ux_test_sim_outp_logbuf_set(outp_log, 12); + ux_test_sim_inp_sequence_set(inp_seq, 1); + + status = _ux_utility_pci_class_scan(0xF, 0, 0, 0, &bus_n, &dev_n, &func_n); + if (ux_test_sim_outp_log_count() == 0) + { + printf("ERROR #%d: expected operation but there is no\n", __LINE__); + error_counter ++; + } + if (status != UX_ERROR) + { + printf("ERROR #%d: expected 0x%x but got 0x%x\n", __LINE__, UX_ERROR, status); + error_counter ++; + } + + inp_seq[0] = 0x18 << 8; + ux_test_sim_inp_sequence_set(inp_seq, 1); + status = _ux_utility_pci_class_scan(0x18, 0, 0, 0, &bus_n, &dev_n, &func_n); + if (ux_test_sim_outp_log_count() == 0) + { + printf("ERROR #%d: expected operation but there is no\n", __LINE__); + error_counter ++; + } + if (status != UX_SUCCESS) + { + printf("ERROR #%d: expected 0x%x but got 0x%x\n", __LINE__, UX_SUCCESS, status); + error_counter ++; + } + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_ux_utility_pci_read_test.c b/test/regression/usbx_ux_utility_pci_read_test.c new file mode 100644 index 00000000..700d48b6 --- /dev/null +++ b/test/regression/usbx_ux_utility_pci_read_test.c @@ -0,0 +1,388 @@ +/* This test is designed to test the ux_utility_pci_read. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors. */ +#define DPUMP_IFC_DESC(ifc, alt, nb_ep) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), (alt), (nb_ep), 0x99, 0x99, 0x99, 0x00, + +#define DPUMP_IFC_EP_DESC(epaddr, eptype, epsize) \ + /* Endpoint descriptor */\ + 0x07, 0x05, (epaddr), (eptype), LSB(epsize), MSB(epsize), 0x01, + +#define DPUMP_IFC_DESC_ALL_LEN(nb_ep) (9 + (nb_ep) * 7) + +#define CFG_DESC_ALL_LEN (CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN(4)) + +#define CFG_DESC_ALL \ + CFG_DESC(CFG_DESC_ALL_LEN, 1, 1)\ + DPUMP_IFC_DESC(0, 0, 4)\ + DPUMP_IFC_EP_DESC(0x81, 2, 64)\ + DPUMP_IFC_EP_DESC(0x02, 2, 64)\ + DPUMP_IFC_EP_DESC(0x83, 1, 64)\ + DPUMP_IFC_EP_DESC(0x84, 3, 64)\ + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC_ALL +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC_ALL +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +/* Simulator actions. */ + +static UX_TEST_HCD_SIM_ACTION endpoint0x83_create_del_skip[] = { +/* 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_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x83, UX_NULL, 0, 0, + UX_SUCCESS}, +{ UX_HCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x83, UX_NULL, 0, 0, + UX_SUCCESS}, +{ 0 } +}; + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 break_on_dpump_ready(VOID) +{ + +UINT status; +UX_HOST_CLASS *class; + + /* Find the main data pump container. */ + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class); + if (status != UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + /* Find the instance. */ + status = ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump); + if (status != UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + if (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + + +static UINT test_ux_device_class_dpump_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + switch(command->ux_slave_class_command_request) + { + case UX_SLAVE_CLASS_COMMAND_INITIALIZE: + case UX_SLAVE_CLASS_COMMAND_QUERY: + case UX_SLAVE_CLASS_COMMAND_CHANGE: + return UX_SUCCESS; + + default: + return UX_NO_CLASS_MATCH; + } +} + +static UINT test_ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command) +{ + switch (command -> ux_host_class_command_request) + { + case UX_HOST_CLASS_COMMAND_QUERY: + default: + return _ux_host_class_dpump_entry(command); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_utility_pci_read_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; + + /* Inform user. */ + printf("Running ux_utility_pci_read Test ................................... "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + + +ULONG output_log[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +ULONG inp_value = 0x12345678; +ULONG result; + + ux_test_sim_outp_logbuf_set(output_log, 12); + ux_test_sim_inp_sequence_set(&inp_value, 1); + result = _ux_utility_pci_read(0, 0, 0, 0, 0); + if (result != 0) + { + printf("ERROR #%d: expected 0x%x but got 0x%lx\n", __LINE__, 0, result); + error_counter ++; + } + if (ux_test_sim_outp_log_count()) + { + printf("ERROR #%d: expected no operation but there is\n", __LINE__); + error_counter ++; + ux_test_sim_outp_log_reset(); + } + result = _ux_utility_pci_read(0, 0, 0, 0, 8); + if (result != 0x78) + { + printf("ERROR #%d: expected 0x%x but got 0x%lx\n", __LINE__, 0x78, result); + error_counter ++; + } + result = _ux_utility_pci_read(0, 0, 0, 0, 16); + if (result != 0x5678) + { + printf("ERROR #%d: expected 0x%x but got 0x%lx\n", __LINE__, 0x5678, result); + error_counter ++; + } + result = _ux_utility_pci_read(0, 0, 0, 0, 32); + if (result != 0x12345678) + { + printf("ERROR #%d: expected 0x%x but got 0x%lx\n", __LINE__, 0x12345678, result); + error_counter ++; + } + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_ux_utility_pci_write_test.c b/test/regression/usbx_ux_utility_pci_write_test.c new file mode 100644 index 00000000..3125e203 --- /dev/null +++ b/test/regression/usbx_ux_utility_pci_write_test.c @@ -0,0 +1,384 @@ +/* This test is designed to test the _ux_utility_pci_write. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors. */ +#define DPUMP_IFC_DESC(ifc, alt, nb_ep) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), (alt), (nb_ep), 0x99, 0x99, 0x99, 0x00, + +#define DPUMP_IFC_EP_DESC(epaddr, eptype, epsize) \ + /* Endpoint descriptor */\ + 0x07, 0x05, (epaddr), (eptype), LSB(epsize), MSB(epsize), 0x01, + +#define DPUMP_IFC_DESC_ALL_LEN(nb_ep) (9 + (nb_ep) * 7) + +#define CFG_DESC_ALL_LEN (CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN(4)) + +#define CFG_DESC_ALL \ + CFG_DESC(CFG_DESC_ALL_LEN, 1, 1)\ + DPUMP_IFC_DESC(0, 0, 4)\ + DPUMP_IFC_EP_DESC(0x81, 2, 64)\ + DPUMP_IFC_EP_DESC(0x02, 2, 64)\ + DPUMP_IFC_EP_DESC(0x83, 1, 64)\ + DPUMP_IFC_EP_DESC(0x84, 3, 64)\ + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC_ALL +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC_ALL +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +/* Simulator actions. */ + +static UX_TEST_HCD_SIM_ACTION endpoint0x83_create_del_skip[] = { +/* 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_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x83, UX_NULL, 0, 0, + UX_SUCCESS}, +{ UX_HCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x83, UX_NULL, 0, 0, + UX_SUCCESS}, +{ 0 } +}; + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 break_on_dpump_ready(VOID) +{ + +UINT status; +UX_HOST_CLASS *class; + + /* Find the main data pump container. */ + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class); + if (status != UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + /* Find the instance. */ + status = ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump); + if (status != UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + if (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + + +static UINT test_ux_device_class_dpump_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + switch(command->ux_slave_class_command_request) + { + case UX_SLAVE_CLASS_COMMAND_INITIALIZE: + case UX_SLAVE_CLASS_COMMAND_QUERY: + case UX_SLAVE_CLASS_COMMAND_CHANGE: + return UX_SUCCESS; + + default: + return UX_NO_CLASS_MATCH; + } +} + +static UINT test_ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command) +{ + switch (command -> ux_host_class_command_request) + { + case UX_HOST_CLASS_COMMAND_QUERY: + default: + return _ux_host_class_dpump_entry(command); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_utility_pci_write_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; + + /* Inform user. */ + printf("Running ux_utility_pci_write Test .................................. "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + + +ULONG output_log[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +ULONG addr, value; + + ux_test_sim_outp_logbuf_set(output_log, 12); + _ux_utility_pci_write(0, 0, 0, 0, 1, 0); + if (ux_test_sim_outp_log_count()) + { + printf("ERROR #%d: expected no operation but there is\n", __LINE__); + error_counter ++; + ux_test_sim_outp_log_reset(); + } + _ux_utility_pci_write(0, 0, 0, 0, 2, 8); + _ux_utility_pci_write(0, 0, 0, 0, 3, 16); + _ux_utility_pci_write(0, 0, 0, 0, 4, 32); + ux_test_sim_outp_log_get(1, &addr, &value); + if (value != 2) + { + printf("ERROR #%d: expected %x but got %lx\n", __LINE__, 2, value); + error_counter ++; + } + ux_test_sim_outp_log_get(3, &addr, &value); + if (value != 3) + { + printf("ERROR #%d: expected %x but got %lx\n", __LINE__, 3, value); + error_counter ++; + } + ux_test_sim_outp_log_get(5, &addr, &value); + if (value != 4) + { + printf("ERROR #%d: expected %x but got %lx\n", __LINE__, 4, value); + error_counter ++; + } + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_ux_utility_physical_address_test.c b/test/regression/usbx_ux_utility_physical_address_test.c new file mode 100644 index 00000000..1475e6f7 --- /dev/null +++ b/test/regression/usbx_ux_utility_physical_address_test.c @@ -0,0 +1,368 @@ +/* This test is designed to test the ux_utility_physical_address. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors. */ +#define DPUMP_IFC_DESC(ifc, alt, nb_ep) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), (alt), (nb_ep), 0x99, 0x99, 0x99, 0x00, + +#define DPUMP_IFC_EP_DESC(epaddr, eptype, epsize) \ + /* Endpoint descriptor */\ + 0x07, 0x05, (epaddr), (eptype), LSB(epsize), MSB(epsize), 0x01, + +#define DPUMP_IFC_DESC_ALL_LEN(nb_ep) (9 + (nb_ep) * 7) + +#define CFG_DESC_ALL_LEN (CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN(4)) + +#define CFG_DESC_ALL \ + CFG_DESC(CFG_DESC_ALL_LEN, 1, 1)\ + DPUMP_IFC_DESC(0, 0, 4)\ + DPUMP_IFC_EP_DESC(0x81, 2, 64)\ + DPUMP_IFC_EP_DESC(0x02, 2, 64)\ + DPUMP_IFC_EP_DESC(0x83, 1, 64)\ + DPUMP_IFC_EP_DESC(0x84, 3, 64)\ + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC_ALL +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC_ALL +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +/* Simulator actions. */ + +static UX_TEST_HCD_SIM_ACTION endpoint0x83_create_del_skip[] = { +/* 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_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x83, UX_NULL, 0, 0, + UX_SUCCESS}, +{ UX_HCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x83, UX_NULL, 0, 0, + UX_SUCCESS}, +{ 0 } +}; + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 break_on_dpump_ready(VOID) +{ + +UINT status; +UX_HOST_CLASS *class; + + /* Find the main data pump container. */ + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class); + if (status != UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + /* Find the instance. */ + status = ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump); + if (status != UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + if (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + + +static UINT test_ux_device_class_dpump_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + switch(command->ux_slave_class_command_request) + { + case UX_SLAVE_CLASS_COMMAND_INITIALIZE: + case UX_SLAVE_CLASS_COMMAND_QUERY: + case UX_SLAVE_CLASS_COMMAND_CHANGE: + return UX_SUCCESS; + + default: + return UX_NO_CLASS_MATCH; + } +} + +static UINT test_ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command) +{ + switch (command -> ux_host_class_command_request) + { + case UX_HOST_CLASS_COMMAND_QUERY: + default: + return _ux_host_class_dpump_entry(command); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_utility_physical_address_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; + + /* Inform user. */ + printf("Running ux_utility_physical_address Test (and virtual).............. "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + + +VOID *pointer; + +#define TEST_ADDR ((void *)0x1234567) + pointer = _ux_utility_physical_address(TEST_ADDR); + if (pointer != TEST_ADDR) + { + printf("ERROR #%d: expected addr %p but got %p\n", __LINE__, TEST_ADDR, pointer); + error_counter ++; + } + + pointer = _ux_utility_virtual_address(TEST_ADDR); + if (pointer != TEST_ADDR) + { + printf("ERROR #%d: expected addr %p but got %p\n", __LINE__, TEST_ADDR, pointer); + error_counter ++; + } + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_ux_utility_semaphore_test.c b/test/regression/usbx_ux_utility_semaphore_test.c new file mode 100644 index 00000000..580c9768 --- /dev/null +++ b/test/regression/usbx_ux_utility_semaphore_test.c @@ -0,0 +1,187 @@ +/* This test is designed to test the ux_utility_semaphore. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +/* Define the counters used in the test application... */ + +static CHAR *stack_pointer; +static CHAR *memory_pointer; + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +/* Define USBX test global variables. */ + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +/* Simulator actions. */ + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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); + } + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_utility_semaphore_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; + + /* Inform user. */ + printf("Running ux_utility_semaphore... Test................................ "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation 0", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d: thread create fail 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Reset threads. */ + _ux_utility_memory_set(&ux_test_thread_simulation_1, 0, sizeof(ux_test_thread_simulation_1)); +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ +UINT status; +TX_SEMAPHORE test_semaphore; + + error_callback_ignore = UX_TRUE; + + status = _ux_utility_semaphore_create(&test_semaphore, "test semaphore", 1); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: sem_create 0x%x\n", __LINE__, status); + error_counter ++; + } + + status = _ux_utility_semaphore_create(&test_semaphore, "test semaphore", 1); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: sem_create must fail\n", __LINE__); + error_counter ++; + } + + status = _ux_utility_semaphore_get(&test_semaphore, 100); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: sem_get 0x%x\n", __LINE__, status); + error_counter ++; + } + + status = _ux_utility_semaphore_get(&test_semaphore, 10); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: sem_get 0x%x\n", __LINE__, status); + error_counter ++; + } + + /* Check for errors. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static void ux_test_thread_simulation_1_entry(ULONG arg) +{ + while(1) + { + _ux_utility_delay_ms(100); + } +} diff --git a/test/regression/usbx_ux_utility_string_length_check_test.c b/test/regression/usbx_ux_utility_string_length_check_test.c new file mode 100644 index 00000000..09b39cbb --- /dev/null +++ b/test/regression/usbx_ux_utility_string_length_check_test.c @@ -0,0 +1,383 @@ +/* This test is designed to test the ux_utility_string_length_check. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors. */ +#define DPUMP_IFC_DESC(ifc, alt, nb_ep) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), (alt), (nb_ep), 0x99, 0x99, 0x99, 0x00, + +#define DPUMP_IFC_EP_DESC(epaddr, eptype, epsize) \ + /* Endpoint descriptor */\ + 0x07, 0x05, (epaddr), (eptype), LSB(epsize), MSB(epsize), 0x01, + +#define DPUMP_IFC_DESC_ALL_LEN(nb_ep) (9 + (nb_ep) * 7) + +#define CFG_DESC_ALL_LEN (CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN(4)) + +#define CFG_DESC_ALL \ + CFG_DESC(CFG_DESC_ALL_LEN, 1, 1)\ + DPUMP_IFC_DESC(0, 0, 4)\ + DPUMP_IFC_EP_DESC(0x81, 2, 64)\ + DPUMP_IFC_EP_DESC(0x02, 2, 64)\ + DPUMP_IFC_EP_DESC(0x83, 1, 64)\ + DPUMP_IFC_EP_DESC(0x84, 3, 64)\ + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +static TX_TIMER test_timer; + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC_ALL +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC_ALL +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +/* Simulator actions. */ + +static UX_TEST_HCD_SIM_ACTION endpoint0x83_create_del_skip[] = { +/* 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_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x83, UX_NULL, 0, 0, + UX_SUCCESS}, +{ UX_HCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x83, UX_NULL, 0, 0, + UX_SUCCESS}, +{ 0 } +}; + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 break_on_dpump_ready(VOID) +{ + +UINT status; +UX_HOST_CLASS *class; + + /* Find the main data pump container. */ + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class); + if (status != UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + /* Find the instance. */ + status = ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump); + if (status != UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + if (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + + +static UINT test_ux_device_class_dpump_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + switch(command->ux_slave_class_command_request) + { + case UX_SLAVE_CLASS_COMMAND_INITIALIZE: + case UX_SLAVE_CLASS_COMMAND_QUERY: + case UX_SLAVE_CLASS_COMMAND_CHANGE: + return UX_SUCCESS; + + default: + return UX_NO_CLASS_MATCH; + } +} + +static UINT test_ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command) +{ + switch (command -> ux_host_class_command_request) + { + case UX_HOST_CLASS_COMMAND_QUERY: + default: + return _ux_host_class_dpump_entry(command); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_utility_string_length_check_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +CHAR *rpool_start; +CHAR *cpool_start; +const CHAR flags[] = { + UX_REGULAR_MEMORY, UX_CACHE_SAFE_MEMORY, 0xFF +}; +const CHAR expect_error[] = { + UX_FALSE, UX_FALSE, UX_TRUE +}; + + /* Inform user. */ + printf("Running ux_utility_string_length_check Test......................... "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_memory; + memory_pointer = stack_pointer + (UX_TEST_STACK_SIZE * 2); + + rpool_start = memory_pointer; + cpool_start = memory_pointer + UX_TEST_MEMORY_SIZE; + + /* Initialize USBX Memory. */ + status = ux_system_initialize(rpool_start, UX_TEST_MEMORY_SIZE, cpool_start, UX_TEST_MEMORY_SIZE); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ +UINT status; +UINT string_length; + + /* Ignore errors. */ + error_callback_ignore = UX_TRUE; + + stepinfo(">>>>>>>>> _ux_utility_string_length_check - error if string is NULL\n"); + status = _ux_utility_string_length_check(UX_NULL, &string_length, 128); + if (status != UX_ERROR) + { + printf("ERROR #%d: expect UX_ERROR\n", __LINE__); + error_counter ++; + } + + stepinfo(">>>>>>>>> _ux_utility_string_length_check - no error if string_length_ptr is NULL\n"); + status = _ux_utility_string_length_check(_ux_system_host_class_dpump_name, UX_NULL, 128); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: expect UX_SUCCESS\n", __LINE__); + error_counter ++; + } + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} \ No newline at end of file diff --git a/test/regression/usbx_ux_utility_thread_create_test.c b/test/regression/usbx_ux_utility_thread_create_test.c new file mode 100644 index 00000000..4f2e8ea2 --- /dev/null +++ b/test/regression/usbx_ux_utility_thread_create_test.c @@ -0,0 +1,195 @@ +/* This test is designed to test the ux_utility_thread_create. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +/* Define the counters used in the test application... */ + +static CHAR *stack_pointer; +static CHAR *memory_pointer; + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +/* Define USBX test global variables. */ + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +/* Simulator actions. */ + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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); + } + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_utility_thread_create_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; + + /* Inform user. */ + printf("Running ux_utility_thread_create Test............................... "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Create the simulation thread. */ + status = ux_utility_thread_create(&ux_test_thread_simulation_0, "test simulation 0", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d: thread create fail 0x%x\n", __LINE__, status); + error_counter ++; + } + + /* Reset threads. */ + _ux_utility_memory_set(&ux_test_thread_simulation_1, 0, sizeof(ux_test_thread_simulation_1)); +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ +UINT status; + + /* Create the simulation thread. */ + status = ux_utility_thread_create(&ux_test_thread_simulation_1, "test simulation 1", ux_test_thread_simulation_1_entry, 0, + stack_pointer + UX_TEST_STACK_SIZE, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d: thread create fail 0x%x\n", __LINE__, status); + error_counter ++; + } + + error_callback_ignore = UX_TRUE; + + /* Create the simulation thread. */ + status = ux_utility_thread_create(&ux_test_thread_simulation_0, "test simulation 0", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status == TX_SUCCESS) + { + + printf("ERROR #%d: thread create must fail\n", __LINE__); + error_counter ++; + } + + /* Check for errors. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static void ux_test_thread_simulation_1_entry(ULONG arg) +{ + while(1) + { + _ux_utility_delay_ms(100); + } +} diff --git a/test/regression/usbx_ux_utility_thread_identify_test.c b/test/regression/usbx_ux_utility_thread_identify_test.c new file mode 100644 index 00000000..c56ca3ad --- /dev/null +++ b/test/regression/usbx_ux_utility_thread_identify_test.c @@ -0,0 +1,198 @@ +/* This test is designed to test the ux_utility_thread_identify. */ + +#include +#include "tx_api.h" +#include "tx_thread.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +/* Define the counters used in the test application... */ + +static CHAR *stack_pointer; +static CHAR *memory_pointer; + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +/* Define USBX test global variables. */ + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +/* Simulator actions. */ + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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); + } + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_utility_thread_identify_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; + + + /* Inform user. */ + printf("Running ux_utility_thread_identify Test............................. "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Create the simulation thread. */ + status = ux_utility_thread_create(&ux_test_thread_simulation_0, "test simulation 0", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d: thread create fail 0x%x\n", __LINE__, status); + error_counter ++; + } + + /* Reset threads. */ + _ux_utility_memory_set(&ux_test_thread_simulation_1, 0, sizeof(ux_test_thread_simulation_1)); +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + +TX_THREAD *this_thread; + + + /* Create the simulation thread. */ + this_thread = ux_utility_thread_identify(); + + /* Check for error. */ + if (this_thread != &ux_test_thread_simulation_0) + { + + printf("ERROR #%d: thread different %p <> %p\n", __LINE__, this_thread, &ux_test_thread_simulation_0); + error_counter ++; + } + + /* Simulate ISR enter */ + _tx_thread_system_state ++; + + this_thread = ux_utility_thread_identify(); + + /* Check for error. */ + if (this_thread != UX_NULL) + { + + printf("ERROR #%d: thread different %p <> NULL\n", __LINE__, this_thread); + error_counter ++; + } + + /* Simulate ISR exit. */ + _tx_thread_system_state --; + + /* Check for errors. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static void ux_test_thread_simulation_1_entry(ULONG arg) +{ + while(1) + { + _ux_utility_delay_ms(100); + } +} diff --git a/test/regression/usbx_ux_utility_thread_schedule_other_test.c b/test/regression/usbx_ux_utility_thread_schedule_other_test.c new file mode 100644 index 00000000..95eb3470 --- /dev/null +++ b/test/regression/usbx_ux_utility_thread_schedule_other_test.c @@ -0,0 +1,380 @@ +/* This test is designed to test the ux_utility_thread_schedule_other_.... */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors. */ +#define DPUMP_IFC_DESC(ifc, alt, nb_ep) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), (alt), (nb_ep), 0x99, 0x99, 0x99, 0x00, + +#define DPUMP_IFC_EP_DESC(epaddr, eptype, epsize) \ + /* Endpoint descriptor */\ + 0x07, 0x05, (epaddr), (eptype), LSB(epsize), MSB(epsize), 0x01, + +#define DPUMP_IFC_DESC_ALL_LEN(nb_ep) (9 + (nb_ep) * 7) + +#define CFG_DESC_ALL_LEN (CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN(4)) + +#define CFG_DESC_ALL \ + CFG_DESC(CFG_DESC_ALL_LEN, 1, 1)\ + DPUMP_IFC_DESC(0, 0, 4)\ + DPUMP_IFC_EP_DESC(0x81, 2, 64)\ + DPUMP_IFC_EP_DESC(0x02, 2, 64)\ + DPUMP_IFC_EP_DESC(0x83, 1, 64)\ + DPUMP_IFC_EP_DESC(0x84, 3, 64)\ + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +static TX_TIMER test_timer; + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC_ALL +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC_ALL +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +/* Simulator actions. */ + +static UX_TEST_HCD_SIM_ACTION endpoint0x83_create_del_skip[] = { +/* 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_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x83, UX_NULL, 0, 0, + UX_SUCCESS}, +{ UX_HCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x83, UX_NULL, 0, 0, + UX_SUCCESS}, +{ 0 } +}; + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 break_on_dpump_ready(VOID) +{ + +UINT status; +UX_HOST_CLASS *class; + + /* Find the main data pump container. */ + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class); + if (status != UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + /* Find the instance. */ + status = ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump); + if (status != UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + if (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + + +static UINT test_ux_device_class_dpump_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + switch(command->ux_slave_class_command_request) + { + case UX_SLAVE_CLASS_COMMAND_INITIALIZE: + case UX_SLAVE_CLASS_COMMAND_QUERY: + case UX_SLAVE_CLASS_COMMAND_CHANGE: + return UX_SUCCESS; + + default: + return UX_NO_CLASS_MATCH; + } +} + +static UINT test_ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command) +{ + switch (command -> ux_host_class_command_request) + { + case UX_HOST_CLASS_COMMAND_QUERY: + default: + return _ux_host_class_dpump_entry(command); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_utility_thread_schedule_other_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +CHAR *rpool_start; +CHAR *cpool_start; + + /* Inform user. */ + printf("Running ux_utility_thread_schedule_other Test....................... "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_memory; + memory_pointer = stack_pointer + (UX_TEST_STACK_SIZE * 2); + + rpool_start = memory_pointer; + cpool_start = memory_pointer + UX_TEST_MEMORY_SIZE; + + /* Initialize USBX Memory. */ + status = ux_system_initialize(rpool_start, UX_TEST_MEMORY_SIZE, cpool_start, UX_TEST_MEMORY_SIZE); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ +UINT status; +ULONG priority; + + /* Ignore errors. */ + error_callback_ignore = UX_TRUE; + + status = _ux_utility_thread_schedule_other(UX_THREAD_PRIORITY_ENUM); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: code 0x%x\n", __LINE__, status); + error_counter ++; + } + + priority = _ux_system->ux_system_thread_lowest_priority; + _ux_system->ux_system_thread_lowest_priority = TX_MAX_PRIORITIES; + status = _ux_utility_thread_schedule_other(UX_THREAD_PRIORITY_ENUM); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: Expect error\n", __LINE__); + error_counter ++; + } + _ux_system->ux_system_thread_lowest_priority = priority; + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} \ No newline at end of file diff --git a/test/regression/usbx_ux_utility_thread_suspend_test.c b/test/regression/usbx_ux_utility_thread_suspend_test.c new file mode 100644 index 00000000..80833bf5 --- /dev/null +++ b/test/regression/usbx_ux_utility_thread_suspend_test.c @@ -0,0 +1,204 @@ +/* This test is designed to test the ux_utility_thread_suspend. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +/* Define the counters used in the test application... */ + +static CHAR *stack_pointer; +static CHAR *memory_pointer; + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +/* Define USBX test global variables. */ + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +/* Simulator actions. */ + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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); + } + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_utility_thread_suspend_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; + + /* Inform user. */ + printf("Running ux_utility_thread_suspend Test.............................. "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation 0", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Reset another thread. */ + _ux_utility_memory_set(&ux_test_thread_simulation_1, 0, sizeof(ux_test_thread_simulation_1)); +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ +UINT status; + + /* Suspend the thread. */ + status = _ux_utility_thread_suspend(UX_NULL); + if (status != TX_THREAD_ERROR) + { + printf("ERROR #%d: expect TX_THREAD_ERROR but got 0x%x\n", __LINE__, status); + error_counter ++; + } + + /* Suspend the thread. */ + status = _ux_utility_thread_suspend(&ux_test_thread_simulation_1); + if (status != TX_THREAD_ERROR) + { + printf("ERROR #%d: expect TX_THREAD_ERROR but got 0x%x\n", __LINE__, status); + error_counter ++; + } + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_1, "test simulation 1", ux_test_thread_simulation_1_entry, 0, + stack_pointer + UX_TEST_STACK_SIZE, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d: thread create fail 0x%x\n", __LINE__, status); + test_control_return(1); + } + + /* Suspend the thread. */ + status = _ux_utility_thread_suspend(&ux_test_thread_simulation_1); + if (status != UX_SUCCESS) + { + printf("ERROR #%d: expect OK but got 0x%x\n", __LINE__, status); + error_counter ++; + } + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static void ux_test_thread_simulation_1_entry(ULONG arg) +{ + while(1) + { + _ux_utility_delay_ms(100); + } +} diff --git a/test/regression/usbx_ux_utility_timer_test.c b/test/regression/usbx_ux_utility_timer_test.c new file mode 100644 index 00000000..8eb60df9 --- /dev/null +++ b/test/regression/usbx_ux_utility_timer_test.c @@ -0,0 +1,384 @@ +/* This test is designed to test the ux_utility_timer_.... */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors. */ +#define DPUMP_IFC_DESC(ifc, alt, nb_ep) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), (alt), (nb_ep), 0x99, 0x99, 0x99, 0x00, + +#define DPUMP_IFC_EP_DESC(epaddr, eptype, epsize) \ + /* Endpoint descriptor */\ + 0x07, 0x05, (epaddr), (eptype), LSB(epsize), MSB(epsize), 0x01, + +#define DPUMP_IFC_DESC_ALL_LEN(nb_ep) (9 + (nb_ep) * 7) + +#define CFG_DESC_ALL_LEN (CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN(4)) + +#define CFG_DESC_ALL \ + CFG_DESC(CFG_DESC_ALL_LEN, 1, 1)\ + DPUMP_IFC_DESC(0, 0, 4)\ + DPUMP_IFC_EP_DESC(0x81, 2, 64)\ + DPUMP_IFC_EP_DESC(0x02, 2, 64)\ + DPUMP_IFC_EP_DESC(0x83, 1, 64)\ + DPUMP_IFC_EP_DESC(0x84, 3, 64)\ + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +static TX_TIMER test_timer; + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC_ALL +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC_ALL +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +/* Simulator actions. */ + +static UX_TEST_HCD_SIM_ACTION endpoint0x83_create_del_skip[] = { +/* 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_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x83, UX_NULL, 0, 0, + UX_SUCCESS}, +{ UX_HCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x83, UX_NULL, 0, 0, + UX_SUCCESS}, +{ 0 } +}; + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 break_on_dpump_ready(VOID) +{ + +UINT status; +UX_HOST_CLASS *class; + + /* Find the main data pump container. */ + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class); + if (status != UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + /* Find the instance. */ + status = ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump); + if (status != UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + if (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + + +static UINT test_ux_device_class_dpump_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + switch(command->ux_slave_class_command_request) + { + case UX_SLAVE_CLASS_COMMAND_INITIALIZE: + case UX_SLAVE_CLASS_COMMAND_QUERY: + case UX_SLAVE_CLASS_COMMAND_CHANGE: + return UX_SUCCESS; + + default: + return UX_NO_CLASS_MATCH; + } +} + +static UINT test_ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command) +{ + switch (command -> ux_host_class_command_request) + { + case UX_HOST_CLASS_COMMAND_QUERY: + default: + return _ux_host_class_dpump_entry(command); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_utility_timer_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; +CHAR *rpool_start; +CHAR *cpool_start; +const CHAR flags[] = { + UX_REGULAR_MEMORY, UX_CACHE_SAFE_MEMORY, 0xFF +}; +const CHAR expect_error[] = { + UX_FALSE, UX_FALSE, UX_TRUE +}; + + /* Inform user. */ + printf("Running ux_utility_timer_... Test................................... "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_memory; + memory_pointer = stack_pointer + (UX_TEST_STACK_SIZE * 2); + + rpool_start = memory_pointer; + cpool_start = memory_pointer + UX_TEST_MEMORY_SIZE; + + /* Initialize USBX Memory. */ + status = ux_system_initialize(rpool_start, UX_TEST_MEMORY_SIZE, cpool_start, UX_TEST_MEMORY_SIZE); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ +UINT status; + + /* Ignore errors. */ + error_callback_ignore = UX_TRUE; + + /* Timer create. */ + status = ux_utility_timer_create(&test_timer, "test_timer", UX_NULL, 0, 100, 100, TX_NO_ACTIVATE); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d: timer create fail\n", __LINE__); + test_control_return(1); + } + + /* Timer create again, expect error. */ + status = ux_utility_timer_create(&test_timer, "test_timer", UX_NULL, 0, 100, 100, TX_NO_ACTIVATE); + if (status == UX_SUCCESS) + { + + printf("ERROR #%d: Expect timer create fail\n", __LINE__); + error_counter ++; + } + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} \ No newline at end of file diff --git a/test/regression/usbx_ux_utility_unicode_to_string_test.c b/test/regression/usbx_ux_utility_unicode_to_string_test.c new file mode 100644 index 00000000..ea801b38 --- /dev/null +++ b/test/regression/usbx_ux_utility_unicode_to_string_test.c @@ -0,0 +1,404 @@ +/* This test is designed to test the ux_utility_unicode_to_string. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" +#include "ux_host_class_cdc_acm.h" + +#include "ux_host_class_dpump.h" +#include "ux_device_class_dpump.h" + +#include "ux_host_class_hid.h" +#include "ux_device_class_hid.h" + +#include "ux_host_class_storage.h" +#include "ux_device_class_storage.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_RUN 1 +#define UX_TEST_MEMORY_SIZE (64*1024) + +#define LSB(x) ( (x) & 0x00ff) +#define MSB(x) (((x) & 0xff00) >> 8) + +/* Configuration descriptor 9 bytes */ +#define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\ + /* Configuration 1 descriptor 9 bytes */\ + 0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\ + (bNumInterfaces), (bConfigurationValue), 0x00,\ + 0x40, 0x00, +#define CFG_DESC_LEN 9 + +/* DPUMP interface descriptors. */ +#define DPUMP_IFC_DESC(ifc, alt, nb_ep) \ + /* Interface descriptor */\ + 0x09, 0x04, (ifc), (alt), (nb_ep), 0x99, 0x99, 0x99, 0x00, + +#define DPUMP_IFC_EP_DESC(epaddr, eptype, epsize) \ + /* Endpoint descriptor */\ + 0x07, 0x05, (epaddr), (eptype), LSB(epsize), MSB(epsize), 0x01, + +#define DPUMP_IFC_DESC_ALL_LEN(nb_ep) (9 + (nb_ep) * 7) + +#define CFG_DESC_ALL_LEN (CFG_DESC_LEN + DPUMP_IFC_DESC_ALL_LEN(4)) + +#define CFG_DESC_ALL \ + CFG_DESC(CFG_DESC_ALL_LEN, 1, 1)\ + DPUMP_IFC_DESC(0, 0, 4)\ + DPUMP_IFC_EP_DESC(0x81, 2, 64)\ + DPUMP_IFC_EP_DESC(0x02, 2, 64)\ + DPUMP_IFC_EP_DESC(0x83, 1, 64)\ + DPUMP_IFC_EP_DESC(0x84, 3, 64)\ + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +static UCHAR buffer[UX_TEST_BUFFER_SIZE]; + +/* Define USBX test global variables. */ + +static UX_HOST_CLASS *class_driver; +static UX_HOST_CLASS_DPUMP *dpump; +static UX_SLAVE_CLASS_DPUMP *dpump_slave = UX_NULL; + +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor 18 bytes */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, + 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + + CFG_DESC_ALL +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + CFG_DESC_ALL +}; +#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 + Byte 2 : Byte containing the index of the descriptor + Byte 3 : Byte containing the length of the descriptor string +*/ + +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, + 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70, + 0x44, 0x65, 0x6d, 0x6f, + + /* Serial Number string descriptor : Index 3 */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static UCHAR language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static VOID ux_test_instance_activate(VOID *dpump_instance); +static VOID ux_test_instance_deactivate(VOID *dpump_instance); + +UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command); +UINT ux_hcd_sim_initialize(UX_HCD *hcd); +UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer, + ULONG requested_length, ULONG *actual_length); +UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer, + ULONG requested_length, ULONG *actual_length); + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +/* Simulator actions. */ + +static UX_TEST_HCD_SIM_ACTION endpoint0x83_create_del_skip[] = { +/* 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_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x83, UX_NULL, 0, 0, + UX_SUCCESS}, +{ UX_HCD_CREATE_ENDPOINT, NULL, + UX_FALSE, 0, + UX_TEST_MATCH_EP, 0x83, UX_NULL, 0, 0, + UX_SUCCESS}, +{ 0 } +}; + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +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 break_on_dpump_ready(VOID) +{ + +UINT status; +UX_HOST_CLASS *class; + + /* Find the main data pump container. */ + status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class); + if (status != UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + /* Find the instance. */ + status = ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump); + if (status != UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + if (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + +static UINT break_on_removal(VOID) +{ + +UINT status; +UX_DEVICE *device; + + status = ux_host_stack_device_get(0, &device); + if (status == UX_SUCCESS) + /* Do not break. */ + return UX_SUCCESS; + + return 1; +} + + +static UINT test_ux_device_class_dpump_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + switch(command->ux_slave_class_command_request) + { + case UX_SLAVE_CLASS_COMMAND_INITIALIZE: + case UX_SLAVE_CLASS_COMMAND_QUERY: + case UX_SLAVE_CLASS_COMMAND_CHANGE: + return UX_SUCCESS; + + default: + return UX_NO_CLASS_MATCH; + } +} + +static UINT test_ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command) +{ + switch (command -> ux_host_class_command_request) + { + case UX_HOST_CLASS_COMMAND_QUERY: + default: + return _ux_host_class_dpump_entry(command); + } +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_ux_utility_unicode_to_string_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; + + /* Inform user. */ + printf("Running ux_utility_unicode_to_string Test (and string_to_unicode)... "); + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Register the error callback. */ + _ux_utility_error_callback_register(error_callback); + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + + +#define TEST_STR "12345" +#define TEST_STR_LEN (sizeof(TEST_STR)) /* Including null terminator */ +UCHAR test_str[] = TEST_STR; +UCHAR s_buffer[16]; +UCHAR u_buffer[16 * 2 + 1]; +INT i, j; + + _ux_utility_memory_set(s_buffer, 0xFF, sizeof(s_buffer)); + _ux_utility_memory_set(u_buffer, 0xFF, sizeof(u_buffer)); + + _ux_utility_string_to_unicode(test_str, (UCHAR *)u_buffer); + if (u_buffer[0] != TEST_STR_LEN) + { + printf("ERROR #%d: expected 0x%x but got 0x%x\n", __LINE__, TEST_STR_LEN, u_buffer[0]); + } + for (i = 0, j = 1; i < TEST_STR_LEN; i ++, j += 2) + { + if (test_str[i] != u_buffer[j]) + { + printf("ERROR #%d: expected 0x%x but got 0x%x\n", __LINE__, test_str[i], u_buffer[j]); + } + if (0x0 != u_buffer[j + 1]) + { + printf("ERROR #%d: expected 0x%x but got 0x%x\n", __LINE__, 0, u_buffer[j + 1]); + } + } + for (; j < sizeof(u_buffer); j ++) + { + if (0xFF != u_buffer[j]) + { + printf("ERROR #%d: expected 0x%x but got 0x%x\n", __LINE__, 0xFF, s_buffer[j]); + } + } + + /* Modify unicode length to exclude null-terminator. */ + /* Here additional null terminator always pend to string end. */ + *u_buffer = (*u_buffer) - 1; + _ux_utility_unicode_to_string((UCHAR *)u_buffer, s_buffer); + for (i = 0; i < TEST_STR_LEN; i ++) + { + if (test_str[i] != s_buffer[i]) + { + printf("ERROR #%d: expected 0x%x but got 0x%x\n", __LINE__, test_str[i], s_buffer[i]); + } + } + for (; i < sizeof(s_buffer); i ++) + { + if (0xFF != s_buffer[i]) + { + printf("ERROR #%d: expected 0x%x but got 0x%x\n", __LINE__, 0xFF, s_buffer[i]); + } + } + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_uxe_device_audio_test.c b/test/regression/usbx_uxe_device_audio_test.c new file mode 100644 index 00000000..b581240e --- /dev/null +++ b/test/regression/usbx_uxe_device_audio_test.c @@ -0,0 +1,625 @@ +/* This test is designed to test the ux_utility_descriptor_pack. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_audio.h" +#include "ux_device_class_audio10.h" +#include "ux_device_class_audio20.h" + +#include "ux_test.h" + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + +static UX_DEVICE_CLASS_AUDIO *slave_audio; +static UX_DEVICE_CLASS_AUDIO_PARAMETER slave_audio_parameter; +static UX_DEVICE_CLASS_AUDIO_STREAM_PARAMETER slave_audio_stream_parameter[2]; + +static UX_DEVICE_CLASS_AUDIO *slave_audio_tx; +static UX_DEVICE_CLASS_AUDIO_STREAM *slave_audio_tx_stream; +static UX_DEVICE_CLASS_AUDIO_PARAMETER slave_audio_tx_parameter; +static UX_DEVICE_CLASS_AUDIO_STREAM_PARAMETER slave_audio_tx_stream_parameter; + +static UX_DEVICE_CLASS_AUDIO *slave_audio_rx; +static UX_DEVICE_CLASS_AUDIO_STREAM *slave_audio_rx_stream; +static UX_DEVICE_CLASS_AUDIO_PARAMETER slave_audio_rx_parameter; +static UX_DEVICE_CLASS_AUDIO_STREAM_PARAMETER slave_audio_rx_stream_parameter; +static UX_SLAVE_TRANSFER *slave_audio_rx_transfer; + +/* Define USBX test global variables. */ + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +#define D3(d) ((UCHAR)((d) >> 24)) +#define D2(d) ((UCHAR)((d) >> 16)) +#define D1(d) ((UCHAR)((d) >> 8)) +#define D0(d) ((UCHAR)((d) >> 0)) + +static unsigned char device_framework_full_speed[] = { + +/* --------------------------------------- Device Descriptor */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 0x08, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x01, 0x00, +/* 12 bcdDevice */ D0(0x100),D1(0x100), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* -------------------------------- Configuration Descriptor *//* 9+8+88+52*2=209 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(209),D1(209), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------ Interface Association Descriptor */ +/* 0 bLength, bDescriptorType */ 8, 0x0B, +/* 2 bFirstInterface, bInterfaceCount */ 0, 3, +/* 4 bFunctionClass, bFunctionSubClass, bFunctionProtocol */ 0x01, 0x01, 0x00, +/* 7 iFunction */ 0, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+72+7=88) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x00, +/* 8 iInterface */ 0, +/* ---------------- Audio 1.0 AC Interface Header Descriptor *//* (10+12*2+10*2+9*2=72) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x01, +/* 3 bcdADC */ 0x00, 0x01, +/* 5 wTotalLength, bInCollection */ D0(72),D1(72), 2, +/* 8 baInterfaceNr(1) ... baInterfaceNr(n) */ 1, 2, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x02, +/* 8 iTerminal */ 0, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x05, +/* 8 iTerminal */ 0, +/* --------------------- Audio 1.0 AC INT Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x83, 0x03, +/* 4 wMaxPacketSize, bInterval */ D0(8),D1(8), 1, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x03, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 1, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x04, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 1, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { +/* --------------------------------------- Device Descriptor */ +/* 0 bLength, bDescriptorType */ 18, 0x01, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x01, 0x00, +/* 12 bcdDevice */ D0(0x100),D1(0x100), +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, +/* 17 bNumConfigurations */ 1, + +/* ----------------------------- Device Qualifier Descriptor */ +/* 0 bLength, bDescriptorType */ 10, 0x06, +/* 2 bcdUSB */ D0(0x200),D1(0x200), +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, +/* 7 bMaxPacketSize0 */ 8, +/* 8 bNumConfigurations */ 1, +/* 9 bReserved */ 0, + +/* -------------------------------- Configuration Descriptor *//* 9+8+88+52*2=209 */ +/* 0 bLength, bDescriptorType */ 9, 0x02, +/* 2 wTotalLength */ D0(209),D1(209), +/* 4 bNumInterfaces, bConfigurationValue */ 3, 1, +/* 6 iConfiguration */ 0, +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +/* ------------------------ Interface Association Descriptor */ +/* 0 bLength, bDescriptorType */ 8, 0x0B, +/* 2 bFirstInterface, bInterfaceCount */ 0, 3, +/* 4 bFunctionClass, bFunctionSubClass, bFunctionProtocol */ 0x01, 0x01, 0x00, +/* 7 iFunction */ 0, + +/* ------------------------------------ Interface Descriptor *//* 0 Control (9+72+7=88) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 0, 0, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x01, 0x00, +/* 8 iInterface */ 0, +/* ---------------- Audio 1.0 AC Interface Header Descriptor *//* (10+12*2+10*2+9*2=72) */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x01, +/* 3 bcdADC */ 0x00, 0x01, +/* 5 wTotalLength, bInCollection */ D0(72),D1(72), 2, +/* 8 baInterfaceNr(1) ... baInterfaceNr(n) */ 1, 2, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x01, D0(0x0201),D1(0x0201), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x02, 0x01, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x03, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x02, +/* 8 iTerminal */ 0, +/* ------------------- Audio 1.0 AC Input Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 12, 0x24, 0x02, +/* 3 bTerminalID, wTerminalType */ 0x04, D0(0x0101),D1(0x0101), +/* 6 bAssocTerminal, */ 0x00, +/* 7 bNrChannels, wChannelConfig */ 0x02, D0(0),D1(0), +/* 10 iChannelNames, iTerminal */ 0, 0, +/* --------------------- Audio 1.0 AC Feature Unit Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 10, 0x24, 0x06, +/* 3 bUnitID, bSourceID */ 0x05, 0x04, +/* 5 bControlSize */ 1, +/* 6 bmaControls(0) ... bmaControls(...) ... */ 0x00, 0x00, 0x00, +/* . iFeature */ 0, +/* ------------------ Audio 1.0 AC Output Terminal Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 9, 0x24, 0x03, +/* 3 bTerminalID, wTerminalType */ 0x06, D0(0x0301),D1(0x0301), +/* 6 bAssocTerminal, bSourceID */ 0x00, 0x05, +/* 8 iTerminal */ 0, +/* --------------------- Audio 1.0 AC INT Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 7, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x83, 0x03, +/* 4 wMaxPacketSize, bInterval */ D0(8),D1(8), 4, + +/* ------------------------------------ Interface Descriptor *//* 1 Stream IN (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 1, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x03, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x81, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 4, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), + +/* ------------------------------------ Interface Descriptor *//* 2 Stream OUT (9+9+7+11+9+7=52) */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 0, +/* 4 bNumEndpoints */ 0, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------------------ Interface Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x04, +/* 2 bInterfaceNumber, bAlternateSetting */ 2, 1, +/* 4 bNumEndpoints */ 1, +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ 0x01, 0x02, 0x00, +/* 8 iInterface */ 0, +/* ------------------------ Audio 1.0 AS Interface Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x24, 0x01, +/* 3 bTerminalLink */ 0x04, +/* 4 bDelay, wFormatTag */ 0x00, D0(0x0001),D1(0x0001), +/* -------------------------- Audio AS Format Type Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 11, 0x24, 0x02, +/* 3 bFormatType, bNrChannels, bSubframeSize, bBitResolution */ 0x01, 0x02, 0x02, 16, +/* 7 bSamFreqType (n), tSamFreq[1] ... tSamFreq[n] */ 1, D0(48000),D1(48000),D2(48000), +/* --------------------- Audio 1.0 AS ISO Endpoint Descriptor */ +/* 0 bLength, bDescriptorType */ 9, 0x05, +/* 2 bEndpointAddress, bmAttributes */ 0x02, 0x01, +/* 4 wMaxPacketSize, bInterval, bRefresh, bSynchAddress */ D0(256),D1(256), 4, 0, 0, +/* ---------- Audio 1.0 AS ISO Audio Data Endpoint Descriptor */ +/* 0 bLength, bDescriptorType, bDescriptorSubtype */ 7, 0x25, 0x01, +/* 3 bmAttributes */ 0x00, +/* 5 bLockDelayUnits, wLockDelay */ 0x00, D0(0),D1(0), +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + +/* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + +/* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + +/* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +static VOID slave_audio_tx_activate(VOID *audio_instance){} +static VOID slave_audio_deactivate(VOID *audio_instance){} +static VOID slave_audio_tx_stream_change(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG alt){} +static UINT slave_audio_control_process(UX_DEVICE_CLASS_AUDIO *audio, UX_SLAVE_TRANSFER *transfer) +{ + return(UX_ERROR); +} +static VOID slave_audio_tx_done(UX_DEVICE_CLASS_AUDIO_STREAM *audio, ULONG length){} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_uxe_device_audio_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +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! + printf("SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + 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); + UX_TEST_CHECK_SUCCESS(status); + +#if !defined(UX_DEVICE_STANDALONE) + slave_audio_tx_stream_parameter.ux_device_class_audio_stream_parameter_thread_entry = ux_device_class_audio_write_thread_entry; +#else + slave_audio_tx_stream_parameter.ux_device_class_audio_stream_parameter_task_function = _ux_device_class_audio_write_task_function; +#endif + slave_audio_tx_stream_parameter.ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_change = slave_audio_tx_stream_change; + slave_audio_tx_stream_parameter.ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_frame_done = slave_audio_tx_done; + slave_audio_tx_stream_parameter.ux_device_class_audio_stream_parameter_max_frame_buffer_size = 256; + slave_audio_tx_stream_parameter.ux_device_class_audio_stream_parameter_max_frame_buffer_nb = 8; + slave_audio_tx_parameter.ux_device_class_audio_parameter_streams = &slave_audio_tx_stream_parameter; + slave_audio_tx_parameter.ux_device_class_audio_parameter_streams_nb = 1; + slave_audio_tx_parameter.ux_device_class_audio_parameter_callbacks.ux_slave_class_audio_instance_activate = slave_audio_tx_activate; + slave_audio_tx_parameter.ux_device_class_audio_parameter_callbacks.ux_slave_class_audio_instance_deactivate = slave_audio_deactivate; + slave_audio_tx_parameter.ux_device_class_audio_parameter_callbacks.ux_device_class_audio_control_process = slave_audio_control_process; + slave_audio_tx_parameter.ux_device_class_audio_parameter_callbacks.ux_device_class_audio_arg = UX_NULL; + + status = ux_device_stack_class_register(_ux_system_slave_class_audio_name, ux_device_class_audio_entry, + 1, 1, NX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + slave_audio_tx_parameter.ux_device_class_audio_parameter_streams = NX_NULL; + status = ux_device_stack_class_register(_ux_system_slave_class_audio_name, ux_device_class_audio_entry, + 1, 1, &slave_audio_tx_parameter); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + slave_audio_tx_parameter.ux_device_class_audio_parameter_streams = &slave_audio_tx_stream_parameter; + slave_audio_tx_parameter.ux_device_class_audio_parameter_streams_nb = 0; + status = ux_device_stack_class_register(_ux_system_slave_class_audio_name, ux_device_class_audio_entry, + 1, 1, &slave_audio_tx_parameter); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + slave_audio_tx_parameter.ux_device_class_audio_parameter_streams = &slave_audio_tx_stream_parameter; + slave_audio_tx_parameter.ux_device_class_audio_parameter_streams_nb = 1; + slave_audio_tx_stream_parameter.ux_device_class_audio_stream_parameter_max_frame_buffer_nb = 0; + status = ux_device_stack_class_register(_ux_system_slave_class_audio_name, ux_device_class_audio_entry, + 1, 1, &slave_audio_tx_parameter); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + slave_audio_tx_parameter.ux_device_class_audio_parameter_streams = &slave_audio_tx_stream_parameter; + slave_audio_tx_parameter.ux_device_class_audio_parameter_streams_nb = 1; + slave_audio_tx_stream_parameter.ux_device_class_audio_stream_parameter_max_frame_buffer_nb = 1; + slave_audio_tx_stream_parameter.ux_device_class_audio_stream_parameter_max_frame_buffer_size = 0; + status = ux_device_stack_class_register(_ux_system_slave_class_audio_name, ux_device_class_audio_entry, + 1, 1, &slave_audio_tx_parameter); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ +UINT status; +UX_DEVICE_CLASS_AUDIO dummy_audio_inst; +UX_DEVICE_CLASS_AUDIO *dummy_audio = &dummy_audio_inst; +UX_DEVICE_CLASS_AUDIO_STREAM dummy_stream_inst; +UX_DEVICE_CLASS_AUDIO_STREAM *dummy_stream = &dummy_stream_inst; +UCHAR *dummy_buffer; +ULONG dummy_dw; +UX_SLAVE_TRANSFER dummy_transfer; +UX_DEVICE_CLASS_AUDIO10_CONTROL_GROUP dummy_group10; +UX_DEVICE_CLASS_AUDIO20_CONTROL_GROUP dummy_group20; + + /* ux_device_class_audio_stream_get() */ + status = ux_device_class_audio_stream_get(UX_NULL, 0, &dummy_stream); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_device_class_audio_stream_get(dummy_audio, 0, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + dummy_stream = &dummy_stream_inst; + + /* ux_device_class_audio_reception_start() */ + status = ux_device_class_audio_reception_start(UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_device_class_audio_sample_read8() */ + status = ux_device_class_audio_sample_read8(UX_NULL, (UCHAR *)&dummy_dw); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_device_class_audio_sample_read16() */ + status = ux_device_class_audio_sample_read16(UX_NULL, (USHORT *)&dummy_dw); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_device_class_audio_sample_read24() */ + status = ux_device_class_audio_sample_read24(UX_NULL, &dummy_dw); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_device_class_audio_sample_read32() */ + status = ux_device_class_audio_sample_read32(UX_NULL, &dummy_dw); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_device_class_audio_read_frame_get() */ + status = ux_device_class_audio_read_frame_get(UX_NULL, &dummy_buffer, &dummy_dw); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_device_class_audio_read_frame_get(dummy_stream, UX_NULL, &dummy_dw); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_device_class_audio_read_frame_get(dummy_stream, &dummy_buffer, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_device_class_audio_read_frame_free() */ + status = ux_device_class_audio_read_frame_free(UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_device_class_audio_transmission_start() */ + status = ux_device_class_audio_transmission_start(UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_device_class_audio_frame_write() */ + status = ux_device_class_audio_frame_write(UX_NULL, dummy_buffer, 4); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_device_class_audio_frame_write(dummy_stream, UX_NULL, 4); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_device_class_audio_frame_write(dummy_stream, dummy_buffer, 0); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_device_class_audio_write_frame_get() */ + status = ux_device_class_audio_write_frame_get(UX_NULL, &dummy_buffer, &dummy_dw); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_device_class_audio_write_frame_get(dummy_stream, UX_NULL, &dummy_dw); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_device_class_audio_write_frame_get(dummy_stream, &dummy_buffer, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_device_class_audio_write_frame_commit() */ + status = ux_device_class_audio_write_frame_commit(UX_NULL, 1); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_device_class_audio_write_frame_commit(dummy_stream, 0); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_device_class_audio_ioctl() */ + status = ux_device_class_audio_ioctl(UX_NULL, 0, &dummy_dw); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_device_class_audio_feedback_get() */ + status = ux_device_class_audio_feedback_get(UX_NULL, (UCHAR *)&dummy_dw); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_device_class_audio_feedback_get(dummy_stream, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_device_class_audio_feedback_set() */ + status = ux_device_class_audio_feedback_set(UX_NULL, (UCHAR *)&dummy_dw); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_device_class_audio_feedback_set(dummy_stream, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_device_class_audio_interrupt_send() */ + status = ux_device_class_audio_interrupt_send(UX_NULL, (UCHAR *)&dummy_dw); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_device_class_audio_interrupt_send(dummy_audio, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_device_class_audio10_control_process() */ + status = ux_device_class_audio10_control_process(UX_NULL, &dummy_transfer, &dummy_group10); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_device_class_audio10_control_process(dummy_audio, UX_NULL, &dummy_group10); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_device_class_audio10_control_process(dummy_audio, &dummy_transfer, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_device_class_audio20_control_process() */ + status = ux_device_class_audio20_control_process(UX_NULL, &dummy_transfer, &dummy_group20); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_device_class_audio20_control_process(dummy_audio, UX_NULL, &dummy_group20); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_device_class_audio20_control_process(dummy_audio, &dummy_transfer, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_uxe_device_ccid_test.c b/test/regression/usbx_uxe_device_ccid_test.c new file mode 100644 index 00000000..376a45c9 --- /dev/null +++ b/test/regression/usbx_uxe_device_ccid_test.c @@ -0,0 +1,245 @@ +/* This test is designed to test the ux_utility_descriptor_pack. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_ccid.h" + +#include "ux_test.h" + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG error_counter = 0; + +/* Define USBX test global variables. */ + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_simulation_0; +static void ux_test_thread_simulation_0_entry(ULONG); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +#if 0 +static UINT ux_test_ccid_icc_power_on(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_icc_power_off(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_get_slot_status(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_xfr_block(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_get_parameters(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_reset_parameters(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_set_parameters(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_escape(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_icc_clock(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_t0_apdu(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_secure(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_mechanical(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_abort(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); +static UINT ux_test_ccid_set_data_rate_and_clock_frequency(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg); + +static UX_DEVICE_CLASS_CCID_HANDLES device_ccid_handles = +{ + ux_test_ccid_icc_power_on, + ux_test_ccid_icc_power_off, + ux_test_ccid_get_slot_status, + ux_test_ccid_xfr_block, + ux_test_ccid_get_parameters, + ux_test_ccid_reset_parameters, + ux_test_ccid_set_parameters, + ux_test_ccid_escape, + ux_test_ccid_icc_clock, + ux_test_ccid_t0_apdu, + ux_test_ccid_secure, + ux_test_ccid_mechanical, + ux_test_ccid_abort, + ux_test_ccid_set_data_rate_and_clock_frequency, +}; + +static UINT ux_test_ccid_icc_power_on(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ + return UX_SUCCESS; +} + +static UINT ux_test_ccid_icc_power_off(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ + return UX_SUCCESS; +} + +static UINT ux_test_ccid_get_slot_status(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ + return UX_SUCCESS; +} + +static UINT ux_test_ccid_xfr_block(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ + return UX_SUCCESS; +} + +static UINT ux_test_ccid_get_parameters(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ + return UX_SUCCESS; +} + +static UINT ux_test_ccid_reset_parameters(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ + return UX_SUCCESS; +} + +static UINT ux_test_ccid_set_parameters(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ + return UX_SUCCESS; +} + +static UINT ux_test_ccid_escape(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ + return UX_SUCCESS; +} + +static UINT ux_test_ccid_icc_clock(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ + return UX_SUCCESS; +} + +static UINT ux_test_ccid_t0_apdu(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ + return UX_SUCCESS; +} + +static UINT ux_test_ccid_secure(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ + return UX_SUCCESS; +} + +static UINT ux_test_ccid_mechanical(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ + return UX_SUCCESS; +} + +static UINT ux_test_ccid_abort(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ + return UX_SUCCESS; +} + +static UINT ux_test_ccid_set_data_rate_and_clock_frequency(ULONG slot, UX_DEVICE_CLASS_CCID_MESSAGES*io_msg) +{ + return UX_SUCCESS; +} + +#endif + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_uxe_device_ccid_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +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! + printf("SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ +UINT status; +UX_DEVICE_CLASS_CCID dummy_ccid_inst; +UX_DEVICE_CLASS_CCID *dummy_ccid = &dummy_ccid_inst; +UCHAR dummy_buffer[32]; +ULONG dummy_actual_length; + +UX_DEVICE_CLASS_CCID_PARAMETER device_ccid_parameter; + + + status = ux_device_class_ccid_icc_insert(UX_NULL, 0, 0); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_device_class_ccid_icc_remove(UX_NULL, 0); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_device_class_ccid_auto_seq_done(UX_NULL, 0, 0); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_device_class_ccid_time_extension(UX_NULL, 0, 0); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_device_class_ccid_time_extension(UX_NULL, UX_DEVICE_CLASS_CCID_MAX_N_SLOTS, 0); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = _uxe_device_class_ccid_hardware_error(UX_NULL, 0, 1); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_uxe_device_cdc_acm_test.c b/test/regression/usbx_uxe_device_cdc_acm_test.c new file mode 100644 index 00000000..e0d85e3b --- /dev/null +++ b/test/regression/usbx_uxe_device_cdc_acm_test.c @@ -0,0 +1,177 @@ +/* This test is designed to test the ux_utility_descriptor_pack. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_cdc_acm.h" + +#include "ux_test.h" + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_MEMORY_SIZE (64*1024) + +/* Define the counters used in the test application... */ + +static ULONG error_counter = 0; + +/* Define USBX test global variables. */ + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_simulation_0; +static void ux_test_thread_simulation_0_entry(ULONG); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_uxe_device_cdc_acm_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +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! + printf("SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ +UINT status; +UX_SLAVE_CLASS_CDC_ACM dummy_inst; +//UX_SLAVE_CLASS_CDC_ACM *dummy_cdc_acm = &dummy_inst; +UCHAR dummy_buffer[32]; +ULONG dummy_actual_length; +UX_SLAVE_CLASS_COMMAND dummy_command; + +#if !defined(UX_DEVICE_STANDALONE) + + /* ux_device_class_cdc_acm_read() */ + status = ux_device_class_cdc_acm_read(UX_NULL, dummy_buffer, 32, &dummy_actual_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_device_class_cdc_acm_read(&dummy_inst, UX_NULL, 32, &dummy_actual_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_device_class_cdc_acm_read(&dummy_inst, dummy_buffer, 32, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + + /* _ux_device_class_cdc_acm_write() */ + status = ux_device_class_cdc_acm_write(UX_NULL, dummy_buffer, 32, &dummy_actual_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_device_class_cdc_acm_write(&dummy_inst, UX_NULL, 32, &dummy_actual_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_device_class_cdc_acm_write(&dummy_inst, dummy_buffer, 32, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_device_class_printer_ioctl() */ + status = ux_device_class_cdc_acm_ioctl(UX_NULL, UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_CODING, 0); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_device_class_cdc_acm_write_with_callback() */ + status = ux_device_class_cdc_acm_write_with_callback(NX_NULL, dummy_buffer, 32); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_device_class_cdc_acm_write_with_callback(&dummy_inst, NX_NULL, 32); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + +#else + + /* ux_device_class_cdc_acm_read_run() */ + status = ux_device_class_cdc_acm_read_run(UX_NULL, dummy_buffer, 32, &dummy_actual_length); + UX_TEST_CHECK_CODE(UX_STATE_ERROR, status); + + status = ux_device_class_cdc_acm_read_run(&dummy_inst, UX_NULL, 32, &dummy_actual_length); + UX_TEST_CHECK_CODE(UX_STATE_ERROR, status); + + status = ux_device_class_cdc_acm_read_run(&dummy_inst, dummy_buffer, 32, UX_NULL); + UX_TEST_CHECK_CODE(UX_STATE_ERROR, status); + + /* ux_device_class_cdc_acm_write_run() */ + status = ux_device_class_cdc_acm_write_run(UX_NULL, dummy_buffer, 32, &dummy_actual_length); + UX_TEST_CHECK_CODE(UX_STATE_ERROR, status); + + status = ux_device_class_cdc_acm_write_run(&dummy_inst, UX_NULL, 32, &dummy_actual_length); + UX_TEST_CHECK_CODE(UX_STATE_ERROR, status); + + status = ux_device_class_cdc_acm_write_run(&dummy_inst, dummy_buffer, 32, UX_NULL); + UX_TEST_CHECK_CODE(UX_STATE_ERROR, status); + +#endif + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_uxe_device_dfu_test.c b/test/regression/usbx_uxe_device_dfu_test.c new file mode 100644 index 00000000..0be15ff1 --- /dev/null +++ b/test/regression/usbx_uxe_device_dfu_test.c @@ -0,0 +1,665 @@ +/* This test is designed to test the simple dpump host/device class operation. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" + +#include "fx_api.h" + +#include "ux_device_class_dfu.h" +#include "ux_device_stack.h" +#include "ux_host_stack.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_utility_sim.h" + + +#define UX_DEMO_REQUEST_MAX_LENGTH \ + ((UX_HCD_SIM_HOST_MAX_PAYLOAD) > (UX_SLAVE_REQUEST_DATA_MAX_LENGTH) ? \ + (UX_HCD_SIM_HOST_MAX_PAYLOAD) : (UX_SLAVE_REQUEST_DATA_MAX_LENGTH)) + + +/* Define constants. */ + +#define UX_DEMO_MEMORY_SIZE (128*1024) +#define UX_DEMO_STACK_SIZE (1024) + +/* Define local/extern function prototypes. */ + +static void test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; + +static VOID demo_thread_dfu_activate(VOID *dfu); +static VOID demo_thread_dfu_deactivate(VOID *dfu); +static UINT demo_thread_dfu_read(VOID *dfu, ULONG block_number, UCHAR * data_pointer, ULONG length, ULONG *actual_length); +static UINT demo_thread_dfu_write(VOID *dfu, ULONG block_number, UCHAR * data_pointer, ULONG length, ULONG *media_status); +static UINT demo_thread_dfu_get_status(VOID *dfu, ULONG *media_status); +static UINT demo_thread_dfu_notify(VOID *dfu, ULONG notification); +static UINT demo_thread_dfu_custom_request(VOID *dfu, UX_SLAVE_TRANSFER *transfer); +static void ux_test_thread_simulation_0_entry(ULONG); +/* Define global data structures. */ + +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +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 interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +static UX_SLAVE_CLASS_DFU_PARAMETER dfu_parameter; + +static UX_DEVICE *device; +static ULONG dfu_block; +static ULONG dfu_transfer_length; +static ULONG dfu_actual_length; +static UCHAR dfu_host_buffer[UX_DEMO_REQUEST_MAX_LENGTH]; +static UCHAR dfu_device_buffer[UX_DEMO_REQUEST_MAX_LENGTH]; + +static TX_THREAD ux_test_thread_simulation_0; +/* Define device framework. */ + +/* DFU descriptor must be same for all frameworks!!! */ +#define DFU_FUNCTION_DESCRIPTOR \ + /* Functional descriptor for DFU. */ \ + 0x09, 0x21, \ + 0x0f, /* bmAttributes: B3 bitWillDetach */ \ + /* B2 bitManifestationTolerant */ \ + /* B1 bitCanUpload, B0 bitCanDnload */ \ + 0xE8, 0x03, /* wDetachTimeOut: 0x03E8 (1000) */ \ + UX_W0(UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH), \ + UX_W1(UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH), /* wTransferSize: */ \ + 0x00, 0x01, /* bcdDFUVersion: 0x0100 */ + +/* Interface descriptor for APP/DFU mode. */ +#define DFU_INTERFACE_DESCRIPTOR(bInterfaceNumber, bInterfaceProtocol) \ + /* Interface descriptor for DFU. */ \ + 0x09, 0x04, \ + (bInterfaceNumber), 0x00, 0x00, \ + 0xFE, 0x01, (bInterfaceProtocol), \ + 0x00, \ + +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) +static UCHAR device_framework_full_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x40, + 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x1b, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor for DFU (bInterfaceProtocol = 1). */ + DFU_INTERFACE_DESCRIPTOR(0x00, 0x01) + DFU_FUNCTION_DESCRIPTOR +}; + +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) +static UCHAR device_framework_high_speed[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x99, 0x99, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Device qualifier descriptor */ + 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x00, + + /* Configuration descriptor */ + 0x09, 0x02, 0x1b, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor for DFU (bInterfaceProtocol = 1). */ + DFU_INTERFACE_DESCRIPTOR(0x00, 0x01) + DFU_FUNCTION_DESCRIPTOR +}; + +/* 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 sizeof(string_framework) +static UCHAR string_framework[] = { + + /* Manufacturer string descriptor : Index 1 - "Microsoft AzureRTOS" */ + 0x09, 0x04, 0x01, 19, + 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', + 't', ' ', 'A', 'z', 'u', 'r', 'e', 'R', + 'T', 'O', 'S', + + /* Product string descriptor : Index 2 - "DFU Demo Device" */ + 0x09, 0x04, 0x02, 15, + 'D', 'F', 'U', ' ', 'D', 'e', 'm', 'o', + ' ', 'D', 'e', 'v', 'i', 'c', 'e', + + /* Serial Number string descriptor : Index 3 - "0000" */ + 0x09, 0x04, 0x03, 0x04, + '0', '0', '0', '0' +}; + +/* 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 sizeof(language_id_framework) +static UCHAR language_id_framework[] = { + + /* English. */ + 0x09, 0x04 +}; + + +#define DEVICE_FRAMEWORK_LENGTH_DFU sizeof(device_framework_dfu) +static UCHAR device_framework_dfu[] = { + + /* Device descriptor */ + 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x40, + 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x01, + + /* Configuration descriptor */ + 0x09, 0x02, 0x1B, 0x00, 0x01, 0x01, 0x00, 0xc0, + 0x32, + + /* Interface descriptor for DFU (bInterfaceProtocol = 2). */ + DFU_INTERFACE_DESCRIPTOR(0x00, 0x02) + DFU_FUNCTION_DESCRIPTOR +}; + + +/* Define the ISR dispatch. */ + +extern VOID (*test_isr_dispatch)(void); + + +/* 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); + } + } +} + + +/* Define the ISR dispatch routine. */ + +static void test_isr(void) +{ + + /* For further expansion of interrupt-level testing. */ +} + + +static UINT demo_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) +{ + if (event == UX_DEVICE_CONNECTION) + { + device = (UX_DEVICE *)inst; + } + if (event == UX_DEVICE_DISCONNECTION) + { + if ((VOID *)device == inst) + device = UX_NULL; + } +} + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_uxe_device_dfu_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR * stack_pointer; +CHAR * memory_pointer; +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! + printf("SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif /* UX_DEVICE_CLASS_DFU_ENABLE_ERROR_CHECKING */ + + + /* 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(); + + /* 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 #%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(demo_system_host_change_function); + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* There is no host class for DFU now. */ + + /* 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); + } + + /* Store the DFU parameters. */ + dfu_parameter.ux_slave_class_dfu_parameter_instance_activate = demo_thread_dfu_activate; + dfu_parameter.ux_slave_class_dfu_parameter_instance_deactivate = demo_thread_dfu_deactivate; + dfu_parameter.ux_slave_class_dfu_parameter_read = demo_thread_dfu_read; + dfu_parameter.ux_slave_class_dfu_parameter_write = demo_thread_dfu_write; + dfu_parameter.ux_slave_class_dfu_parameter_get_status = demo_thread_dfu_get_status; + dfu_parameter.ux_slave_class_dfu_parameter_notify = demo_thread_dfu_notify; +#ifdef UX_DEVICE_CLASS_DFU_CUSTOM_REQUEST_ENABLE + dfu_parameter.ux_device_class_dfu_parameter_custom_request = demo_thread_dfu_custom_request; +#endif + dfu_parameter.ux_slave_class_dfu_parameter_framework = UX_NULL; + dfu_parameter.ux_slave_class_dfu_parameter_framework_length = DEVICE_FRAMEWORK_LENGTH_DFU; + + /* Initilize the device dfu class. The class is connected with interface 1 on configuration 1. */ + // status = ux_device_stack_class_register(_ux_system_slave_class_dfu_name, ux_device_class_dfu_entry, + // 1, 0, (VOID *)&dfu_parameter); + status = ux_device_stack_class_register(_ux_system_slave_class_dfu_name, ux_device_class_dfu_entry, + 1, 0, UX_NULL); + if(status != UX_INVALID_PARAMETER) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + status = ux_device_stack_class_register(_ux_system_slave_class_dfu_name, ux_device_class_dfu_entry, + 1, 0, (VOID *)&dfu_parameter); + if(status != UX_INVALID_PARAMETER) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + dfu_parameter.ux_slave_class_dfu_parameter_framework = device_framework_dfu; + status = ux_device_stack_class_register(_ux_system_slave_class_dfu_name, ux_device_class_dfu_entry, + 1, 0, (VOID *)&dfu_parameter); + if(status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_DEMO_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + +} + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +static UINT _req_DFU_LOCK(UX_TRANSFER *control_transfer) +{ +UINT status; +#if defined(UX_HOST_STANDALONE) + while(1) + { + ux_system_tasks_run(); + tx_thread_relinquish(); + + UX_ENDPOINT *endpoint = control_transfer -> ux_transfer_request_endpoint; + if (endpoint == UX_NULL || endpoint -> ux_endpoint_state != UX_ENDPOINT_RUNNING) + { + status = UX_ENDPOINT_HANDLE_UNKNOWN; + break; + } + UX_DEVICE *device = endpoint -> ux_endpoint_device; + if (device == UX_NULL || device -> ux_device_handle != (ULONG)(ALIGN_TYPE)(device)) + { + status = UX_DEVICE_HANDLE_UNKNOWN; + break; + } + if ((device -> ux_device_flags & UX_DEVICE_FLAG_LOCK) == 0) + { + device -> ux_device_flags |= UX_DEVICE_FLAG_LOCK; + control_transfer -> ux_transfer_request_flags |= UX_TRANSFER_FLAG_AUTO_DEVICE_UNLOCK; + control_transfer -> ux_transfer_request_timeout_value = UX_WAIT_FOREVER; + status = UX_SUCCESS; + break; + } + } +#else + status = _ux_utility_semaphore_get(&control_transfer->ux_transfer_request_endpoint->ux_endpoint_device->ux_device_protection_semaphore, UX_WAIT_FOREVER); +#endif + if (status != UX_SUCCESS) + { + printf("ERROR #%d: %x\n", __LINE__, status); + test_control_return(1); + } +} +static UINT _req_DFU_GETSTATE(UX_TRANSFER *control_transfer) +{ + _req_DFU_LOCK(control_transfer); + control_transfer->ux_transfer_request_type = 0xA1; + control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_GET_STATE; + control_transfer->ux_transfer_request_index = 0; + control_transfer->ux_transfer_request_requested_length = 1; + control_transfer->ux_transfer_request_data_pointer = dfu_host_buffer; + control_transfer->ux_transfer_request_value = 0; + return ux_host_stack_transfer_request(control_transfer); +} +static UINT _req_DFU_GETSTATUS(UX_TRANSFER *control_transfer) +{ + _req_DFU_LOCK(control_transfer); + control_transfer->ux_transfer_request_type = 0xA1; + control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_GET_STATUS; + control_transfer->ux_transfer_request_index = 0; + control_transfer->ux_transfer_request_requested_length = 6; + control_transfer->ux_transfer_request_data_pointer = dfu_host_buffer; + control_transfer->ux_transfer_request_value = 0; + return ux_host_stack_transfer_request(control_transfer); +} +static UINT _req_DFU_DETACH(UX_TRANSFER *control_transfer) +{ + _req_DFU_LOCK(control_transfer); + control_transfer->ux_transfer_request_type = 0x21; + control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_DETACH; + control_transfer->ux_transfer_request_index = 0; + control_transfer->ux_transfer_request_value = 1000; + control_transfer->ux_transfer_request_requested_length = 0; + return ux_host_stack_transfer_request(control_transfer); +} +static UINT _req_DFU_DNLOAD_IN(UX_TRANSFER *control_transfer, ULONG block, ULONG len) +{ + _req_DFU_LOCK(control_transfer); + control_transfer->ux_transfer_request_type = 0xA1; + control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_DOWNLOAD; + control_transfer->ux_transfer_request_index = 0; + control_transfer->ux_transfer_request_data_pointer = dfu_host_buffer; + control_transfer->ux_transfer_request_requested_length = len; + control_transfer->ux_transfer_request_value = block; + return ux_host_stack_transfer_request(control_transfer); +} +static UINT _req_DFU_DNLOAD(UX_TRANSFER *control_transfer, ULONG block, ULONG len) +{ + _req_DFU_LOCK(control_transfer); + control_transfer->ux_transfer_request_type = 0x21; + control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_DOWNLOAD; + control_transfer->ux_transfer_request_index = 0; + control_transfer->ux_transfer_request_data_pointer = dfu_host_buffer; + control_transfer->ux_transfer_request_requested_length = len; + control_transfer->ux_transfer_request_value = block; + return ux_host_stack_transfer_request(control_transfer); +} +static UINT _req_DFU_UPLOAD(UX_TRANSFER *control_transfer, ULONG block, ULONG len) +{ + _req_DFU_LOCK(control_transfer); + control_transfer->ux_transfer_request_type = 0xA1; + control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_UPLOAD; + control_transfer->ux_transfer_request_index = 0; + control_transfer->ux_transfer_request_data_pointer = dfu_host_buffer; + control_transfer->ux_transfer_request_requested_length = len; + control_transfer->ux_transfer_request_value = block; + return ux_host_stack_transfer_request(control_transfer); +} +static UINT _req_DFU_CLRSTATUS(UX_TRANSFER *control_transfer) +{ + _req_DFU_LOCK(control_transfer); + control_transfer->ux_transfer_request_type = 0x21; + control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_CLEAR_STATUS; + control_transfer->ux_transfer_request_index = 0; + control_transfer->ux_transfer_request_data_pointer = UX_NULL; + control_transfer->ux_transfer_request_requested_length = 0; + control_transfer->ux_transfer_request_value = 0; + return ux_host_stack_transfer_request(control_transfer); +} + + +static UINT demo_device_state_change(ULONG event) +{ + return(UX_SUCCESS); +} + +static VOID demo_thread_dfu_activate(VOID *dfu) +{ +} + +static VOID demo_thread_dfu_deactivate(VOID *dfu) +{ +} + +static UINT demo_thread_dfu_read(VOID *dfu, ULONG block_number, UCHAR * data_pointer, ULONG length, ULONG *actual_length) +{ +ULONG return_length; + + stepinfo("dfuRead %ld,%ld: %2x %2x %2x %2x ... -> %p\n", block_number, length, + dfu_device_buffer[0], dfu_device_buffer[1], dfu_device_buffer[2], dfu_device_buffer[3], + data_pointer); + dfu_block = block_number; + dfu_transfer_length = length; + + return_length = UX_MIN(length, sizeof(dfu_device_buffer)); + return_length = UX_MIN(return_length, dfu_actual_length); + + ux_utility_memory_copy(data_pointer, dfu_device_buffer, return_length); + + /* Here is where the data block is read from the firmware. */ + /* Some code needs to be inserted specifically for a target platform. */ + *actual_length = return_length; + return(UX_SUCCESS); +} + +static UINT demo_thread_dfu_write(VOID *dfu, ULONG block_number, UCHAR * data_pointer, ULONG length, ULONG *media_status) +{ + stepinfo("dfuWrite %ld,%ld\n", block_number, length); + dfu_block = block_number; + dfu_transfer_length = length; + ux_utility_memory_copy(dfu_device_buffer, data_pointer, UX_MIN(length, sizeof(dfu_device_buffer))); + + /* Here is where the data block is coming to be written to the firmware. */ + /* Some code needs to be inserted specifically for a target platform. */ + /* Return media status ok. */ + *media_status = UX_SLAVE_CLASS_DFU_MEDIA_STATUS_OK ; + return(UX_SUCCESS); +} + +static UINT demo_thread_dfu_get_status(VOID *dfu, ULONG *media_status) +{ + + /* Return media status ok. */ + *media_status = UX_SLAVE_CLASS_DFU_MEDIA_STATUS_OK ; + + return(UX_SUCCESS); +} + +static UINT demo_thread_dfu_notify(VOID *dfu, ULONG notification) +{ + stepinfo("dfuNotify 0x%lx\n", notification); + switch (notification) + { + + + case UX_SLAVE_CLASS_DFU_NOTIFICATION_BEGIN_DOWNLOAD : + + /* Begin of Download. */ + break; + + case UX_SLAVE_CLASS_DFU_NOTIFICATION_END_DOWNLOAD : + + /* Completion of Download. */ + break; + + case UX_SLAVE_CLASS_DFU_NOTIFICATION_ABORT_DOWNLOAD : + + /* Download was aborted. */ + break; + + case UX_SLAVE_CLASS_DFU_NOTIFICATION_BEGIN_UPLOAD : + + /* Begin of UPLOAD. */ + break; + + case UX_SLAVE_CLASS_DFU_NOTIFICATION_END_UPLOAD : + + /* Completion of UPLOAD. */ + break; + + case UX_SLAVE_CLASS_DFU_NOTIFICATION_ABORT_UPLOAD : + + /* Download was aborted. */ + break; + + default : + + /* Bad notification signal. Should never get here. */ + break; + + } + + return(UX_SUCCESS); +} + +static UINT demo_thread_dfu_custom_request(VOID *dfu, UX_SLAVE_TRANSFER *transfer) +{ +UCHAR *setup; +UCHAR *buffer; + + /* Check state and request to insert custom operation, before the standard + handling process. + If no standard handling process is needed, return UX_SUCCESS. + */ + + /* E.g., accept DNLOAD command with wLength 0 in dfuIDLE. */ + if (ux_device_class_dfu_state_get((UX_SLAVE_CLASS_DFU *)dfu) == UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_IDLE) + { + setup = transfer -> ux_slave_transfer_request_setup; + buffer = transfer -> ux_slave_transfer_request_data_pointer; + + if (setup[UX_SETUP_REQUEST] == UX_SLAVE_CLASS_DFU_COMMAND_DOWNLOAD && + setup[UX_SETUP_LENGTH] == 0 && + setup[UX_SETUP_LENGTH + 1] == 0) + { + + /* Accept the case (by default it's stalled). */ + stepinfo("dfuIDLE - accept dfuDNLOAD & wLength 0\n"); + + /* Fill the status data payload. First with status. */ + *buffer = UX_SLAVE_CLASS_DFU_STATUS_OK; + + /* Poll time out value is set to 500ms. */ + *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT) = UX_DW0(500); + *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 1) = UX_DW1(500); + *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 2) = UX_DW2(500); + + /* Next state: still dfuIDLE. */ + *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_STATE) = (UCHAR) UX_SYSTEM_DFU_STATE_DFU_IDLE; + + /* String index set to 0. */ + *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_STRING) = 0; + + /* We have a request to obtain the status of the DFU instance. */ + _ux_device_stack_transfer_request(transfer, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH); + + /* Inform stack it's taken. */ + return(UX_SUCCESS); + } + } + + /* No custom request. */ + return(UX_ERROR); +} diff --git a/test/regression/usbx_uxe_device_hid_test.c b/test/regression/usbx_uxe_device_hid_test.c new file mode 100644 index 00000000..ca03f7ef --- /dev/null +++ b/test/regression/usbx_uxe_device_hid_test.c @@ -0,0 +1,206 @@ +/* This test is designed to test the ux_utility_descriptor_pack. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_hid.h" + +#include "ux_test.h" + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + + +/* Define USBX test global variables. */ + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_uxe_device_hid_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +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! + printf("SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ +UINT status; +UX_SLAVE_CLASS_HID *dummy_hid_ptr; +UX_SLAVE_CLASS_HID dummy_hid_inst; +UX_SLAVE_CLASS_HID_EVENT dummy_event; +UX_DEVICE_CLASS_HID_RECEIVED_EVENT dummy_rx_event; +UCHAR dummy_buffer[32]; +ULONG dummy_length; +UX_SLAVE_CLASS_HID_PARAMETER dummy_parameter; +UX_SLAVE_CLASS dummy_class_array[2]; + + /* Initialize struct for register ... */ + ux_utility_memory_set(dummy_class_array, 0, sizeof(dummy_class_array)); + _ux_system_slave -> ux_system_slave_class_array = dummy_class_array; +#if UX_MAX_SLAVE_CLASS_DRIVER > 1 + UX_SYSTEM_DEVICE_MAX_CLASS_SET(1); +#endif + + /* Device HID parameters. */ + dummy_parameter.ux_device_class_hid_parameter_report_address = UX_NULL; + dummy_parameter.ux_device_class_hid_parameter_report_length = 10; + status = ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1, 1, &dummy_parameter); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + dummy_parameter.ux_device_class_hid_parameter_report_address = dummy_buffer; + dummy_parameter.ux_device_class_hid_parameter_report_length = 0; + status = ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1, 1, &dummy_parameter); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + dummy_parameter.ux_device_class_hid_parameter_report_address = dummy_buffer; + dummy_parameter.ux_device_class_hid_parameter_report_length = UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH + 1; + status = ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry, + 1, 1, &dummy_parameter); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_device_class_hid_event_set() */ + status = ux_device_class_hid_event_set(UX_NULL, &dummy_event); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_device_class_hid_event_set(&dummy_hid_inst, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_device_class_hid_event_get() */ + status = ux_device_class_hid_event_get(UX_NULL, &dummy_event); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_device_class_hid_event_get(&dummy_hid_inst, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_device_class_hid_protocol_get() */ + dummy_hid_ptr = UX_NULL; + status = ux_device_class_hid_protocol_get(dummy_hid_ptr); + UX_TEST_CHECK_CODE(UX_ERROR, status); + +#if !defined(UX_DEVICE_STANDALONE) + /* ux_device_class_hid_read() */ + status = ux_device_class_hid_read(UX_NULL, dummy_buffer, 8, &dummy_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_device_class_hid_read(&dummy_hid_inst, UX_NULL, 8, &dummy_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_device_class_hid_read(&dummy_hid_inst, dummy_buffer, 0, &dummy_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_device_class_hid_read(&dummy_hid_inst, dummy_buffer, 8, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + +#else + /* ux_device_class_hid_read_run() */ + status = ux_device_class_hid_read_run(UX_NULL, dummy_buffer, 8, &dummy_length); + UX_TEST_CHECK_CODE(UX_STATE_ERROR, status); + status = ux_device_class_hid_read_run(&dummy_hid_inst, UX_NULL, 8, &dummy_length); + UX_TEST_CHECK_CODE(UX_STATE_ERROR, status); + status = ux_device_class_hid_read_run(&dummy_hid_inst, dummy_buffer, 0, &dummy_length); + UX_TEST_CHECK_CODE(UX_STATE_ERROR, status); + status = ux_device_class_hid_read_run(&dummy_hid_inst, dummy_buffer, 8, UX_NULL); + UX_TEST_CHECK_CODE(UX_STATE_ERROR, status); + +#endif + + /* _uxe_device_class_hid_receiver_event_get() */ + status = _uxe_device_class_hid_receiver_event_get(UX_NULL, &dummy_rx_event); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = _uxe_device_class_hid_receiver_event_get(&dummy_hid_inst, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_device_class_hid_receiver_event_free() */ + status = ux_device_class_hid_receiver_event_free(UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_uxe_device_pima_test.c b/test/regression/usbx_uxe_device_pima_test.c new file mode 100644 index 00000000..5cbea5d4 --- /dev/null +++ b/test/regression/usbx_uxe_device_pima_test.c @@ -0,0 +1,820 @@ +/* This test is designed to test the ux_utility_descriptor_pack. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_pima.h" + +#include "ux_test.h" + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG error_counter = 0; + +/* Define USBX test global variables. */ + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_simulation_0; +static void ux_test_thread_simulation_0_entry(ULONG); + + +/* PIMA MTP names ... */ +UCHAR device_info_vendor_name[] = "Microsoft AzureRTOS"; +UCHAR device_info_product_name[] = "AzureRTOS MTP Device"; +UCHAR device_info_serial_no[] = "1.1.1.1"; +UCHAR 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"; + + +/* 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 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 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 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 +}; + +/* 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 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 +}; + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +UINT demo_device_reset(); +UINT demo_device_prop_desc_get(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima, + ULONG device_property, + UCHAR **device_prop_dataset, + ULONG *device_prop_dataset_length); +UINT demo_device_prop_value_get(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima, + ULONG device_property, + UCHAR **device_prop_value, + ULONG *device_prop_value_length); +UINT demo_device_prop_value_set(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima, + ULONG device_property, + UCHAR *device_prop_value, + ULONG device_prop_value_length); +UINT demo_storage_format(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima, + ULONG storage_id); +UINT demo_storage_info_get(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima, + ULONG storage_id); +UINT demo_object_number_get(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima, + ULONG object_format_code, + ULONG object_association, + ULONG *object_number); +UINT demo_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 demo_object_info_get (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima, + ULONG object_handle, + UX_SLAVE_CLASS_PIMA_OBJECT **object); +UINT demo_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 demo_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 demo_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 demo_object_delete(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima, + ULONG object_handle); +UINT demo_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 demo_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 demo_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 demo_object_references_get (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima, + ULONG object_handle, + UCHAR **object_references_array, + ULONG *object_references_array_length); +UINT demo_object_references_set (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima, + ULONG object_handle, + UCHAR *object_references_array, + ULONG object_references_array_length); +UINT demo_object_handle_check(ULONG object_handle, + UX_SLAVE_CLASS_PIMA_OBJECT **object, + ULONG *caller_handle_index); +UINT demo_device_class_custom_entry(UX_SLAVE_CLASS_COMMAND *command); +UINT demo_vendor_request(ULONG request, ULONG request_value, ULONG request_index, ULONG request_length, + UCHAR *transfer_request_buffer, + ULONG *transfer_request_length); + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_uxe_device_pima_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +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! + printf("SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ +UINT status; +UX_SLAVE_CLASS_PIMA dummy_pima_inst; +UX_SLAVE_CLASS_PIMA *dummy_pima = &dummy_pima_inst; +UX_SLAVE_CLASS_COMMAND dummy_command; +UX_SLAVE_CLASS_PIMA_PARAMETER dummy_pima_parameter; +UCHAR *dummy_null_string = ""; + + dummy_pima_parameter.ux_device_class_pima_parameter_manufacturer = device_info_vendor_name; + dummy_pima_parameter.ux_device_class_pima_parameter_model = device_info_product_name; + dummy_pima_parameter.ux_device_class_pima_parameter_device_version = device_info_version; + dummy_pima_parameter.ux_device_class_pima_parameter_serial_number = device_info_serial_no; + dummy_pima_parameter.ux_device_class_pima_parameter_storage_id = 1; + dummy_pima_parameter.ux_device_class_pima_parameter_storage_type = UX_DEVICE_CLASS_PIMA_STC_FIXED_RAM; + dummy_pima_parameter.ux_device_class_pima_parameter_storage_file_system_type = UX_DEVICE_CLASS_PIMA_FSTC_GENERIC_FLAT; + dummy_pima_parameter.ux_device_class_pima_parameter_storage_access_capability = UX_DEVICE_CLASS_PIMA_AC_READ_WRITE; + dummy_pima_parameter.ux_device_class_pima_parameter_storage_max_capacity_low = 1024 * 1024; + dummy_pima_parameter.ux_device_class_pima_parameter_storage_max_capacity_high = 0; + dummy_pima_parameter.ux_device_class_pima_parameter_storage_free_space_low = 800 * 1024; + dummy_pima_parameter.ux_device_class_pima_parameter_storage_free_space_high = 0; + dummy_pima_parameter.ux_device_class_pima_parameter_storage_free_space_image = 0xFFFFFFFF; + dummy_pima_parameter.ux_device_class_pima_parameter_storage_description = pima_parameter_volume_description; + dummy_pima_parameter.ux_device_class_pima_parameter_storage_volume_label = pima_parameter_volume_label; + /* Property lists. */ + dummy_pima_parameter.ux_device_class_pima_parameter_device_properties_list = device_prop_supported; + dummy_pima_parameter.ux_device_class_pima_parameter_supported_capture_formats_list = device_supported_capture_formats; + dummy_pima_parameter.ux_device_class_pima_parameter_supported_image_formats_list = device_supported_image_formats; + /* Callback functions. */ + /* pima_parameter -> ux_device_class_pima_parameter_cancel can be NULL */ + dummy_pima_parameter.ux_device_class_pima_parameter_device_reset = demo_device_reset; + dummy_pima_parameter.ux_device_class_pima_parameter_device_prop_desc_get = demo_device_prop_desc_get; + dummy_pima_parameter.ux_device_class_pima_parameter_device_prop_value_get = demo_device_prop_value_get; + dummy_pima_parameter.ux_device_class_pima_parameter_device_prop_value_set = demo_device_prop_value_set; + dummy_pima_parameter.ux_device_class_pima_parameter_storage_format = demo_storage_format; + dummy_pima_parameter.ux_device_class_pima_parameter_storage_info_get = demo_storage_info_get; + dummy_pima_parameter.ux_device_class_pima_parameter_object_number_get = demo_object_number_get; + dummy_pima_parameter.ux_device_class_pima_parameter_object_handles_get = demo_object_handles_get; + dummy_pima_parameter.ux_device_class_pima_parameter_object_info_get = demo_object_info_get; + dummy_pima_parameter.ux_device_class_pima_parameter_object_data_get = demo_object_data_get; + dummy_pima_parameter.ux_device_class_pima_parameter_object_info_send = demo_object_info_send; + dummy_pima_parameter.ux_device_class_pima_parameter_object_data_send = demo_object_data_send; + dummy_pima_parameter.ux_device_class_pima_parameter_object_delete = demo_object_delete; +#ifdef UX_PIMA_WITH_MTP_SUPPORT + dummy_pima_parameter.ux_device_class_pima_parameter_object_properties_list = object_prop_supported; + dummy_pima_parameter.ux_device_class_pima_parameter_object_prop_desc_get = demo_object_prop_desc_get; + dummy_pima_parameter.ux_device_class_pima_parameter_object_prop_value_get = demo_object_prop_value_get; + dummy_pima_parameter.ux_device_class_pima_parameter_object_prop_value_set = demo_object_prop_value_set; + dummy_pima_parameter.ux_device_class_pima_parameter_object_references_get = demo_object_references_get; + dummy_pima_parameter.ux_device_class_pima_parameter_object_references_set = demo_object_references_set; +#endif + + dummy_command.ux_slave_class_command_parameter = &dummy_pima_parameter; + + /* ux_device_class_pima_entry() */ + dummy_command.ux_slave_class_command_request = UX_SLAVE_CLASS_COMMAND_INITIALIZE; + + dummy_pima_parameter.ux_device_class_pima_parameter_device_reset = UX_NULL; + status = ux_device_class_pima_entry(&dummy_command); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + dummy_pima_parameter.ux_device_class_pima_parameter_device_reset = demo_device_reset; + + dummy_pima_parameter.ux_device_class_pima_parameter_device_prop_desc_get = UX_NULL; + status = ux_device_class_pima_entry(&dummy_command); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + dummy_pima_parameter.ux_device_class_pima_parameter_device_prop_desc_get = demo_device_prop_desc_get; + + dummy_pima_parameter.ux_device_class_pima_parameter_device_prop_value_get = UX_NULL; + status = ux_device_class_pima_entry(&dummy_command); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + dummy_pima_parameter.ux_device_class_pima_parameter_device_prop_value_get = demo_device_prop_value_get; + + dummy_pima_parameter.ux_device_class_pima_parameter_device_prop_value_set = UX_NULL; + status = ux_device_class_pima_entry(&dummy_command); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + dummy_pima_parameter.ux_device_class_pima_parameter_device_prop_value_set = demo_device_prop_value_set; + + dummy_pima_parameter.ux_device_class_pima_parameter_storage_format = UX_NULL; + status = ux_device_class_pima_entry(&dummy_command); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + dummy_pima_parameter.ux_device_class_pima_parameter_storage_format = demo_storage_format; + + dummy_pima_parameter.ux_device_class_pima_parameter_object_number_get = UX_NULL; + status = ux_device_class_pima_entry(&dummy_command); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + dummy_pima_parameter.ux_device_class_pima_parameter_object_number_get = demo_object_number_get; + + dummy_pima_parameter.ux_device_class_pima_parameter_object_handles_get = UX_NULL; + status = ux_device_class_pima_entry(&dummy_command); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + dummy_pima_parameter.ux_device_class_pima_parameter_object_handles_get = demo_object_handles_get; + + dummy_pima_parameter.ux_device_class_pima_parameter_object_info_get = UX_NULL; + status = ux_device_class_pima_entry(&dummy_command); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + dummy_pima_parameter.ux_device_class_pima_parameter_object_info_get = demo_object_info_get; + + dummy_pima_parameter.ux_device_class_pima_parameter_object_data_get = UX_NULL; + status = ux_device_class_pima_entry(&dummy_command); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + dummy_pima_parameter.ux_device_class_pima_parameter_object_data_get = demo_object_data_get; + + dummy_pima_parameter.ux_device_class_pima_parameter_object_info_send = UX_NULL; + status = ux_device_class_pima_entry(&dummy_command); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + dummy_pima_parameter.ux_device_class_pima_parameter_object_info_send = demo_object_info_send; + + dummy_pima_parameter.ux_device_class_pima_parameter_object_data_send = UX_NULL; + status = ux_device_class_pima_entry(&dummy_command); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + dummy_pima_parameter.ux_device_class_pima_parameter_object_data_send = demo_object_data_send; + + dummy_pima_parameter.ux_device_class_pima_parameter_object_delete = UX_NULL; + status = ux_device_class_pima_entry(&dummy_command); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + dummy_pima_parameter.ux_device_class_pima_parameter_object_delete = demo_object_delete; + +#ifdef UX_PIMA_WITH_MTP_SUPPORT + dummy_pima_parameter.ux_device_class_pima_parameter_object_properties_list = UX_NULL; + status = ux_device_class_pima_entry(&dummy_command); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + dummy_pima_parameter.ux_device_class_pima_parameter_object_properties_list = object_prop_supported; + + dummy_pima_parameter.ux_device_class_pima_parameter_object_prop_desc_get = UX_NULL; + status = ux_device_class_pima_entry(&dummy_command); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + dummy_pima_parameter.ux_device_class_pima_parameter_object_prop_desc_get = demo_object_prop_desc_get; + + dummy_pima_parameter.ux_device_class_pima_parameter_object_prop_value_get = UX_NULL; + status = ux_device_class_pima_entry(&dummy_command); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + dummy_pima_parameter.ux_device_class_pima_parameter_object_prop_value_get = demo_object_prop_value_get; + + dummy_pima_parameter.ux_device_class_pima_parameter_object_prop_value_set = UX_NULL; + status = ux_device_class_pima_entry(&dummy_command); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + dummy_pima_parameter.ux_device_class_pima_parameter_object_prop_value_set = demo_object_prop_value_set; + + dummy_pima_parameter.ux_device_class_pima_parameter_object_references_get = UX_NULL; + status = ux_device_class_pima_entry(&dummy_command); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + dummy_pima_parameter.ux_device_class_pima_parameter_object_references_get = demo_object_references_get; + + dummy_pima_parameter.ux_device_class_pima_parameter_object_references_set = UX_NULL; + status = ux_device_class_pima_entry(&dummy_command); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + dummy_pima_parameter.ux_device_class_pima_parameter_object_references_set = demo_object_references_set; +#endif + + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +UINT demo_device_reset() +{ + return(UX_SUCCESS); +} + +UINT demo_device_prop_desc_get(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima, + ULONG device_property, + UCHAR **device_prop_dataset, + ULONG *device_prop_dataset_length) + +{ + return(UX_ERROR); +} + +UINT demo_device_prop_value_get(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima, + ULONG device_property, + UCHAR **device_prop_value, + ULONG *device_prop_value_length) +{ + return(UX_ERROR); +} + +UINT demo_device_prop_value_set(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima, + ULONG device_property, + UCHAR *device_prop_value, + ULONG device_prop_value_length) +{ + return(UX_ERROR); +} + + +UINT demo_storage_format(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima, + ULONG storage_id) +{ + return(UX_ERROR); +} + + +UINT demo_storage_info_get(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima, + ULONG storage_id) +{ + return(UX_ERROR); +} + +UINT demo_object_number_get(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima, + ULONG object_format_code, + ULONG object_association, + ULONG *object_number) +{ + return(UX_ERROR); +} + +UINT demo_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) +{ + return(UX_ERROR); +} + +UINT demo_object_info_get (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima, + ULONG object_handle, + UX_SLAVE_CLASS_PIMA_OBJECT **object) +{ + return(UX_ERROR); +} + +UINT demo_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) + +{ + return(UX_ERROR); +} + +UINT demo_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) +{ + return(UX_ERROR); +} + + +UINT demo_object_data_send (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima, + ULONG object_handle, + ULONG phase , + UCHAR *object_buffer, + ULONG object_offset, + ULONG object_length) +{ + return(UX_ERROR); +} + +UINT demo_object_delete(struct UX_SLAVE_CLASS_PIMA_STRUCT *pima, + ULONG object_handle) +{ + return(UX_ERROR); +} + + +UINT demo_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) +{ + return(UX_ERROR); +} + + +UINT demo_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) +{ + return(UX_ERROR); +} + + +UINT demo_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) +{ + return(UX_ERROR); +} + + +UINT demo_object_references_get (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima, + ULONG object_handle, + UCHAR **object_references_array, + ULONG *object_references_array_length) +{ + return(UX_ERROR); +} + + +UINT demo_object_references_set (struct UX_SLAVE_CLASS_PIMA_STRUCT *pima, + ULONG object_handle, + UCHAR *object_references_array, + ULONG object_references_array_length) +{ + return(UX_ERROR); +} + + +UINT demo_object_handle_check(ULONG object_handle, + UX_SLAVE_CLASS_PIMA_OBJECT **object, + ULONG *caller_handle_index) +{ + return(UX_ERROR); +} diff --git a/test/regression/usbx_uxe_device_printer_test.c b/test/regression/usbx_uxe_device_printer_test.c new file mode 100644 index 00000000..2cc29b41 --- /dev/null +++ b/test/regression/usbx_uxe_device_printer_test.c @@ -0,0 +1,191 @@ +/* This test is designed to test the ux_utility_descriptor_pack. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_printer.h" + +#include "ux_test.h" + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG error_counter = 0; + +/* Define USBX test global variables. */ + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_simulation_0; +static void ux_test_thread_simulation_0_entry(ULONG); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_uxe_device_printer_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +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! + printf("SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ +UINT status; +UX_DEVICE_CLASS_PRINTER dummy_printer_inst; +UX_DEVICE_CLASS_PRINTER *dummy_printer = &dummy_printer_inst; +UCHAR dummy_buffer[32]; +ULONG dummy_actual_length; +UX_SLAVE_CLASS_COMMAND dummy_command; +UX_DEVICE_CLASS_PRINTER_PARAMETER dummy_printer_parameter; + +#if !defined(UX_DEVICE_STANDALONE) +/* Device printer device ID. */ +UCHAR printer_device_id[] = + { + " " // Will be replaced by length (big endian) + "MFG:Generic;" // manufacturer (case sensitive) + "MDL:Generic_/_Text_Only;" // model (case sensitive) + "CMD:1284.4;" // PDL command set + "CLS:PRINTER;" // class + "DES:Generic text only printer;" // description + }; + + dummy_printer_parameter.ux_device_class_printer_device_id = printer_device_id; + dummy_command.ux_slave_class_command_parameter = &dummy_printer_parameter; + + /* ux_device_class_printer_entry() */ + dummy_command.ux_slave_class_command_request = UX_SLAVE_CLASS_COMMAND_INITIALIZE; + + printer_device_id[0] = 2; + printer_device_id[1] = 1; + status = ux_device_class_printer_entry(&dummy_command); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_device_class_printer_write() */ + status = ux_device_class_printer_write(UX_NULL, dummy_buffer, 32, &dummy_actual_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_device_class_printer_write(dummy_printer, UX_NULL, 32, &dummy_actual_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_device_class_printer_write(dummy_printer, dummy_buffer, 32, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_device_class_printer_read() */ + status = ux_device_class_printer_read(UX_NULL, dummy_buffer, 32, &dummy_actual_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_device_class_printer_read(dummy_printer, UX_NULL, 32, &dummy_actual_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_device_class_printer_read(dummy_printer, dummy_buffer, 32, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_device_class_printer_ioctl() */ + status = ux_device_class_printer_ioctl(UX_NULL, UX_DEVICE_CLASS_PRINTER_IOCTL_PORT_STATUS_SET, 0); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); +#else + + /* ux_device_class_printer_read_run() */ + status = ux_device_class_printer_read_run(UX_NULL, dummy_buffer, 32, &dummy_actual_length); + UX_TEST_CHECK_CODE(UX_STATE_ERROR, status); + + status = ux_device_class_printer_read_run(&dummy_printer_inst, UX_NULL, 32, &dummy_actual_length); + UX_TEST_CHECK_CODE(UX_STATE_ERROR, status); + + status = ux_device_class_printer_read_run(&dummy_printer_inst, dummy_buffer, 32, UX_NULL); + UX_TEST_CHECK_CODE(UX_STATE_ERROR, status); + + /* ux_device_class_cdc_acm_write_run() */ + status = ux_device_class_printer_write_run(UX_NULL, dummy_buffer, 32, &dummy_actual_length); + UX_TEST_CHECK_CODE(UX_STATE_ERROR, status); + + status = ux_device_class_printer_write_run(&dummy_printer_inst, UX_NULL, 32, &dummy_actual_length); + UX_TEST_CHECK_CODE(UX_STATE_ERROR, status); + + status = ux_device_class_printer_write_run(&dummy_printer_inst, dummy_buffer, 32, UX_NULL); + UX_TEST_CHECK_CODE(UX_STATE_ERROR, status); + +#endif + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_uxe_device_stack_test.c b/test/regression/usbx_uxe_device_stack_test.c new file mode 100644 index 00000000..ad20181d --- /dev/null +++ b/test/regression/usbx_uxe_device_stack_test.c @@ -0,0 +1,154 @@ +/* This test is designed to test the ux_utility_descriptor_pack. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_dummy.h" +#include "ux_host_class_dummy.h" + +#include "ux_test.h" + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + + +/* Define USBX test global variables. */ + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_uxe_system_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +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! + printf("SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_memory; + memory_pointer = stack_pointer + (UX_TEST_STACK_SIZE * 2); +#if 1 + /* Initialize USBX Memory. */ + status = ux_system_initialize(memory_pointer, UX_TEST_MEMORY_SIZE, UX_NULL, 0); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#endif + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ +UINT status; +UCHAR *buffer = (UCHAR *)&status; + + /* ux_device_stack_initialize() */ + status = ux_device_stack_initialize(UX_NULL, 64, buffer, 64, buffer, 64, buffer, 64, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_device_stack_initialize(buffer, 64, UX_NULL, 64, buffer, 64, buffer, 64, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_device_stack_initialize(buffer, 64, buffer, 0, buffer, 64, buffer, 64, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_device_stack_initialize(buffer, 64, buffer, 64, UX_NULL, 64, buffer, 64, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_device_stack_initialize(buffer, 64, buffer, 64, buffer, 64, UX_NULL, 64, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_device_stack_initialize(buffer, 64, buffer, 64, buffer, 64, buffer, 0, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_device_stack_class_register() */ + status = ux_device_stack_class_register(UX_NULL, _ux_device_class_dummy_entry, 0, 1, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_device_stack_class_register(_ux_device_class_dummy_name, UX_NULL, 0, 1, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_device_stack_class_unregister() */ + status = ux_device_stack_class_unregister(UX_NULL, _ux_device_class_dummy_entry); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_device_stack_class_unregister(_ux_device_class_dummy_name, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + +#if defined(UX_DEVICE_STANDALONE) +#endif + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_uxe_device_storage_test.c b/test/regression/usbx_uxe_device_storage_test.c new file mode 100644 index 00000000..ab93ea76 --- /dev/null +++ b/test/regression/usbx_uxe_device_storage_test.c @@ -0,0 +1,191 @@ +/* This test is designed to test the ux_utility_descriptor_pack. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_storage.h" + +#include "ux_test.h" + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + + +/* Define USBX test global variables. */ + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_uxe_device_storage_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +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! + printf("SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static UINT _dummy_storage_media_read(VOID *storage, ULONG lun, UCHAR *data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + return(0); +} +static UINT _dummy_storage_media_write(VOID *storage, ULONG lun, UCHAR *data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + return(0); +} +static UINT _dummy_storage_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status) +{ + return(0); +} +static UINT _dummy_storage_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status) +{ + return(0); +} +static UINT _dummy_storage_media_notification(VOID *storage, ULONG lun, ULONG media_id, ULONG notification_class, UCHAR **media_notification, ULONG *media_notification_length) +{ + return(0); +} + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ + +UINT status; +UX_SLAVE_CLASS_COMMAND dummy_command; +UX_SLAVE_CLASS_STORAGE_PARAMETER dummy_parameter; + + /* uxe storage initialize. */ + dummy_command.ux_slave_class_command_parameter = &dummy_parameter; + dummy_command.ux_slave_class_command_request = UX_SLAVE_CLASS_COMMAND_INITIALIZE; + + dummy_parameter.ux_slave_class_storage_parameter_number_lun = 0x7F; + status = ux_device_class_storage_entry(&dummy_command); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + dummy_parameter.ux_slave_class_storage_parameter_number_lun = 1; + + dummy_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = UX_NULL; + dummy_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = _dummy_storage_media_write; + dummy_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = _dummy_storage_media_flush; + dummy_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = _dummy_storage_media_status; + dummy_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_notification = _dummy_storage_media_notification; + status = ux_device_class_storage_entry(&dummy_command); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + dummy_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = _dummy_storage_media_read; + dummy_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = UX_NULL; + dummy_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = _dummy_storage_media_flush; + dummy_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = _dummy_storage_media_status; + dummy_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_notification = _dummy_storage_media_notification; + status = ux_device_class_storage_entry(&dummy_command); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + dummy_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = _dummy_storage_media_read; + dummy_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = _dummy_storage_media_write; + dummy_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = _dummy_storage_media_flush; + dummy_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = UX_NULL; + dummy_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_notification = _dummy_storage_media_notification; + status = ux_device_class_storage_entry(&dummy_command); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + +#if defined(UX_SLAVE_CLASS_STORAGE_INCLUDE_MMC) + dummy_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = _dummy_storage_media_read; + dummy_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = _dummy_storage_media_write; + dummy_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush = _dummy_storage_media_flush; + dummy_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = _dummy_storage_media_status; + dummy_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_notification = UX_NULL; + status = ux_device_class_storage_entry(&dummy_command); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); +#endif + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_uxe_device_video_test.c b/test/regression/usbx_uxe_device_video_test.c new file mode 100644 index 00000000..fa72ba25 --- /dev/null +++ b/test/regression/usbx_uxe_device_video_test.c @@ -0,0 +1,616 @@ +/* This test is designed to test the ux_utility_descriptor_pack. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" +#include "ux_host_class_video.h" +#include "ux_host_class_dummy.h" + +#include "ux_device_class_video.h" + +#include "ux_test.h" + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG error_counter = 0; + +/* Define USBX test global variables. */ + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_simulation_0; +static void ux_test_thread_simulation_0_entry(ULONG); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +/* Define constants. */ + +#define UX_DEMO_REQUEST_MAX_LENGTH \ + ((UX_HCD_SIM_HOST_MAX_PAYLOAD) > (UX_SLAVE_REQUEST_DATA_MAX_LENGTH) ? \ + (UX_HCD_SIM_HOST_MAX_PAYLOAD) : (UX_SLAVE_REQUEST_DATA_MAX_LENGTH)) + +#define UX_DEMO_DEBUG_SIZE (4096*8) +#define UX_DEMO_STACK_SIZE 1024 +#define UX_DEMO_BUFFER_SIZE (UX_DEMO_REQUEST_MAX_LENGTH + 1) +#define UX_DEMO_MEMORY_SIZE (128*1024) +#define UX_DEMO_ENDPOINT_SIZE 480 + +#define UX_TEST_LOG_SIZE (64) + + +/* Define local/extern function prototypes. */ +static void test_thread_entry(ULONG); +static TX_THREAD tx_test_thread_host_simulation; +static TX_THREAD tx_test_thread_slave_simulation; +static void tx_test_thread_host_simulation_entry(ULONG); +static void tx_test_thread_slave_simulation_entry(ULONG); + + +/* Define global data structures. */ +static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; + +static UX_HOST_CLASS_DUMMY *dummy_control; +static UX_HOST_CLASS_DUMMY *dummy_tx; +static UX_HOST_CLASS_DUMMY *dummy_rx; + +static UX_DEVICE_CLASS_VIDEO *device_video; +static UX_DEVICE_CLASS_VIDEO_STREAM *device_video_tx_stream; +static UX_DEVICE_CLASS_VIDEO_STREAM *device_video_rx_stream; +static UX_DEVICE_CLASS_VIDEO_PARAMETER device_video_parameter; +static UX_DEVICE_CLASS_VIDEO_STREAM_PARAMETER device_video_stream_parameter[2]; + +static UX_SLAVE_TRANSFER *device_video_tx_transfer; +static UX_SLAVE_TRANSFER *device_video_rx_transfer; + +static UX_HOST_CLASS_VIDEO *video; + +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_video_sem_usage; +static ULONG rsc_video_sem_get_count; +static ULONG rsc_video_mutex_usage; +static ULONG rsc_video_mem_usage; + +static ULONG interaction_count; + +static UCHAR error_callback_ignore = UX_TRUE; +static ULONG error_callback_counter; + +static struct BUFFER_LOG_STRUCT { + ULONG length; + UCHAR data[256]; +} buffer_log[UX_TEST_LOG_SIZE]; +static ULONG buffer_log_count = 0; +#define SAVE_BUFFER_LOG(buf,siz) do { \ + if (buffer_log_count < UX_TEST_LOG_SIZE) { \ + ULONG __local_size__ = ((siz) > 256) ? 256 : (siz); \ + buffer_log[buffer_log_count].length = (siz); \ + _ux_utility_memory_copy(buffer_log[buffer_log_count].data, (buf), __local_size__); \ + } \ + buffer_log_count ++; \ +} while(0) + +static ULONG test_tx_ack_count = 0xFFFFFFFF; +static ULONG test_tx_ins_count = 0; +static ULONG test_tx_ins_way = 0; + +static struct CALLBACK_INVOKE_LOG_STRUCT { + VOID *func; + VOID *param1; + VOID *param2; + VOID *param3; +} callback_invoke_log[UX_TEST_LOG_SIZE]; +static ULONG callback_invoke_count = 0; + +#define SAVE_CALLBACK_INVOKE_LOG(f,p1,p2,p3) do { \ + if (callback_invoke_count < UX_TEST_LOG_SIZE) { \ + callback_invoke_log[callback_invoke_count].func = (VOID *)(f); \ + callback_invoke_log[callback_invoke_count].param1 = (VOID *)(p1); \ + callback_invoke_log[callback_invoke_count].param2 = (VOID *)(p2); \ + callback_invoke_log[callback_invoke_count].param3 = (VOID *)(p3); \ + callback_invoke_count++; \ + } \ +} while(0) +#define RESET_CALLBACK_INVOKE_LOG() do { \ + callback_invoke_count = 0; \ +} while(0) + +/* Define device framework. */ + +#define W(d) UX_DW0(d), UX_DW1(d) +#define DW(d) UX_DW0(d), UX_DW1(d), UX_DW2(d), UX_DW3(d) + +#define _DEVICE_DESCRIPTOR() \ +/* --------------------------------------- Device Descriptor */ \ +/* 0 bLength, bDescriptorType */ 18, 0x01, \ +/* 2 bcdUSB */ UX_DW0(0x200),UX_DW1(0x200), \ +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, \ +/* 7 bMaxPacketSize0 */ 0x08, \ +/* 8 idVendor, idProduct */ 0x84, 0x84, 0x01, 0x00, \ +/* 12 bcdDevice */ UX_DW0(0x100),UX_DW1(0x100), \ +/* 14 iManufacturer, iProduct, iSerialNumber */ 0, 0, 0, \ +/* 17 bNumConfigurations */ 1, + +#define _DEVICE_QUALIFIER_DESCRIPTOR() \ +/* ----------------------------- Device Qualifier Descriptor */ \ +/* 0 bLength, bDescriptorType */ 10, 0x06, \ +/* 2 bcdUSB */ UX_DW0(0x200),UX_DW1(0x200), \ +/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol */ 0x00, 0x00, 0x00, \ +/* 7 bMaxPacketSize0 */ 8, \ +/* 8 bNumConfigurations */ 1, \ +/* 9 bReserved */ 0, + +#define _CONFIGURE_DESCRIPTOR(total_len,n_ifc,cfg_v) \ +/* -------------------------------- Configuration Descriptor */ \ +/* 0 bLength, bDescriptorType */ 9, 0x02, \ +/* 2 wTotalLength */ UX_DW0(total_len),UX_DW1(total_len),\ +/* 4 bNumInterfaces, bConfigurationValue */ (n_ifc), (cfg_v), \ +/* 6 iConfiguration */ 0, \ +/* 7 bmAttributes, bMaxPower */ 0x80, 50, + +#define _IAD_DESCRIPTOR(ifc_0,ifc_cnt,cls,sub,protocol) \ +/* ------------------------ Interface Association Descriptor */ \ +/* 0 bLength, bDescriptorType */ 8, 0x0B, \ +/* 2 bFirstInterface, bInterfaceCount */ (ifc_0), (ifc_cnt), \ +/* 4 bFunctionClass, bFunctionSubClass, bFunctionProtocol */ (cls), (sub), (protocol), \ +/* 7 iFunction */ 0, + +#define _INTERFACE_DESCRIPTOR(ifc,alt,n_ep,cls,sub,protocol) \ +/* ------------------------------------ Interface Descriptor */ \ +/* 0 bLength, bDescriptorType */ 9, 0x04, \ +/* 2 bInterfaceNumber, bAlternateSetting */ (ifc), (alt), \ +/* 4 bNumEndpoints */ (n_ep), \ +/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ (cls), (sub), (protocol), \ +/* 8 iInterface */ 0, + +#define _ENDPOINT_DESCRIPTOR(addr,attr,pkt_siz,interval) \ +/* ------------------------------------- Endpoint Descriptor */ \ +/* 0 bLength, bDescriptorType */ 7, 0x05, \ +/* 2 bEndpointAddress, bmAttributes */ (addr), (attr), \ +/* 4 wMaxPacketSize, bInterval */ UX_DW0(pkt_siz),UX_DW1(pkt_siz),(interval), + +#define _VC_DESCRIPTORS_LEN (14+17+9+17+9) +#define _VC_DESCRIPTORS() \ + /*--------------------------- Class VC Interface Descriptor (VC_HEADER). */ \ + 14, 0x24, 0x01, W(0x150), \ + W(_VC_DESCRIPTORS_LEN), /* wTotalLength. */ \ + DW(6000000), /* dwClockFrequency. */ \ + 2, /* bInCollection. */ \ + 1, 2, /* BaInterfaceNr(2). */ \ + /*--------------------------- Input Terminal (VC_INPUT_TERMINAL, Camera) */ \ + 17, 0x24, 0x02, \ + 0x01, /* bTerminalID, ITT_CAMERA */ \ + W(0x201), /* wTerminalType */ \ + 0x00, 0x00, W(0), W(0), W(0), \ + 0x02, W(0), /* bControlSize, bmControls */ \ + /*---------------------------- Output Terminal (VC_OUTPUT_TERMINAL, USB) */ \ + 9, 0x24, 0x03, \ + 0x02, /* bTerminalID */ \ + W(0x0101), /* wTerminalType, TT_STREAMING */ \ + 0x00, 0x01/* bSourceID */, 0x00, \ + /*--------------------------- Input Terminal (VC_INPUT_TERMINAL, USB) */ \ + 17, 0x24, 0x02, \ + 0x03, /* bTerminalID */ \ + W(0x101), /* wTerminalType, TT_STREAMING */ \ + 0x00, 0x00, W(0), W(0), W(0), \ + 0x02, W(0), /* bControlSize, bmControls */ \ + /*---------------------------- Output Terminal (VC_OUTPUT_TERMINAL, DISPLAY) */ \ + 9, 0x24, 0x03, \ + 0x04, /* bTerminalID */ \ + W(0x0301), /* wTerminalType, OTT_DISPLAY */ \ + 0x00, 0x03/* bSourceID */, 0x00, + +#if 0 + /*--------------------------------- Processing Unit (VC_PROCESSING_UNIT) */ \ + 12, 0x24, 0x05, \ + , /* bUnitID */ \ + , /* bSourceID */ \ + W(0), \ + 3 /* bControlSize */, 0, 0, 0 /*bmControls */, \ + 0x00, 0x00, \ + /*--------------------------------- Processing Unit (VC_PROCESSING_UNIT) */ \ + 12, 0x24, 0x05, \ + , /* bUnitID */ \ + , /* bSourceID */ \ + W(0), \ + 3 /* bControlSize */, 0, 0, 0 /*bmControls */, \ + 0x00, 0x00, \ + +#endif + +#define _VS_IN_DESCRIPTORS_LEN (14+11+38) +#define _VS_IN_DESCRIPTORS() \ + /*------------------------- Class VS Header Descriptor (VS_INPUT_HEADER) */ \ + 14, 0x24, 0x01, \ + 0X01, /* bNumFormats */ \ + W(_VS_IN_DESCRIPTORS_LEN), /* wTotalLength */ \ + 0x81, /* bEndpointAddress */ \ + 0x00, \ + 0x02, /* bTerminalLink */ \ + 0x00, /* bStillCaptureMethod */ \ + 0x00, 0x00, /* bTriggerSupport, bTriggerUsage */ \ + 0x01, 0x00, /* bControlSize, bmaControls */ \ + /*------------------------------- VS Format Descriptor (VS_FORMAT_MJPEG) */ \ + 11, 0x24, 0x06, \ + 0x01, /* bFormatIndex */ \ + 0x01, /* bNumFrameDescriptors */ \ + 0x01, /* bmFlags */ \ + 0x01, /* bDefaultFrameIndex */ \ + 0x00, 0x00, 0x00, 0x00, \ + /*--------------------------------- VS Frame Descriptor (VS_FRAME_MJPEG) */ \ + 38, 0x24, 0x07, \ + 0x01, /* bFrameIndex */ \ + 0x03, /* bmCapabilities */ \ + W(176), W(144), /* wWidth, wHeight */ \ + DW(912384), DW(912384), /* dwMinBitRate, dwMaxBitRate */ \ + DW(38016), /* dwMaxVideoFrameBufSize */ \ + DW(666666), /* dwDefaultFrameInterval */ \ + 0x00, /* bFrameIntervalType */ \ + DW(666666), DW(666666), DW(0), /* dwMinFrameInterval, dwMaxFrameInterval, dwFrameIntervalStep */ + +#define _VS_OUT_DESCRIPTORS_LEN (11+11+38) +#define _VS_OUT_DESCRIPTORS() \ + /*------------------------- Class VS Header Descriptor (VS_OUTPUT_HEADER) */ \ + 11, 0x24, 0x02, \ + 0x01, /* bNumFormats */ \ + W(_VS_OUT_DESCRIPTORS_LEN), /* wTotalLength */ \ + 0x02, /* bEndpointAddress */ \ + 0x00, \ + 0x03, /* bTerminalLink */ \ + 0x01, 0x00, /* bControlSize, bmaControls */ \ + /*------------------------------- VS Format Descriptor (VS_FORMAT_MJPEG) */ \ + 11, 0x24, 0x06, \ + 0x01, /* bFormatIndex */ \ + 0x01, /* bNumFrameDescriptors */ \ + 0x01, /* bmFlags */ \ + 0x01, /* bDefaultFrameIndex */ \ + 0x00, 0x00, 0x00, 0x00, \ + /*--------------------------------- VS Frame Descriptor (VS_FRAME_MJPEG) */ \ + 38, 0x24, 0x07, \ + 0x01, /* bFrameIndex */ \ + 0x03, /* bmCapabilities */ \ + W(176), W(144), /* wWidth, wHeight */ \ + DW(912384), DW(912384), /* dwMinBitRate, dwMaxBitRate */ \ + DW(38016), /* dwMaxVideoFrameBufSize */ \ + DW(666666), /* dwDefaultFrameInterval */ \ + 0x00, /* bFrameIntervalType */ \ + DW(666666), DW(666666), DW(0), /* dwMinFrameInterval, dwMaxFrameInterval, dwFrameIntervalStep */ + + +#define _CONFIGURE_DESCRIPTORS_LEN (9+ 8+ 9+_VC_DESCRIPTORS_LEN+ 9+_VS_IN_DESCRIPTORS_LEN+9+7+ 9+_VS_OUT_DESCRIPTORS_LEN+9+7) + +static unsigned char device_framework_full_speed[] = { + _DEVICE_DESCRIPTOR() + _CONFIGURE_DESCRIPTOR(_CONFIGURE_DESCRIPTORS_LEN,3,1) + _IAD_DESCRIPTOR(0,3,0x0E,0x03,0x00) + + _INTERFACE_DESCRIPTOR(0,0,0,0x0E,0x01,0x01) + _VC_DESCRIPTORS() + + _INTERFACE_DESCRIPTOR(1,0,0,0x0E,0x02,0x00) + _VS_IN_DESCRIPTORS() + _INTERFACE_DESCRIPTOR(1,1,1,0x0E,0x02,0x00) + _ENDPOINT_DESCRIPTOR(0x81,0x05,UX_DEMO_ENDPOINT_SIZE,0x01) + + _INTERFACE_DESCRIPTOR(2,0,0,0x0E,0x02,0x00) + _VS_OUT_DESCRIPTORS() + _INTERFACE_DESCRIPTOR(2,1,1,0x0E,0x02,0x00) + _ENDPOINT_DESCRIPTOR(0x02,0x05,UX_DEMO_ENDPOINT_SIZE,0x01) +}; +#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) + +static unsigned char device_framework_high_speed[] = { + _DEVICE_DESCRIPTOR() + _DEVICE_QUALIFIER_DESCRIPTOR() + _CONFIGURE_DESCRIPTOR(_CONFIGURE_DESCRIPTORS_LEN,3,1) + _IAD_DESCRIPTOR(0,3,0x0E,0x03,0x00) + + _INTERFACE_DESCRIPTOR(0,0,0,0x0E,0x01,0x01) + _VC_DESCRIPTORS() + + _INTERFACE_DESCRIPTOR(1,0,0,0x0E,0x02,0x00) + _VS_IN_DESCRIPTORS() + _INTERFACE_DESCRIPTOR(1,1,1,0x0E,0x02,0x00) + _ENDPOINT_DESCRIPTOR(0x81,0x05,UX_DEMO_ENDPOINT_SIZE,0x01) + + _INTERFACE_DESCRIPTOR(2,0,0,0x0E,0x02,0x00) + _VS_OUT_DESCRIPTORS() + _INTERFACE_DESCRIPTOR(2,1,1,0x0E,0x02,0x00) + _ENDPOINT_DESCRIPTOR(0x02,0x05,UX_DEMO_ENDPOINT_SIZE,0x01) +}; +#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) + +static unsigned char string_framework[] = { + +/* Manufacturer string descriptor : Index 1 - "Express Logic" */ + 0x09, 0x04, 0x01, 0x0c, + 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c, + 0x6f, 0x67, 0x69, 0x63, + +/* Product string descriptor : Index 2 - "EL Composite device" */ + 0x09, 0x04, 0x02, 0x13, + 0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, + +/* Serial Number string descriptor : Index 3 - "0001" */ + 0x09, 0x04, 0x03, 0x04, + 0x30, 0x30, 0x30, 0x31 +}; +#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. */ +static unsigned char language_id_framework[] = { + +/* English. */ + 0x09, 0x04 +}; +#define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) + +static VOID device_video_activate(VOID *video_instance) +{ + device_video = (UX_DEVICE_CLASS_VIDEO *)video_instance; + ux_device_class_video_stream_get(device_video, 0, &device_video_tx_stream); + ux_device_class_video_stream_get(device_video, 1, &device_video_rx_stream); + // printf("sVID:%p,%p,%p\n", video_instance, device_video_tx_stream, device_video_rx_stream); +} +static VOID device_video_deactivate(VOID *video_instance) +{ + if ((VOID *)device_video == video_instance) + { + device_video = UX_NULL; + device_video_tx_stream = UX_NULL; + device_video_rx_stream = UX_NULL; + } +} +static VOID device_video_tx_stream_change(UX_DEVICE_CLASS_VIDEO_STREAM *video, ULONG alt) +{ + SAVE_CALLBACK_INVOKE_LOG(device_video_tx_stream_change, video, (ALIGN_TYPE)alt, 0); +} +static VOID device_video_rx_stream_change(UX_DEVICE_CLASS_VIDEO_STREAM *video, ULONG alt) +{ + SAVE_CALLBACK_INVOKE_LOG(device_video_rx_stream_change, video, (ALIGN_TYPE)alt, 0); + + device_video_rx_transfer = UX_NULL; +} +static UINT device_video_vc_control_process(UX_DEVICE_CLASS_VIDEO *video, UX_SLAVE_TRANSFER *transfer) +{ + SAVE_CALLBACK_INVOKE_LOG(device_video_vc_control_process, video, transfer, 0); + return(UX_ERROR); +} +static UINT device_video_vs_control_process(UX_DEVICE_CLASS_VIDEO_STREAM *video, UX_SLAVE_TRANSFER *transfer) +{ + SAVE_CALLBACK_INVOKE_LOG(device_video_vs_control_process, video, transfer, 0); + return(UX_ERROR); +} +static VOID device_video_tx_done(UX_DEVICE_CLASS_VIDEO_STREAM *video, ULONG length) +{ + SAVE_CALLBACK_INVOKE_LOG(device_video_tx_done, video, (ALIGN_TYPE)length, 0); +} +static VOID device_video_rx_done(UX_DEVICE_CLASS_VIDEO_STREAM *video, ULONG length) +{ + SAVE_CALLBACK_INVOKE_LOG(device_video_rx_done, video, (ALIGN_TYPE)length, 0); +} + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_uxe_device_video_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +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! + printf("SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif /* UX_DEVICE_CLASS_VIDEO_ENABLE_ERROR_CHECKING */ + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + 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); + + UX_TEST_CHECK_SUCCESS(status); + + /* Set the parameters for callback when insertion/extraction of a Video device, with IAD. */ +#if defined(UX_DEVICE_STANDALONE) + device_video_stream_parameter[0].ux_device_class_video_stream_parameter_task_function = ux_device_class_video_write_task_function; +#else + device_video_stream_parameter[0].ux_device_class_video_stream_parameter_thread_entry = ux_device_class_video_write_thread_entry; +#endif + device_video_stream_parameter[0].ux_device_class_video_stream_parameter_callbacks.ux_device_class_video_stream_change = device_video_tx_stream_change; + device_video_stream_parameter[0].ux_device_class_video_stream_parameter_callbacks.ux_device_class_video_stream_payload_done = device_video_tx_done; + device_video_stream_parameter[0].ux_device_class_video_stream_parameter_callbacks.ux_device_class_video_stream_request = device_video_vs_control_process; + device_video_stream_parameter[0].ux_device_class_video_stream_parameter_max_payload_buffer_size = UX_DEMO_ENDPOINT_SIZE; + device_video_stream_parameter[0].ux_device_class_video_stream_parameter_max_payload_buffer_nb = 8; +#if defined(UX_DEVICE_STANDALONE) + device_video_stream_parameter[1].ux_device_class_video_stream_parameter_task_function = ux_device_class_video_read_task_function; +#else + device_video_stream_parameter[1].ux_device_class_video_stream_parameter_thread_entry = ux_device_class_video_read_thread_entry; +#endif + device_video_stream_parameter[1].ux_device_class_video_stream_parameter_callbacks.ux_device_class_video_stream_change = device_video_rx_stream_change; + device_video_stream_parameter[1].ux_device_class_video_stream_parameter_callbacks.ux_device_class_video_stream_payload_done = device_video_rx_done; + device_video_stream_parameter[1].ux_device_class_video_stream_parameter_callbacks.ux_device_class_video_stream_request = device_video_vs_control_process; + device_video_stream_parameter[1].ux_device_class_video_stream_parameter_max_payload_buffer_size = UX_DEMO_ENDPOINT_SIZE; + device_video_stream_parameter[1].ux_device_class_video_stream_parameter_max_payload_buffer_nb = 8; + // device_video_parameter.ux_device_class_video_parameter_streams = device_video_stream_parameter; + device_video_parameter.ux_device_class_video_parameter_streams_nb = 2; + device_video_parameter.ux_device_class_video_parameter_callbacks.ux_slave_class_video_instance_activate = device_video_activate; + device_video_parameter.ux_device_class_video_parameter_callbacks.ux_slave_class_video_instance_deactivate = device_video_deactivate; + device_video_parameter.ux_device_class_video_parameter_callbacks.ux_device_class_video_request = device_video_vc_control_process; + device_video_parameter.ux_device_class_video_parameter_callbacks.ux_device_class_video_arg = UX_NULL; + + status = ux_device_stack_class_register(_ux_system_device_class_video_name, ux_device_class_video_entry, + 1, 0, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + device_video_parameter.ux_device_class_video_parameter_streams = UX_NULL; + status = ux_device_stack_class_register(_ux_system_device_class_video_name, ux_device_class_video_entry, + 1, 0, &device_video_parameter); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + device_video_parameter.ux_device_class_video_parameter_streams = device_video_stream_parameter; + device_video_parameter.ux_device_class_video_parameter_streams_nb = 0; + status = ux_device_stack_class_register(_ux_system_device_class_video_name, ux_device_class_video_entry, + 1, 0, &device_video_parameter); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + device_video_parameter.ux_device_class_video_parameter_streams = device_video_stream_parameter; + device_video_parameter.ux_device_class_video_parameter_streams_nb = 2; + device_video_stream_parameter[0].ux_device_class_video_stream_parameter_max_payload_buffer_size = 0; + status = ux_device_stack_class_register(_ux_system_device_class_video_name, ux_device_class_video_entry, + 1, 0, &device_video_parameter); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + device_video_parameter.ux_device_class_video_parameter_streams = device_video_stream_parameter; + device_video_parameter.ux_device_class_video_parameter_streams_nb = 2; + device_video_stream_parameter[0].ux_device_class_video_stream_parameter_max_payload_buffer_size = UX_DEMO_ENDPOINT_SIZE; + device_video_stream_parameter[1].ux_device_class_video_stream_parameter_max_payload_buffer_nb = 0; + status = ux_device_stack_class_register(_ux_system_device_class_video_name, ux_device_class_video_entry, + 1, 0, &device_video_parameter); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +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; + + dummy_length = ux_device_class_video_max_payload_length(UX_NULL); + if (dummy_length != 0) + { + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + status = ux_device_class_video_reception_start(UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_device_class_video_read_payload_get(UX_NULL, dummy_payload, &payload_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_device_class_video_read_payload_get(&dummy_video_stream, UX_NULL, &payload_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_device_class_video_read_payload_get(&dummy_video_stream, dummy_payload, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_device_class_video_read_payload_free(UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_device_class_video_transmission_start(UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_device_class_video_write_payload_get(UX_NULL, dummy_payload, &payload_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_device_class_video_write_payload_get(&dummy_video_stream, UX_NULL, &payload_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_device_class_video_write_payload_get(&dummy_video_stream, dummy_payload, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_device_class_video_write_payload_commit(UX_NULL, 8); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_device_class_video_write_payload_commit(&dummy_video_stream, 0); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_device_class_video_ioctl(UX_NULL, 0, 0); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_uxe_host_audio_test.c b/test/regression/usbx_uxe_host_audio_test.c new file mode 100644 index 00000000..e3c0e2c2 --- /dev/null +++ b/test/regression/usbx_uxe_host_audio_test.c @@ -0,0 +1,245 @@ +/* This test is designed to test the ux_utility_descriptor_pack. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_host_class_audio.h" + +#include "ux_test.h" + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG error_counter = 0; + +/* Define USBX test global variables. */ + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_simulation_0; +static void ux_test_thread_simulation_0_entry(ULONG); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_uxe_host_audio_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +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! + printf("SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +static UINT _dummy_desc_parse_func(VOID *arg, + UCHAR *packed_interface_descriptor, + UCHAR *packed_endpoint_descriptor, + UCHAR *packed_audio_descriptor) +{ + return(0); +} + +static UINT _dummy_sampling_parse_func(VOID *arg, + UCHAR *packed_interface_descriptor, + UX_HOST_CLASS_AUDIO_SAMPLING_CHARACTERISTICS *sam_attr) +{ + return(0); +} + +static VOID _dummy_int_callback_func(UX_HOST_CLASS_AUDIO_AC *audio, + UCHAR *message, ULONG length, + VOID *arg) +{ +} + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ +UINT status; +UX_HOST_CLASS_AUDIO dummy_audio_inst; +UX_HOST_CLASS_AUDIO *dummy_audio = &dummy_audio_inst; +UX_HOST_CLASS_AUDIO_CONTROL dummy_audio_control; +UX_HOST_CLASS_AUDIO_TRANSFER_REQUEST dummy_audio_request; +UX_HOST_CLASS_AUDIO_SAMPLING_CHARACTERISTICS dummy_audio_sampling_prop; +UX_HOST_CLASS_AUDIO_SAMPLING dummy_audio_sampling; +UCHAR dummy_buffer[64]; + + + /* ux_host_class_audio_control_get() */ + status = ux_host_class_audio_control_get(UX_NULL, &dummy_audio_control); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_audio_control_get(dummy_audio, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_audio_control_value_get() */ + status = ux_host_class_audio_control_value_get(UX_NULL, &dummy_audio_control); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_audio_control_value_get(dummy_audio, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_audio_control_value_set() */ + status = ux_host_class_audio_control_value_set(UX_NULL, &dummy_audio_control); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_audio_control_value_set(dummy_audio, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_audio_read() */ + status = ux_host_class_audio_read(UX_NULL, &dummy_audio_request); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_audio_read(dummy_audio, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* _uxe_host_class_audio_streaming_sampling_get() */ + status = _uxe_host_class_audio_streaming_sampling_get(UX_NULL, &dummy_audio_sampling_prop); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = _uxe_host_class_audio_streaming_sampling_get(dummy_audio, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* _uxe_host_class_audio_streaming_sampling_set() */ + status = _uxe_host_class_audio_streaming_sampling_set(UX_NULL, &dummy_audio_sampling); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = _uxe_host_class_audio_streaming_sampling_set(dummy_audio, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* _uxe_host_class_audio_write() */ + status = _uxe_host_class_audio_write(UX_NULL, &dummy_audio_request); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = _uxe_host_class_audio_write(dummy_audio, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_audio_feedback_get() */ + status = ux_host_class_audio_feedback_get(UX_NULL, dummy_buffer); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_audio_feedback_get(dummy_audio, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_audio_feedback_set() */ + status = ux_host_class_audio_feedback_set(UX_NULL, dummy_buffer); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_audio_feedback_set(dummy_audio, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_audio_control_request() */ + status = ux_host_class_audio_control_request(UX_NULL, 0, 0, 0, 0, 0, UX_NULL, 0, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_audio_descriptors_parse() */ + status = ux_host_class_audio_descriptors_parse(UX_NULL, _dummy_desc_parse_func, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_audio_descriptors_parse(dummy_audio, UX_NULL, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_audio_entity_control_get() */ + status = ux_host_class_audio_entity_control_get(UX_NULL, &dummy_audio_control); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_audio_entity_control_get(dummy_audio, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_audio_entity_control_value_get() */ + status = ux_host_class_audio_entity_control_value_get(UX_NULL, &dummy_audio_control); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_audio_entity_control_value_get(dummy_audio, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_audio_entity_control_value_set() */ + status = ux_host_class_audio_entity_control_value_set(UX_NULL, &dummy_audio_control); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_audio_entity_control_value_set(dummy_audio, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_audio_raw_sampling_parse() */ + status = ux_host_class_audio_raw_sampling_parse(UX_NULL, _dummy_sampling_parse_func, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_audio_raw_sampling_parse(dummy_audio, UX_NULL, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_audio_raw_sampling_start() */ + status = ux_host_class_audio_raw_sampling_start(UX_NULL, &dummy_audio_sampling); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_audio_raw_sampling_start(dummy_audio, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_audio_stop() */ + status = ux_host_class_audio_stop(UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_audio_interrupt_start() */ + status = ux_host_class_audio_interrupt_start(UX_NULL, _dummy_int_callback_func, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_uxe_host_cdc_acm_test.c b/test/regression/usbx_uxe_host_cdc_acm_test.c new file mode 100644 index 00000000..ea07fa28 --- /dev/null +++ b/test/regression/usbx_uxe_host_cdc_acm_test.c @@ -0,0 +1,152 @@ +/* This test is designed to test the ux_utility_descriptor_pack. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_host_class_cdc_acm.h" + +#include "ux_test.h" + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG error_counter = 0; + +/* Define USBX test global variables. */ + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_simulation_0; +static void ux_test_thread_simulation_0_entry(ULONG); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_uxe_host_cdc_acm_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +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! + printf("SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ +UINT status; +UX_HOST_CLASS_CDC_ACM dummy_cdc_acm_inst; +UX_HOST_CLASS_CDC_ACM *dummy_cdc_acm = &dummy_cdc_acm_inst; +UX_HOST_CLASS_CDC_ACM_RECEPTION dummy_reception; +UCHAR dummy_buffer[64]; +ULONG dummy_ul; + + /* ux_host_class_cdc_acm_read() */ + status = ux_host_class_cdc_acm_read(UX_NULL, dummy_buffer, 8, &dummy_ul); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_cdc_acm_read(dummy_cdc_acm, UX_NULL, 8, &dummy_ul); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_cdc_acm_read(dummy_cdc_acm, dummy_buffer, 8, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_cdc_acm_write() */ + status = ux_host_class_cdc_acm_write(UX_NULL, dummy_buffer, 8, &dummy_ul); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_cdc_acm_write(dummy_cdc_acm, UX_NULL, 8, &dummy_ul); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_cdc_acm_write(dummy_cdc_acm, dummy_buffer, 8, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_cdc_acm_ioctl() */ + status = ux_host_class_cdc_acm_ioctl(UX_NULL, 0, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_cdc_acm_reception_start() */ + status = ux_host_class_cdc_acm_reception_start(UX_NULL, &dummy_reception); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_cdc_acm_reception_start(dummy_cdc_acm, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_cdc_acm_reception_stop() */ + status = ux_host_class_cdc_acm_reception_stop(UX_NULL, &dummy_reception); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_cdc_acm_reception_stop(dummy_cdc_acm, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_uxe_host_gser_test.c b/test/regression/usbx_uxe_host_gser_test.c new file mode 100644 index 00000000..7ecb8b8e --- /dev/null +++ b/test/regression/usbx_uxe_host_gser_test.c @@ -0,0 +1,152 @@ +/* This test is designed to test the ux_utility_descriptor_pack. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_host_class_gser.h" + +#include "ux_test.h" + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG error_counter = 0; + +/* Define USBX test global variables. */ + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_simulation_0; +static void ux_test_thread_simulation_0_entry(ULONG); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_uxe_host_gser_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +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! + printf("SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ +UINT status; +UX_HOST_CLASS_GSER dummy_gser_inst; +UX_HOST_CLASS_GSER *dummy_gser = &dummy_gser_inst; +UX_HOST_CLASS_GSER_RECEPTION dummy_reception; +UCHAR dummy_buffer[64]; +ULONG dummy_ul; + + /* ux_host_class_gser_read() */ + status = ux_host_class_gser_read(UX_NULL, 0, dummy_buffer, 8, &dummy_ul); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_gser_read(dummy_gser, 0, UX_NULL, 8, &dummy_ul); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_gser_read(dummy_gser, 0, dummy_buffer, 8, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_gser_write() */ + status = ux_host_class_gser_write(UX_NULL, 0, dummy_buffer, 8, &dummy_ul); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_gser_write(dummy_gser, 0, UX_NULL, 8, &dummy_ul); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_gser_write(dummy_gser, 0, dummy_buffer, 8, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_gser_ioctl() */ + status = ux_host_class_gser_ioctl(UX_NULL, 0, 0, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_gser_reception_start() */ + status = ux_host_class_gser_reception_start(UX_NULL, &dummy_reception); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_gser_reception_start(dummy_gser, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_gser_reception_stop() */ + status = ux_host_class_gser_reception_stop(UX_NULL, &dummy_reception); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_gser_reception_stop(dummy_gser, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_uxe_host_hid_test.c b/test/regression/usbx_uxe_host_hid_test.c new file mode 100644 index 00000000..e635a570 --- /dev/null +++ b/test/regression/usbx_uxe_host_hid_test.c @@ -0,0 +1,253 @@ +/* This test is designed to test the ux_utility_descriptor_pack. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_host_class_hid.h" +#include "ux_host_class_hid_keyboard.h" +#include "ux_host_class_hid_mouse.h" +#include "ux_host_class_hid_remote_control.h" + +#include "ux_test.h" + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + + +/* Define USBX test global variables. */ + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_uxe_device_hid_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +CHAR *memory_pointer; + + /* Inform user. */ + printf("Running uxe_device_hid APIs Test.................................... "); +#if !defined(UX_DEVICE_CLASS_HID_ENABLE_ERROR_CHECKING) ||\ + !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! + printf("SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ +UINT status; +UCHAR *dummy_name = "dummy"; +UX_HOST_CLASS_HID dummy_hid; +UX_HOST_CLASS_HID_KEYBOARD dummy_keyboard; +UX_HOST_CLASS_HID_MOUSE dummy_mouse; +UX_HOST_CLASS_HID_REMOTE_CONTROL dummy_remote_control; + +UX_HOST_CLASS_HID_REPORT_CALLBACK dummy_hid_report_callback; +UX_HOST_CLASS_HID_REPORT_GET_ID dummy_get_id; +UX_HOST_CLASS_HID_CLIENT_REPORT dummy_client_report; +USHORT dummy_word; +ULONG dummy_dw1, dummy_dw2; +SLONG dummy_sl1, dummy_sl2; + + + /* ux_host_class_hid_client_register() */ + status = ux_host_class_hid_client_register(UX_NULL, ux_host_class_hid_keyboard_entry); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_hid_client_register(dummy_name, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_hid_idle_get() */ + status = ux_host_class_hid_idle_get(UX_NULL, &dummy_word, 0); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_hid_idle_get(&dummy_hid, UX_NULL, 0); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_hid_idle_set() */ + status = ux_host_class_hid_idle_set(UX_NULL, 0, 0); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_hid_periodic_report_start() */ + status = ux_host_class_hid_periodic_report_start(UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_hid_periodic_report_stop() */ + status = ux_host_class_hid_periodic_report_stop(UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_hid_report_callback_register() */ + status = ux_host_class_hid_report_callback_register(UX_NULL, &dummy_hid_report_callback); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_hid_report_callback_register(&dummy_hid, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_hid_report_id_get() */ + status = ux_host_class_hid_report_id_get(UX_NULL, &dummy_get_id); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_hid_report_id_get(&dummy_hid, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_hid_report_get() */ + status = ux_host_class_hid_report_get(UX_NULL, &dummy_client_report); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_hid_report_get(&dummy_hid, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_hid_report_set() */ + status = ux_host_class_hid_report_set(UX_NULL, &dummy_client_report); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_hid_report_set(&dummy_hid, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + +#if 0//defined(UX_HOST_STANDALONE) + + /* ux_host_class_hid_idle_set_run() */ + status = ux_host_class_hid_idle_set_run(UX_NULL, 0, 0); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_hid_report_set_run() */ + status = ux_host_class_hid_report_set_run(UX_NULL, &dummy_client_report); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_hid_report_set_run(&dummy_hid, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); +#endif + + + /* ux_host_class_hid_keyboard_key_get() */ + status = ux_host_class_hid_keyboard_key_get(UX_NULL, &dummy_dw1, &dummy_dw2); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_hid_keyboard_key_get(&dummy_keyboard, UX_NULL, &dummy_dw2); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_hid_keyboard_key_get(&dummy_keyboard, &dummy_dw1, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_hid_keyboard_key_get(&dummy_keyboard, &dummy_dw1, &dummy_dw1); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_hid_keyboard_ioctl() */ + status = ux_host_class_hid_keyboard_ioctl(UX_NULL, 0, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + + /* ux_host_class_hid_mouse_buttons_get() */ + status = ux_host_class_hid_mouse_buttons_get(UX_NULL, &dummy_dw1); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_hid_mouse_buttons_get(&dummy_mouse, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* _uxe_host_class_hid_mouse_position_get() */ + status = _uxe_host_class_hid_mouse_position_get(UX_NULL, &dummy_sl1, &dummy_sl2); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = _uxe_host_class_hid_mouse_position_get(&dummy_mouse, UX_NULL, &dummy_sl2); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = _uxe_host_class_hid_mouse_position_get(&dummy_mouse, &dummy_sl1, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = _uxe_host_class_hid_mouse_position_get(&dummy_mouse, &dummy_sl1, &dummy_sl1); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_hid_mouse_wheel_get() */ + status = ux_host_class_hid_mouse_wheel_get(UX_NULL, &dummy_sl1); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_hid_mouse_wheel_get(&dummy_mouse, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + + /* ux_host_class_hid_remote_control_usage_get() */ + status = ux_host_class_hid_remote_control_usage_get(UX_NULL, &dummy_dw1, &dummy_dw2); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_hid_remote_control_usage_get(&dummy_remote_control, UX_NULL, &dummy_dw2); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_hid_remote_control_usage_get(&dummy_remote_control, &dummy_dw1, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_hid_remote_control_usage_get(&dummy_remote_control, &dummy_dw1, &dummy_dw1); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_uxe_host_pima_test.c b/test/regression/usbx_uxe_host_pima_test.c new file mode 100644 index 00000000..e8651008 --- /dev/null +++ b/test/regression/usbx_uxe_host_pima_test.c @@ -0,0 +1,317 @@ +/* This test is designed to test the ux_utility_descriptor_pack. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_host_class_pima.h" + +#include "ux_test.h" + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG error_counter = 0; + +/* Define USBX test global variables. */ + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_simulation_0; +static void ux_test_thread_simulation_0_entry(ULONG); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_uxe_host_pima_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +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! + printf("SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ +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; +UCHAR object_buffer[64]; +UX_HOST_CLASS_PIMA_OBJECT object; +ULONG object_actual_length; +ULONG storage_ids_array[32]; +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); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_device_info_get(dummy_pima, NX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + /* Unit test for function ux_host_class_pima_object_info_send() */ + status = ux_host_class_pima_object_info_send(NX_NULL, &pima_session, 0, 0, &object); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_object_info_send(dummy_pima, NX_NULL, 0, 0, &object); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_object_info_send(dummy_pima, &pima_session, 0, 0, NX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + /* Malloc fail test */ + pima_session.ux_host_class_pima_session_magic = UX_HOST_CLASS_PIMA_MAGIC_NUMBER; + pima_session.ux_host_class_pima_session_state = UX_HOST_CLASS_PIMA_SESSION_STATE_OPENED; + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start = UX_NULL; + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_start = UX_NULL; + status = ux_host_class_pima_object_info_send(dummy_pima, &pima_session, 0, 0, &object); + UX_TEST_CHECK_CODE(UX_MEMORY_INSUFFICIENT ,status); + + /* Unit test for function ux_host_class_pima_object_info_get() */ + status = ux_host_class_pima_object_info_get(NX_NULL, &pima_session, 0, &object); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_object_info_get(dummy_pima, NX_NULL, 0, &object); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_object_info_get(dummy_pima, &pima_session, 0, NX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + /* Malloc fail test */ + pima_session.ux_host_class_pima_session_magic = UX_HOST_CLASS_PIMA_MAGIC_NUMBER; + pima_session.ux_host_class_pima_session_state = UX_HOST_CLASS_PIMA_SESSION_STATE_OPENED; + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start = UX_NULL; + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_start = UX_NULL; + status = ux_host_class_pima_object_info_get(dummy_pima, &pima_session, 0, &object); + UX_TEST_CHECK_CODE(UX_MEMORY_INSUFFICIENT ,status); + + /* Unit test for function ux_host_class_pima_object_open() */ + status = ux_host_class_pima_object_open(NX_NULL, &pima_session, 0, &object); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_object_open(dummy_pima, NX_NULL, 0, &object); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_object_open(dummy_pima, &pima_session, 0, NX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + /* Unit test for function ux_host_class_pima_object_get() */ + status = ux_host_class_pima_object_get(NX_NULL, &pima_session, 0, &object, object_buffer, 64, &object_actual_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_object_get(dummy_pima, NX_NULL, 0, &object, object_buffer, 64, &object_actual_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_object_get(dummy_pima, &pima_session, 0, NX_NULL, object_buffer, 64, &object_actual_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_object_get(dummy_pima, &pima_session, 0, &object, NX_NULL, 64, &object_actual_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_object_get(dummy_pima, &pima_session, 0, &object, object_buffer, 64, NX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + /* Unit test for function ux_host_class_pima_object_get() */ + status = ux_host_class_pima_object_get(NX_NULL, &pima_session, 0, &object, object_buffer, 64, &object_actual_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_object_get(dummy_pima, NX_NULL, 0, &object, object_buffer, 64, &object_actual_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_object_get(dummy_pima, &pima_session, 0, NX_NULL, object_buffer, 64, &object_actual_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_object_get(dummy_pima, &pima_session, 0, &object, NX_NULL, 64, &object_actual_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_object_get(dummy_pima, &pima_session, 0, &object, object_buffer, 64, NX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + /* Unit test for function ux_host_class_pima_thumb_get() */ + status = ux_host_class_pima_thumb_get(NX_NULL, &pima_session, 0, &object, object_buffer, 64, &object_actual_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_thumb_get(dummy_pima, NX_NULL, 0, &object, object_buffer, 64, &object_actual_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_thumb_get(dummy_pima, &pima_session, 0, NX_NULL, object_buffer, 64, &object_actual_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_thumb_get(dummy_pima, &pima_session, 0, &object, NX_NULL, 64, &object_actual_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_thumb_get(dummy_pima, &pima_session, 0, &object, object_buffer, 64, NX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + /* Unit test for function ux_host_class_pima_object_send() */ + status = ux_host_class_pima_object_send(NX_NULL, &pima_session, &object, object_buffer, 64); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_object_send(dummy_pima, NX_NULL, &object, object_buffer, 64); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_object_send(dummy_pima, &pima_session, NX_NULL, object_buffer, 64); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_object_send(dummy_pima, &pima_session, &object, NX_NULL, 64); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + /* Unit test for function ux_host_class_pima_object_delete() */ + status = ux_host_class_pima_object_delete(NX_NULL, &pima_session, 0); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_object_delete(dummy_pima, NX_NULL, 0); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + /* Unit test for function ux_host_class_pima_object_transfer_abort() */ + status = ux_host_class_pima_object_transfer_abort(NX_NULL, &pima_session, 0, &object); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_object_transfer_abort(dummy_pima, NX_NULL, 0, &object); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_object_transfer_abort(dummy_pima, &pima_session, 0, NX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + /* Unit test for function ux_host_class_pima_object_close() */ + status = ux_host_class_pima_object_close(NX_NULL, &pima_session, 0, &object); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_object_close(dummy_pima, NX_NULL, 0, &object); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_object_close(dummy_pima, &pima_session, 0, NX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + /* Unit test for function ux_host_class_pima_session_open() */ + status = ux_host_class_pima_session_open(NX_NULL, &pima_session); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_session_open(dummy_pima, NX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + /* Unit test for function ux_host_class_pima_session_close() */ + status = ux_host_class_pima_session_close(NX_NULL, &pima_session); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_session_close(dummy_pima, NX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + /* Unit test for function ux_host_class_pima_storage_ids_get() */ + status = ux_host_class_pima_storage_ids_get(NX_NULL, &pima_session, storage_ids_array, 32); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_storage_ids_get(dummy_pima, NX_NULL, storage_ids_array, 32); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_storage_ids_get(dummy_pima, &pima_session, NX_NULL, 32); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + /* Unit test for function ux_host_class_pima_storage_info_get() */ + status = ux_host_class_pima_storage_info_get(NX_NULL, &pima_session, 0, &storage); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_storage_info_get(dummy_pima, NX_NULL, 0, &storage); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_storage_info_get(dummy_pima, &pima_session, 0, NX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + /* Unit test for function ux_host_class_pima_object_handles_get() */ + status = ux_host_class_pima_object_handles_get(NX_NULL, &pima_session, object_handles_array, 32, 0, 0, 0); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_object_handles_get(dummy_pima, NX_NULL, object_handles_array, 32, 0, 0, 0); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_object_handles_get(dummy_pima, &pima_session, NX_NULL, 32, 0, 0, 0); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_object_handles_get(dummy_pima, &pima_session, object_handles_array, 0, 0, 0, 0); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + /* Unit test for function ux_host_class_pima_num_objects_get() */ + status = ux_host_class_pima_num_objects_get(NX_NULL, &pima_session, 0, 0); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + status = ux_host_class_pima_num_objects_get(dummy_pima, NX_NULL, 0, 0); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER ,status); + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_uxe_host_printer_test.c b/test/regression/usbx_uxe_host_printer_test.c new file mode 100644 index 00000000..2374123f --- /dev/null +++ b/test/regression/usbx_uxe_host_printer_test.c @@ -0,0 +1,165 @@ +/* This test is designed to test the ux_utility_descriptor_pack. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_host_class_printer.h" + +#include "ux_test.h" + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG error_counter = 0; + +/* Define USBX test global variables. */ + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_simulation_0; +static void ux_test_thread_simulation_0_entry(ULONG); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_uxe_host_printer_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +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! + printf("SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ +UINT status; +UX_HOST_CLASS_PRINTER dummy_printer_inst; +UX_HOST_CLASS_PRINTER *dummy_printer = &dummy_printer_inst; +UCHAR dummy_buffer[64]; +ULONG actual_length; +ULONG printer_status; + + /* ux_host_class_printer_name_get() */ + status = ux_host_class_printer_name_get(UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_printer_device_id_get() */ + status = ux_host_class_printer_device_id_get(UX_NULL, dummy_buffer, 64); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_host_class_printer_device_id_get(dummy_printer, UX_NULL, 64); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_host_class_printer_device_id_get(dummy_printer, dummy_buffer, 0); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_printer_read() */ + status = ux_host_class_printer_read(UX_NULL, dummy_buffer, 64, &actual_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_host_class_printer_read(dummy_printer, UX_NULL, 64, &actual_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_host_class_printer_read(dummy_printer, dummy_buffer, 64, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_printer_soft_reset() */ + status = ux_host_class_printer_soft_reset(UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_printer_status_get() */ + status = ux_host_class_printer_status_get(UX_NULL, &printer_status); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_host_class_printer_status_get(dummy_printer, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_printer_write() */ + status = ux_host_class_printer_write(UX_NULL, dummy_buffer, 64, &actual_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_host_class_printer_write(dummy_printer, UX_NULL, 64, &actual_length); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + status = ux_host_class_printer_write(dummy_printer, dummy_buffer, 64, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_uxe_host_prolific_test.c b/test/regression/usbx_uxe_host_prolific_test.c new file mode 100644 index 00000000..ad55de3a --- /dev/null +++ b/test/regression/usbx_uxe_host_prolific_test.c @@ -0,0 +1,156 @@ +/* This test is designed to test the ux_utility_descriptor_pack. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_host_class_prolific.h" + +#include "ux_test.h" + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG error_counter = 0; + +/* Define USBX test global variables. */ + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_simulation_0; +static void ux_test_thread_simulation_0_entry(ULONG); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_uxe_host_prolific_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +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! + printf("SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ +UINT status; +UX_HOST_CLASS_PROLIFIC dummy_prolific_inst; +UX_HOST_CLASS_PROLIFIC *dummy_prolific = &dummy_prolific_inst; +UX_HOST_CLASS_PROLIFIC_RECEPTION dummy_reception; +UCHAR dummy_buffer[64]; +ULONG dummy_ul; + + /* ux_host_class_prolific_read() */ + status = ux_host_class_prolific_read(UX_NULL, dummy_buffer, 8, &dummy_ul); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_prolific_read(dummy_prolific, UX_NULL, 8, &dummy_ul); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_prolific_read(dummy_prolific, dummy_buffer, 8, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_prolific_write() */ + status = ux_host_class_prolific_write(UX_NULL, dummy_buffer, 8, &dummy_ul); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_prolific_write(dummy_prolific, UX_NULL, 8, &dummy_ul); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_prolific_write(dummy_prolific, dummy_buffer, 8, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_prolific_ioctl() */ + status = ux_host_class_prolific_ioctl(UX_NULL, 0, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_prolific_command() */ + status = ux_host_class_prolific_command(UX_NULL, 0, 0, UX_NULL, 0); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_prolific_reception_start() */ + status = ux_host_class_prolific_reception_start(UX_NULL, &dummy_reception); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_prolific_reception_start(dummy_prolific, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_prolific_reception_stop() */ + status = ux_host_class_prolific_reception_stop(UX_NULL, &dummy_reception); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_prolific_reception_stop(dummy_prolific, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_uxe_host_stack_test.c b/test/regression/usbx_uxe_host_stack_test.c new file mode 100644 index 00000000..1476ba60 --- /dev/null +++ b/test/regression/usbx_uxe_host_stack_test.c @@ -0,0 +1,249 @@ +/* This test is designed to test the ux_utility_descriptor_pack. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_device_class_dummy.h" +#include "ux_host_class_dummy.h" +#include "ux_test_hcd_sim_host.h" + +#include "ux_test.h" + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + + +/* Define USBX test global variables. */ + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_uxe_system_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +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! + printf("SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_memory; + memory_pointer = stack_pointer + (UX_TEST_STACK_SIZE * 2); +#if 1 + /* Initialize USBX Memory. */ + status = ux_system_initialize(memory_pointer, UX_TEST_MEMORY_SIZE, UX_NULL, 0); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#endif + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ +UINT status; +UCHAR *buffer = (UCHAR *)&status; +UX_HOST_CLASS dummy_class; +UX_HOST_CLASS *dummy_class_ptr = &dummy_class; +UX_DEVICE dummy_device; +UX_DEVICE *dummy_device_ptr = &dummy_device; +UX_CONFIGURATION dummy_configuration; +UX_CONFIGURATION *dummy_configuration_ptr = &dummy_configuration; +UX_INTERFACE dummy_interface; +UX_INTERFACE *dummy_interface_ptr = &dummy_interface; +UX_ENDPOINT dummy_endpoint; +UX_ENDPOINT *dummy_endpoint_ptr = &dummy_endpoint; +UX_TRANSFER dummy_transfer; + + /* ux_host_stack_class_get() */ + status = ux_host_stack_class_get(UX_NULL, &dummy_class_ptr); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_stack_class_get("dummy", UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_stack_class_instance_get() */ + status = ux_host_stack_class_instance_get(UX_NULL, 0, (VOID**)buffer); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_stack_class_instance_get(&dummy_class, 0, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_stack_class_register() */ + status = ux_host_stack_class_register(UX_NULL, _ux_host_class_dummy_entry); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_stack_class_register("dummy", UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_stack_configuration_interface_get() */ + status = ux_host_stack_configuration_interface_get(UX_NULL, 0, 0, &dummy_interface_ptr); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_stack_configuration_interface_get(&dummy_configuration, 0, 0, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_stack_device_configuration_activate() */ + status = ux_host_stack_device_configuration_activate(UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_stack_device_configuration_deactivate() */ + status = ux_host_stack_device_configuration_deactivate(UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_stack_device_configuration_get() */ + status = ux_host_stack_device_configuration_get(UX_NULL, 0, &dummy_configuration_ptr); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_stack_device_configuration_get(&dummy_device, 0, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_stack_device_get() */ + status = ux_host_stack_device_get(0, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_stack_device_string_get() */ + status = ux_host_stack_device_string_get(UX_NULL, buffer, 64, 0x1234, 1); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_stack_device_string_get(&dummy_device, UX_NULL, 64, 0x1234, 1); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_stack_device_string_get(&dummy_device, buffer, 0, 0x1234, 1); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_stack_endpoint_transfer_abort() */ + status = ux_host_stack_endpoint_transfer_abort(UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_stack_hcd_register() */ + status = ux_host_stack_hcd_register(UX_NULL, _ux_test_hcd_sim_host_initialize, 0, 0); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_stack_hcd_register("dummy", UX_NULL, 0, 0); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_stack_hcd_unregister() */ + status = ux_host_stack_hcd_unregister(UX_NULL, 0, 0); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_stack_interface_endpoint_get() */ + status = ux_host_stack_interface_endpoint_get(UX_NULL, 0, &dummy_endpoint_ptr); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_stack_interface_endpoint_get(&dummy_interface, 0, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_stack_interface_setting_select() */ + status = ux_host_stack_interface_setting_select(UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_stack_transfer_request() */ + status = ux_host_stack_transfer_request(UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + dummy_transfer.ux_transfer_request_endpoint = UX_NULL; + status = ux_host_stack_transfer_request(&dummy_transfer); + UX_TEST_CHECK_CODE(UX_ENDPOINT_HANDLE_UNKNOWN, status); + dummy_transfer.ux_transfer_request_endpoint = &dummy_endpoint; + dummy_endpoint.ux_endpoint_device = UX_NULL; + status = ux_host_stack_transfer_request(&dummy_transfer); + UX_TEST_CHECK_CODE(UX_DEVICE_HANDLE_UNKNOWN, status); +#if UX_MAX_HCD > 1 + dummy_endpoint.ux_endpoint_device = &dummy_device; + dummy_device.ux_device_hcd = UX_NULL; + status = ux_host_stack_transfer_request(&dummy_transfer); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); +#endif + +#if defined(UX_HOST_STANDALONE) + + /* ux_host_stack_transfer_run() */ + status = ux_host_stack_transfer_run(UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + dummy_transfer.ux_transfer_request_endpoint = UX_NULL; + status = ux_host_stack_transfer_run(&dummy_transfer); + UX_TEST_CHECK_CODE(UX_ENDPOINT_HANDLE_UNKNOWN, status); + dummy_transfer.ux_transfer_request_endpoint = &dummy_endpoint; + dummy_endpoint.ux_endpoint_device = UX_NULL; + status = ux_host_stack_transfer_run(&dummy_transfer); + UX_TEST_CHECK_CODE(UX_DEVICE_HANDLE_UNKNOWN, status); +#if UX_MAX_HCD > 1 + dummy_endpoint.ux_endpoint_device = &dummy_device; + dummy_device.ux_device_hcd = UX_NULL; + status = ux_host_stack_transfer_run(&dummy_transfer); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); +#endif + +#endif + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_uxe_host_storage_test.c b/test/regression/usbx_uxe_host_storage_test.c new file mode 100644 index 00000000..0d66a823 --- /dev/null +++ b/test/regression/usbx_uxe_host_storage_test.c @@ -0,0 +1,177 @@ +/* This test is designed to test the ux_utility_descriptor_pack. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_host_class_storage.h" + +#include "ux_test.h" + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG error_counter = 0; + +/* Define USBX test global variables. */ + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_simulation_0; +static void ux_test_thread_simulation_0_entry(ULONG); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_uxe_host_storage_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +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! + printf("SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ +UINT status; +UX_HOST_CLASS_STORAGE dummy_storage; +UX_HOST_CLASS_STORAGE *dummy_storage_ptr = UX_NULL; +UX_HOST_CLASS_STORAGE_MEDIA dummy_storage_media; +UX_HOST_CLASS_STORAGE_MEDIA *dummy_storage_media_ptr = UX_NULL; +UCHAR dummy_buffer[512]; + + /* ux_host_class_storage_lock() */ + status = ux_host_class_storage_lock(dummy_storage_ptr, UX_WAIT_FOREVER); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + ux_host_class_storage_lock(dummy_storage_ptr, UX_WAIT_FOREVER); + +#if defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + + /* ux_host_class_storage_unlock() */ + ux_host_class_storage_unlock(dummy_storage_ptr); + + /* ux_host_class_storage_lun_select() */ + ux_host_class_storage_lun_select(dummy_storage_ptr, 0); + + /* ux_host_class_storage_media_read() */ + status = ux_host_class_storage_media_read(UX_NULL, 1, 1, dummy_buffer); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_storage_media_read(&dummy_storage, 1, 1, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_storage_media_write() */ + status = ux_host_class_storage_media_write(UX_NULL, 1, 1, dummy_buffer); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_storage_media_get() */ + status = ux_host_class_storage_media_get(UX_NULL, 0, &dummy_storage_media_ptr); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_storage_media_get(&dummy_storage, 0, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + dummy_storage_media_ptr = UX_NULL; + + /* ux_host_class_storage_media_lock() */ + status = ux_host_class_storage_media_lock(dummy_storage_media_ptr, UX_WAIT_FOREVER); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_storage_media_unlock() */ + ux_host_class_storage_media_unlock(dummy_storage_media_ptr); + +#if defined(uX_HOST_STANDALONE) + /* ux_host_class_storage_media_check() */ + status = ux_host_class_storage_media_check(UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); +#endif + +#else + + /* ux_host_class_storage_unlock() */ + status = ux_host_class_storage_unlock(dummy_storage_ptr); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + ux_host_class_storage_unlock(dummy_storage_ptr); + + /* ux_host_class_storage_lun_select() */ + ux_host_class_storage_lun_select(dummy_storage_ptr, 0); + +#endif + + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_uxe_host_swar_test.c b/test/regression/usbx_uxe_host_swar_test.c new file mode 100644 index 00000000..33fc3b38 --- /dev/null +++ b/test/regression/usbx_uxe_host_swar_test.c @@ -0,0 +1,152 @@ +/* This test is designed to test the ux_utility_descriptor_pack. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_host_class_swar.h" + +#include "ux_test.h" + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG error_counter = 0; + +/* Define USBX test global variables. */ + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_simulation_0; +static void ux_test_thread_simulation_0_entry(ULONG); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_uxe_host_swar_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +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! + printf("SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ +UINT status; +UX_HOST_CLASS_SWAR dummy_swar_inst; +UX_HOST_CLASS_SWAR *dummy_swar = &dummy_swar_inst; +UX_HOST_CLASS_SWAR_RECEPTION dummy_reception; +UCHAR dummy_buffer[64]; +ULONG dummy_ul; + + /* ux_host_class_swar_read() */ + status = ux_host_class_swar_read(UX_NULL, dummy_buffer, 8, &dummy_ul); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_swar_read(dummy_swar, UX_NULL, 8, &dummy_ul); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_swar_read(dummy_swar, dummy_buffer, 8, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_swar_write() */ + status = ux_host_class_swar_write(UX_NULL, dummy_buffer, 8, &dummy_ul); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_swar_write(dummy_swar, UX_NULL, 8, &dummy_ul); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_swar_write(dummy_swar, dummy_buffer, 8, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_swar_ioctl() */ + status = ux_host_class_swar_ioctl(UX_NULL, 0, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_swar_reception_start() */ + status = ux_host_class_swar_reception_start(UX_NULL, &dummy_reception); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_swar_reception_start(dummy_swar, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_swar_reception_stop() */ + status = ux_host_class_swar_reception_stop(UX_NULL, &dummy_reception); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_swar_reception_stop(dummy_swar, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_uxe_host_video_test.c b/test/regression/usbx_uxe_host_video_test.c new file mode 100644 index 00000000..c7a6585a --- /dev/null +++ b/test/regression/usbx_uxe_host_video_test.c @@ -0,0 +1,188 @@ +/* This test is designed to test the ux_utility_descriptor_pack. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + +#include "ux_host_class_video.h" + +#include "ux_test.h" + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG error_counter = 0; + +/* Define USBX test global variables. */ + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_simulation_0; +static void ux_test_thread_simulation_0_entry(ULONG); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_uxe_host_video_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +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! + printf("SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_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); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } + + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ +UINT status; +UX_HOST_CLASS_VIDEO dummy_video_inst; +UX_HOST_CLASS_VIDEO *dummy_video = &dummy_video_inst; +UCHAR dummy_buffer[64]; +UX_HOST_CLASS_VIDEO_CONTROL dummy_video_control; +UX_HOST_CLASS_VIDEO_TRANSFER_REQUEST dummy_video_request; +ULONG max_payload = 0xff; + + /* ux_host_class_video_control_get() */ + status = ux_host_class_video_control_get(UX_NULL, &dummy_video_control); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_video_control_get(dummy_video, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_video_control_value_get() */ + status = ux_host_class_video_control_value_get(UX_NULL, &dummy_video_control); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_video_control_value_get(dummy_video, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_video_control_value_set() */ + status = ux_host_class_video_control_value_set(UX_NULL, &dummy_video_control); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_video_control_value_set(dummy_video, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_video_read() */ + status = ux_host_class_video_read(UX_NULL, &dummy_video_request); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_video_read(dummy_video, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_video_ioctl() */ + status = ux_host_class_video_ioctl(UX_NULL, 0, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_video_start() */ + status = ux_host_class_video_start(UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_video_stop() */ + status = ux_host_class_video_stop(UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_video_frame_parameters_set() */ + status = ux_host_class_video_frame_parameters_set(UX_NULL, 0, 255, 255, 100); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_video_max_payload_get() */ + max_payload = ux_host_class_video_max_payload_get(UX_NULL); + UX_TEST_CHECK_CODE(0, max_payload); + + /* ux_host_class_video_transfer_buffer_add() */ + status = ux_host_class_video_transfer_buffer_add(UX_NULL, dummy_buffer); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_host_class_video_transfer_buffer_add(dummy_video, UX_NULL); + 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); + 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); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_video_transfer_callback_set() */ + ux_host_class_video_transfer_callback_set(UX_NULL, UX_NULL); + + /* ux_host_class_video_entities_parse() */ + status = ux_host_class_video_entities_parse(UX_NULL, 0, UX_NULL); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* ux_host_class_video_control_request() */ + status = ux_host_class_video_control_request(UX_NULL, 1, 1, 1, 1, UX_NULL, 2); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbx_uxe_system_test.c b/test/regression/usbx_uxe_system_test.c new file mode 100644 index 00000000..910038d3 --- /dev/null +++ b/test/regression/usbx_uxe_system_test.c @@ -0,0 +1,129 @@ +/* This test is designed to test the ux_utility_descriptor_pack. */ + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_host_stack.h" +#include "ux_device_stack.h" + + +#include "ux_test.h" + +/* Define USBX test constants. */ + +#define UX_TEST_STACK_SIZE 4096 +#define UX_TEST_BUFFER_SIZE 2048 +#define UX_TEST_MEMORY_SIZE (64*1024) + + +/* Define the counters used in the test application... */ + +static ULONG thread_0_counter; +static ULONG thread_1_counter; +static ULONG error_counter; + +static UCHAR error_callback_ignore = UX_FALSE; +static ULONG error_callback_counter; + + +/* Define USBX test global variables. */ + + +/* Define prototypes for external Host Controller's (HCDs), classes and clients. */ + +static TX_THREAD ux_test_thread_simulation_0; +static TX_THREAD ux_test_thread_simulation_1; +static void ux_test_thread_simulation_0_entry(ULONG); +static void ux_test_thread_simulation_1_entry(ULONG); + + +/* Prototype for test control return. */ + +void test_control_return(UINT status); + + +/* Define what the initial system looks like. */ + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void usbx_uxe_system_test_application_define(void *first_unused_memory) +#endif +{ + +UINT status; +CHAR *stack_pointer; +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! + printf("SKIP SUCCESS!\n"); + test_control_return(0); + return; +#endif + + /* Initialize the free memory pointer. */ + stack_pointer = (CHAR *) first_unused_memory; + memory_pointer = stack_pointer + (UX_TEST_STACK_SIZE * 2); +#if 0 + /* Initialize USBX Memory. */ + status = ux_system_initialize(memory_pointer, UX_TEST_MEMORY_SIZE, UX_NULL, 0); + + /* Check for error. */ + if (status != UX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +#endif + /* Create the simulation thread. */ + status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, + stack_pointer, UX_TEST_STACK_SIZE, + 20, 20, 1, TX_AUTO_START); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + printf("ERROR #%d\n", __LINE__); + test_control_return(1); + } +} + + +static void ux_test_thread_simulation_0_entry(ULONG arg) +{ +UINT status; +UCHAR *buffer = (UCHAR *)&status; + + /* ux_system_initialize() */ + status = ux_system_initialize(UX_NULL, UX_TEST_MEMORY_SIZE, UX_NULL, 0); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + status = ux_system_initialize(buffer, 0, UX_NULL, 0); + UX_TEST_CHECK_CODE(UX_INVALID_PARAMETER, status); + + /* Sleep for a tick to make sure everything is complete. */ + tx_thread_sleep(1); + + /* Check for errors from other threads. */ + if (error_counter) + { + + /* Test error. */ + printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); + test_control_return(1); + } + else + { + + /* Successful test. */ + printf("SUCCESS!\n"); + test_control_return(0); + } +} diff --git a/test/regression/usbxtestcontrol.c b/test/regression/usbxtestcontrol.c new file mode 100644 index 00000000..5ffc6871 --- /dev/null +++ b/test/regression/usbxtestcontrol.c @@ -0,0 +1,1312 @@ +/* This is the test control routine of the USBX kernel. All tests are dispatched from this routine. */ + +#include "tx_api.h" +#include "fx_api.h" +#include "nx_api.h" +#include "ux_api.h" +#include + +#include "ux_test.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_utility_sim.h" + +#define TEST_STACK_SIZE 6144 + +/* Define the test control USBX objects... */ + +TX_THREAD test_control_thread; +TX_THREAD test_thread; + + +/* Define the test control global variables. */ + +ULONG test_control_return_status; +ULONG test_control_successful_tests; +ULONG test_control_failed_tests; +ULONG test_control_system_errors; + + + +/* Remember the start of free memory. */ + +UCHAR *test_free_memory_ptr; + + +/* Define the function pointer for ISR dispatch. */ + +VOID (*test_isr_dispatch)(void); + + +UCHAR test_control_thread_stack[TEST_STACK_SIZE]; +UCHAR tests_memory[1024*1024*1024]; + +/* Define the external reference for the preempt disable flag. */ + +extern volatile UINT _tx_thread_preempt_disable; +extern volatile ULONG _tx_thread_system_state; + + +/* Define test entry pointer type. */ + +typedef struct TEST_ENTRY_STRUCT +{ + +VOID (*test_entry)(void *); +} TEST_ENTRY; + +/* Demos */ + +void usbx_hid_keyboard_key_press_release_demo_application_define(void *); + +/* Define the prototypes for the test entry points. */ + +void usbx_dpump_basic_test_application_define(void *); + +/* Utility */ + +void usbx_ux_utility_descriptor_pack_test_application_define(void *); +void usbx_ux_utility_descriptor_parse_test_application_define(void *); +void usbx_ux_utility_event_flags_test_application_define(void *); +void usbx_ux_utility_memory_safe_test_application_define(void *); +void usbx_ux_utility_memory_test_application_define(void *); +void usbx_ux_utility_mutex_test_application_define(void *); +void usbx_ux_utility_pci_write_test_application_define(void *); +void usbx_ux_utility_pci_read_test_application_define(void *); +void usbx_ux_utility_pci_class_scan_test_application_define(void *); +void usbx_ux_utility_physical_address_test_application_define(void *); +void usbx_ux_utility_semaphore_test_application_define(void *); +void usbx_ux_utility_string_length_check_test_application_define(void *); +void usbx_ux_utility_thread_create_test_application_define(void *); +void usbx_ux_utility_thread_schedule_other_test_application_define(void *); +void usbx_ux_utility_thread_suspend_test_application_define(void *); +void usbx_ux_utility_thread_identify_test_application_define(void *); +void usbx_ux_utility_timer_test_application_define(void *); +void usbx_ux_utility_unicode_to_string_test_application_define(void *); + +/* General/stack */ +void usbx_host_stack_new_endpoint_create_overage_test_application_define(void*); +void usbx_host_stack_class_unregister_coverage_test_application_define(void *); +void usbx_host_device_basic_test_application_define(void *); +void usbx_host_device_basic_memory_test_application_define(void *); +void usbx_host_device_initialize_test_application_define(void *); + +void usbx_device_stack_standard_request_test_application_define(void *); +void usbx_ux_device_stack_class_register_test_application_define(void *); +void usbx_ux_device_stack_class_unregister_test_application_define(void *); +void usbx_ux_device_stack_clear_feature_coverage_test_application_define(void *); +void usbx_ux_host_stack_uninitialize_test_application_define(void *); +void usbx_ux_host_stack_hcd_unregister_test_application_define(void *); +void usbx_ux_host_stack_class_unregister_test_application_define(void *); + +/* CDC */ + +void usbx_cdc_acm_basic_test_original_application_define(void *); +void usbx_cdc_acm_basic_test_application_define(void *); +void usbx_cdc_acm_basic_memory_test_application_define(void *); +void usbx_cdc_acm_configure_test_application_define(void *); +void usbx_ux_device_class_cdc_acm_activate_test_application_define(void *); +void usbx_cdc_acm_device_dtr_rts_reset_on_disconnect_test_application_define(void *); +void usbx_ux_device_class_cdc_acm_deactivate_test_application_define(void *); +void usbx_ux_device_class_cdc_acm_ioctl_test_application_define(void *); +void usbx_ux_device_class_cdc_acm_transmission_test_application_define(void *); +void usbx_ux_device_class_cdc_acm_write_test_application_define(void *); +void usbx_ux_device_class_cdc_acm_timeout_test_application_define(void *); +void usbx_ux_host_class_cdc_acm_activate_test_application_define(void *); +void usbx_ux_host_class_cdc_acm_capabilities_get_test_application_define(void *); +void usbx_ux_host_class_cdc_acm_deactivate_test_application_define(void *); +void usbx_ux_host_class_cdc_acm_endpoints_get_test_application_define(void *); +void usbx_ux_host_class_cdc_acm_entry_test_application_define(void *); +void usbx_ux_host_class_cdc_acm_read_test_application_define(void *); +void usbx_ux_host_class_cdc_acm_transfer_request_completed_test_application_define(void *); +void usbx_ux_device_class_cdc_acm_bulkout_thread_test_application_define(void *); +void usbx_uxe_device_cdc_acm_test_application_define(void *); + +/* HID */ + +void usbx_ux_device_class_hid_basic_memory_test_application_define(void *); +void usbx_hid_keyboard_basic_test_application_define(void *); +void usbx_ux_host_class_hid_report_get_test_application_define(void *); +void usbx_hid_report_descriptor_global_item_test_application_define(void *); +void usbx_hid_report_descriptor_item_size_test_application_define(void *); +void usbx_hid_report_descriptor_usages_single_test_application_define(void *); +void usbx_hid_report_descriptor_usages_min_max_test_application_define(void *); +void usbx_hid_report_descriptor_multiple_fields_test_application_define(void *); +void usbx_hid_report_descriptor_single_usage_multiple_data_test_application_define(void *); +void usbx_hid_report_descriptor_multiple_reports_input_test_application_define(void *); +void usbx_hid_report_descriptor_multiple_reports_output_test_application_define(void *); +void usbx_hid_report_descriptor_multiple_reports_feature_test_application_define(void *); +void usbx_hid_report_descriptor_multiple_fields_and_reports_test(void *); +void usbx_hid_report_descriptor_previous_report_test_application_define(void *); +void usbx_hid_report_descriptor_push_pop_test_application_define(void *); +void usbx_hid_report_descriptor_decompress_test_application_define(void *); +void usbx_hid_report_descriptor_decompress_array_test_application_define(void *); +void usbx_hid_report_descriptor_delimiter_test_application_define(void *); +void usbx_hid_report_descriptor_global_item_persist_test_application_define(void *); +void usbx_hid_report_descriptor_extended_usage_test_application_define(void *); +void usbx_hid_report_descriptor_multiple_collections_test_application_define(void *); +void usbx_hid_report_descriptor_usages_overflow_test_application_define(void *); +void usbx_hid_report_descriptor_usages_overflow_via_max_test_application_define(void *); +void usbx_hid_report_descriptor_collection_overflow_test_application_define(void *); +void usbx_hid_report_descriptor_end_collection_error_test_application_define(void *); +void usbx_hid_report_descriptor_example_andisplay_test_application_define(void *); +void usbx_hid_report_descriptor_example_delimit_test_application_define(void *); +void usbx_hid_report_descriptor_example_digit_test_application_define(void *); +void usbx_hid_report_descriptor_example_display_test_application_define(void *); +void usbx_hid_report_descriptor_example_joystk_test_application_define(void *); +void usbx_hid_report_descriptor_example_keybrd_test_application_define(void *); +void usbx_hid_report_descriptor_example_monitor_test_application_define(void *); +void usbx_hid_report_descriptor_example_mouse_test_application_define(void *); +void usbx_hid_report_descriptor_example_pwr_test_application_define(void *); +void usbx_hid_report_descriptor_example_remote_test_application_define(void *); +void usbx_hid_report_descriptor_example_tele_test_application_define(void *); +void usbx_hid_report_descriptor_get_zero_length_item_data_test_application_define(void *); +void usbx_hid_report_descriptor_invalid_length_test_application_define(void *); +void usbx_hid_report_descriptor_invalid_item_test_application_define(void *); +void usbx_hid_report_descriptor_delimiter_nested_open_test_application_define(void *); +void usbx_hid_report_descriptor_delimiter_nested_close_test_application_define(void *); +void usbx_hid_report_descriptor_delimiter_unknown_test_application_define(void *); +void usbx_hid_report_descriptor_unknown_local_tag_test_application_define(void *); +void usbx_hid_report_descriptor_unknown_global_tag_test_application_define(void *); +void usbx_hid_report_descriptor_incoherent_usage_min_max_test_application_define(void *); +void usbx_hid_report_descriptor_report_size_overflow_test_application_define(void *); +void usbx_hid_report_descriptor_report_count_overflow_test_application_define(void *); +void usbx_hid_report_descriptor_push_overflow_tag_test_application_define(void *); +void usbx_hid_report_descriptor_pop_underflow_tag_test_application_define(void *); +void usbx_hid_keyboard_extraction_test_application_define(void *); +void usbx_hid_keyboard_extraction_test2_application_define(void *); +void usbx_hid_keyboard_callback_test_application_define(void *); +void usbx_hid_mouse_basic_test_application_define(void *); +void usbx_hid_mouse_extraction_test_application_define(void *); +void usbx_hid_mouse_extraction_test2_application_define(void *); +void usbx_hid_remote_control_tests_application_define(void *); +void usbx_ux_host_class_hid_remote_control_entry_test2_application_define(void *); +void usbx_ux_host_class_hid_remote_control_activate_test_application_define(void *); +void usbx_hid_remote_control_extraction_test_application_define(void *); +void usbx_hid_remote_control_extraction_test2_application_define(void *); +void usbx_hid_report_descriptor_compress_test_application_define(void *); +void usbx_hid_report_descriptor_compress_and_decompress_test_application_define(void *); +void usbx_hid_transfer_request_completed_test_application_define(void *); +void usbx_hid_transfer_request_completed_raw_test_application_define(void *); +void usbx_hid_transfer_request_completed_decompressed_test_application_define(void *); +void usbx_ux_host_class_hid_client_register_test_application_define(void *); +void usbx_ux_host_class_hid_report_set_test_application_define(void *); +void usbx_hid_keyboard_key_get_test_application_define(void *); +void usbx_ux_host_class_hid_client_search_test_application_define(void *); +void usbx_ux_device_class_hid_control_request_test_application_define(void *); +void usbx_ux_device_class_hid_report_set_test_application_define(void *); +void usbx_ux_device_class_hid_interrupt_thread_test_application_define(void *); +void usbx_hid_keyboard_key_test_application_define(void *); +void usbx_hid_keyboard_key_with_report_id_test_application_define(void *); +void usbx_ux_device_class_hid_descriptor_send_test_application_define(void *); +void usbx_control_transfer_stall_test(void *); +void usbx_hid_interrupt_endpoint_get_report_test_application_define(void *); +void usbx_ux_device_class_hid_event_get_AND_set_test_application_define(void *); +void usbx_ux_host_class_hid_report_add_test_application_define(void *); +void usbx_ux_host_class_hid_idle_set_test_application_define(void *); +void usbx_ux_host_class_hid_interrupt_endpoint_search_test_application_define(void *); +void usbx_ux_host_class_hid_keyboard_activate_test_application_define(void *); +void usbx_ux_host_class_hid_report_id_get_test_application_define(void *); +void usbx_ux_host_class_hid_periodic_report_start_test_application_define(void *); +void usbx_ux_host_class_hid_descriptor_parse_coverage_test_application_define(void *); +void usbx_ux_host_class_hid_descriptor_parse_test_application_define(void *); +void usbx_ux_host_class_hid_descriptor_parse_test2_application_define(void *); +void usbx_ux_host_class_hid_mouse_activate_test_application_define(void *); +void usbx_ux_host_class_hid_activate_test_application_define(void *); +void usbx_ux_host_class_hid_report_callback_register_test_application_define(void *); +void usbx_ux_host_class_hid_entry_test_application_define(void *); +void usbx_ux_host_class_hid_periodic_report_stop_test_application_define(void *); +void usbx_ux_host_class_hid_keyboard_entry_test_application_define(void *); +void usbx_ux_host_class_hid_keyboard_ioctl_test_application_define(void *); +void usbx_ux_host_class_hid_mouse_entry_test_application_define(void *); +void usbx_ux_host_class_hid_mouse_positions_get_test_application_define(void *); +void usbx_ux_host_class_hid_mouse_buttons_get_test_application_define(void *); +void usbx_ux_host_class_hid_mouse_wheel_get_test_application_define(void *); +void usbx_ux_host_class_hid_remote_control_entry_test_application_define(void *); +void usbx_ux_host_class_hid_remote_control_usage_get_test_application_define(void *); +void usbx_ux_host_class_hid_configure_test_application_define(void *); +void usbx_ux_device_class_hid_entry_test_application_define(void *); +void usbx_ux_device_class_hid_deactivate_test_application_define(void *); +void usbx_ux_device_class_hid_activate_test_application_define(void *); +void usbx_ux_host_class_hid_keyboard_thread_test_application_define(void *); +void usbx_ux_host_class_hid_keyboard_thread_test2_application_define(void *); +void usbx_ux_host_class_hid_deactivate_test_application_define(void *); +void usbx_ux_host_class_hid_deactivate_test2_application_define(void *); +void usbx_ux_host_class_hid_descriptor_parse_test3_application_define(void *); +void usbx_ux_host_class_hid_descriptor_parse_test4_application_define(void *); +void usbx_ux_host_class_hid_descriptor_parse_test5_application_define(void *); +void usbx_ux_host_class_hid_descriptor_parse_test6_application_define(void *); +void usbx_ux_host_class_hid_descriptor_parse_test7_application_define(void *); +void usbx_ux_host_class_hid_report_descriptor_get_test_application_define(void *); +void usbx_ux_host_class_hid_remote_control_callback_test_application_define(void *); +void usbx_ux_host_class_hid_interrupt_endpoint_search_test2_application_define(void *); +void usbx_ux_host_class_hid_periodic_report_start_test2_application_define(void *); +void usbx_ux_host_class_hid_report_get_test2_application_define(void *); +void usbx_ux_host_class_hid_main_item_parse_test_application_define(void *); +void usbx_ux_host_class_hid_main_item_parse_test2_application_define(void *); +void usbx_ux_host_class_hid_mouse_entry_test3_application_define(void *); +void usbx_ux_host_class_hid_mouse_entry_test2_application_define(void *); +void usbx_ux_host_class_hid_remote_control_entry_test3_application_define(void *); +void usbx_ux_host_class_hid_transfer_request_completed_test_application_define(void *); +void usbx_ux_host_class_hid_keyboard_callback_test2_application_define(void *); +void usbx_ux_host_class_hid_idle_get_test_application_define(void *); +void usbx_ux_host_class_hid_remote_control_activate_test2_application_define(void *); +void usbx_ux_host_class_hid_client_register_test2_application_define(void *); +void usbx_ux_host_class_hid_report_descriptor_get_test_application_define(void *); +void usbx_ux_host_class_hid_report_descriptor_get_test2_application_define(void *); +void usbx_ux_host_class_hid_report_descriptor_get_test3_application_define(void *); +void usbx_ux_host_class_hid_report_descriptor_get_test4_application_define(void *); +void usbx_ux_host_class_hid_deactivate_test3_application_define(void *); +void usbx_ux_host_class_hid_local_item_parse_test_application_define(void *); +void usbx_ux_device_class_hid_uninitialize_test_application_define(void *); +void usbx_ux_device_class_hid_initialize_test_application_define(void *); +void usbx_ux_device_class_hid_report_set_test2_application_define(void *); +void usbx_ux_device_class_hid_activate_test2_application_define(void *); +void usbx_ux_device_class_hid_activate_test3_application_define(void *); +void usbx_ux_device_class_hid_interrupt_thread_test2_application_define(void *); +void usbx_ux_device_class_hid_report_test_application_define(void *); +void usbx_hid_report_descriptor_compress_array_test_application_define(void *); +void usbx_ux_device_class_hid_idle_rate_test_application_define(void *); + + +/* Storage */ +void usbx_host_class_storage_entry_overage_test_application_define(void *); +void usbx_host_class_storage_max_lun_get_coverage_test_application_define(void *); +void usbx_storage_basic_memory_test_application_define(void *); +void usbx_storage_tests_application_define(void *); +void usbx_storage_multi_lun_test_application_define(void *); +void usbx_storage_direct_calls_test_application_define(void *); +void usbx_ux_device_class_storage_vendor_strings_test_application_define(void *); +void usbx_ux_device_class_storage_test_ready_test_application_define(void *); +void usbx_ux_device_class_storage_control_request_test_application_define(void *); +void usbx_ux_device_class_storage_entry_test_application_define(void *); +void usbx_ux_device_class_storage_format_test_application_define(void *); +void usbx_ux_device_class_storage_mode_select_test_application_define(void *); +void usbx_ux_device_class_storage_mode_sense_test_application_define(void *); +void usbx_ux_device_class_storage_request_sense_test_application_define(void *); +void usbx_ux_device_class_storage_start_stop_test_application_define(void *); +void usbx_ux_device_class_storage_prevent_allow_media_removal_test_application_define(void *); +void usbx_ux_device_class_storage_verify_test_application_define(void *); +void usbx_ux_device_class_storage_uninitialize_test_application_define(void *); +void usbx_ux_device_class_storage_inquiry_test_application_define(void *); +void usbx_ux_device_class_storage_initialize_test_application_define(void *); +void usbx_ux_device_class_storage_synchronize_cache_test_application_define(void *); +void usbx_ux_device_class_storage_read_test_application_define(void *); +void usbx_ux_device_class_storage_write_test_application_define(void *); +void usbx_ux_device_class_storage_thread_test_application_define(void *); +void usbx_ux_device_class_storage_request_sense_coverage_test_application_define(void *); +void usbx_ux_host_class_storage_configure_overage_test_application_define(void *); +void usbx_ux_host_class_storage_request_sense_test_application_define(void *); +void usbx_ux_host_class_storage_media_capacity_get_test_application_define(void *); +void usbx_ux_host_class_storage_max_lun_get_test_application_define(void *); +void usbx_ux_host_class_storage_configure_test_application_define(void *); +void usbx_ux_host_class_storage_activate_test_application_define(void *); +void usbx_ux_host_class_storage_device_support_check_test_application_define(void *); +void usbx_ux_host_class_storage_device_initialize_test_application_define(void *); +void usbx_ux_host_class_storage_media_get_test_application_define(void *); +void usbx_ux_host_class_storage_media_mount_test_application_define(void *); +void usbx_ux_host_class_storage_media_open_test_application_define(void *); +void usbx_ux_host_class_storage_media_read_test_application_define(void *); +void usbx_ux_host_class_storage_media_write_test_application_define(void *); +void usbx_ux_host_class_storage_media_protection_check_test_application_define(void *); +void usbx_ux_host_class_storage_media_recovery_sense_get_test_application_define(void *); +void usbx_ux_host_class_storage_start_stop_test_application_define(void *); +void usbx_ux_host_class_storage_transport_bo_test_application_define(void *); +void usbx_ux_host_class_storage_driver_entry_test_application_define(void *); +void usbx_ux_host_class_storage_entry_test_application_define(void *); + +/* RNDIS */ + +void usbx_rndis_basic_test_application_define(void *); + +/* Host stack */ +void usbx_ux_host_class_stack_device_configuration_reset_coverage_test_application_define(void *); +void usbx_ux_host_stack_bandwidth_test_application_define(void *); +void usbx_ux_host_stack_class_device_scan_test_application_define(void *); +void usbx_ux_host_stack_class_get_test_application_define(void *); +void usbx_ux_host_stack_class_instance_destroy_test_application_define(void *); +void usbx_ux_host_stack_class_instance_get_test_application_define(void *); +void usbx_ux_host_stack_class_instance_verify_test_application_define(void *); +void usbx_ux_host_stack_class_interface_scan_test_application_define(void *); +void usbx_ux_host_stack_class_register_test_application_define(void *); +void usbx_ux_host_stack_configuration_descriptor_parse_test_application_define(void *); +void usbx_ux_host_stack_configuration_enumerate_test_application_define(void *); +void usbx_ux_host_stack_configuration_instance_delete_test_application_define(void *); +void usbx_ux_host_stack_configuration_interface_get_test_application_define(void *); +void usbx_ux_host_stack_configuration_set_test_application_define(void *); +void usbx_ux_host_stack_device_address_set_test_application_define(void *); +void usbx_ux_host_stack_device_get_test_application_define(void *); +void usbx_ux_host_stack_device_remove_test_application_define(void *); +void usbx_ux_host_stack_endpoint_instance_create_test_application_define(void *); +void usbx_ux_host_stack_endpoint_instance_test_application_define(void *); +void usbx_ux_host_stack_endpoint_reset_test_application_define(void *); +void usbx_ux_host_stack_hcd_transfer_request_test_application_define(void *); +void usbx_ux_host_stack_hcd_register_test_application_define(void *); +void usbx_ux_host_stack_interface_endpoint_get_test_application_define(void *); +void usbx_ux_host_stack_interface_setting_select_test_application_define(void *); +void usbx_ux_host_stack_interfaces_scan_test_application_define(void *); +void usbx_ux_host_stack_new_configuration_create_test_application_define(void *); +void usbx_ux_host_stack_new_device_get_test_application_define(void *); +void usbx_ux_host_stack_new_device_create_test_application_define(void *); +void usbx_ux_host_stack_new_interface_create_test_application_define(void *); +void usbx_ux_host_stack_rh_change_process_test_application_define(void *); +void usbx_ux_host_stack_rh_device_insertion_test_application_define(void *); +void usbx_ux_host_stack_device_configuration_get_test_application_define(void *); +void usbx_ux_host_stack_device_configuration_reset_select_test_application_define(void *); +void usbx_ux_host_stack_hcd_thread_entry_test_application_define(void *); +void usbx_ux_host_stack_transfer_request_test_application_define(void *); +void usbx_ux_host_class_storage_thread_entry_test_application_define(void *); +//void usbx_ux_host_stack_transfer_request_abort_test_application_define(void *); + +/* Device Stack */ +void usbx_ux_device_stack_alternate_setting_get_test_application_define(void *); +void usbx_ux_device_stack_alternate_setting_set_test_application_define(void *); +void usbx_ux_device_stack_configuration_set_test_application_define(void *); +void usbx_ux_device_stack_control_request_process_coverage_test_application_define(void *); +void usbx_ux_device_stack_control_request_process_test_application_define(void *); +void usbx_ux_device_stack_descriptor_send_test_application_define(void *); +void usbx_ux_host_stack_device_descriptor_read_test_application_define(void *); +void usbx_ux_device_stack_get_status_test_application_define(void *); +void usbx_ux_device_stack_interface_delete_test_application_define(void *); +void usbx_ux_device_stack_interface_set_test_application_define(void *); +void usbx_ux_device_stack_interface_start_test_application_define(void *); +void usbx_ux_device_stack_remote_wakeup_test_application_define(void *); +void usbx_ux_device_stack_set_feature_test_application_define(void *); +void usbx_ux_device_stack_transfer_request_test_application_define(void *); +void usbx_ux_device_stack_endpoint_stall_test_application_define(void *); +void usbx_ux_device_stack_initialize_test_application_define(void *); + +/* CDC-ECM */ + +void usbx_cdc_ecm_basic_test_application_define(void *); +void usbx_cdc_ecm_basic_ipv6_test_application_define(void *); +void usbx_cdc_ecm_disconnect_and_reconnect_test_application_define(void *); +void usbx_cdc_ecm_alternate_setting_change_to_zero_test_application_define(void *); +void usbx_ux_host_class_cdc_ecm_transmission_callback_test_application_define(void *); +void usbx_cdc_ecm_host_bulk_out_transfer_arming_during_link_down_test_application_define(void *); +void usbx_cdc_ecm_host_bulk_out_transfer_fail_test_application_define(void *); +void usbx_ux_host_class_cdc_ecm_write_test_application_define(void *); +void usbx_cdc_ecm_host_bulk_in_transfer_arming_fails_due_to_link_down_and_thread_waiting_test_application_define(void *); +void usbx_cdc_ecm_host_non_ip_packet_received_test_application_define(void *); +void usbx_cdc_ecm_host_bulk_in_transfer_fail_test_application_define(void *); +void usbx_cdc_ecm_host_thread_link_down_before_transfer_test_application_define(void *); +void usbx_cdc_ecm_host_thread_packet_allocate_fail_test_application_define(void *); +void usbx_cdc_ecm_mac_address_test_application_define(void *); +void usbx_cdc_ecm_mac_address_invalid_length_test_application_define(void *); +void usbx_cdc_ecm_no_functional_descriptor_test_application_define(void *); +void usbx_ux_host_class_cdc_ecm_mac_address_get_test_application_define(void *); +void usbx_cdc_ecm_host_bulk_in_transfer_arming_during_link_down_test_application_define(void *); +void usbx_ux_host_class_cdc_ecm_interrupt_notification_test_application_define(void *); +void usbx_cdc_ecm_link_down_while_ongoing_transfers_test_application_define(void *); +void usbx_ux_host_class_cdc_ecm_entry_test_application_define(void *); +void usbx_cdc_ecm_host_bulk_in_transfer_arming_during_deactivate_test_application_define(void *); +void usbx_cdc_ecm_host_first_interrupt_transfer_fail_test_application_define(void *); +void usbx_cdc_ecm_host_packet_pool_create_fail_test_application_define(void *); +void usbx_cdc_ecm_host_thread_create_fail_test_application_define(void *); +void usbx_cdc_ecm_host_interrupt_notification_semaphore_create_fail_test_application_define(void *); +void usbx_cdc_ecm_host_bulk_out_semaphore_create_fail_test_application_define(void *); +void usbx_cdc_ecm_host_bulk_in_semaphore_create_fail_test_application_define(void *); +void usbx_cdc_ecm_control_interface_no_interrupt_endpoint_test_application_define(void *); +void usbx_cdc_ecm_data_interface_no_bulk_in_endpoint_test_application_define(void *); +void usbx_cdc_ecm_data_interface_non_bulk_out_and_non_bulk_in_endpoint_test_application_define(void *); +void usbx_cdc_ecm_data_interface_no_bulk_out_endpoint_test_application_define(void *); +void usbx_cdc_ecm_data_interface_setting_select_fails_test_application_define(void *); +void usbx_cdc_ecm_invalid_alternate_setting_after_zero_endpoint_data_interface_test_application_define(void *); +void usbx_cdc_ecm_non_data_interface_after_zero_endpoint_data_interface_test_application_define(void *); +void usbx_cdc_ecm_one_data_interface_with_no_endpoints_test_application_define(void *); +void usbx_cdc_ecm_no_control_interface_test_application_define(void *); +void usbx_cdc_ecm_interface_before_control_interface_test_application_define(void *); +void usbx_cdc_ecm_basic_memory_test_application_define(void *); +void usbx_ux_host_class_cdc_ecm_activate_test_application_define(void *); +void usbx_cdc_ecm_default_data_interface_with_endpoints_test_application_define(void *); +void usbx_ux_host_class_cdc_ecm_write_test_application_define(void *); +void usbx_ux_host_class_cdc_ecm_interrupt_notification_test_application_define(void *); +void usbx_ux_device_class_cdc_ecm_uninitialize_test_application_define(void *); +void usbx_ux_device_class_cdc_ecm_deactivate_test_application_define(void *); +void usbx_ux_device_class_cdc_ecm_initialize_test_application_define(void *); +void usbx_ux_device_class_cdc_ecm_activate_test_application_define(void *); +void usbx_ux_device_class_cdc_ecm_interrupt_thread_test_application_define(void *); +void usbx_ux_device_class_cdc_ecm_bulkin_thread_test_application_define(void *); +void usbx_ux_device_class_cdc_ecm_bulkout_thread_test_application_define(void *); +void usbx_ux_device_class_cdc_ecm_control_request_test_application_define(void *); +void usbx_ux_device_class_cdc_ecm_change_test_application_define(void *); +void usbx_ux_device_class_cdc_ecm_entry_test_application_define(void *); + +/* Hub */ +void usbx_host_class_hub_port_change_connection_process_coverage_test_application_define(void *); +void usbx_hub_basic_test_application_define(void *); +void usbx_hub_basic_memory_test_application_define(void *); +void usbx_hub_get_status_fails_during_configuration_test_application_define(void *); +void usbx_bus_powered_hub_connected_to_self_and_bus_powered_hub_test_application_define(void *); +void usbx_hub_invalid_hub_descriptor_length_test_application_define(void *); +void usbx_hub_full_speed_hub_test_application_define(void *); +void usbx_hub_multiple_tt_test_application_define(void *); +void usbx_hub_invalid_device_protocol_test_application_define(void *); +void usbx_ux_host_class_hub_descriptor_get_coverage_test_application_define(void *); +void usbx_ux_host_class_hub_entry_test_application_define(void *); +void usbx_hub_request_to_hub_itself_test_application_define(void *); +void usbx_hub_no_endpoints_test_application_define(void *); +void usbx_hub_interrupt_out_endpoint_test_application_define(void *); +void usbx_hub_non_interrupt_in_endpoint_test_application_define(void *); +void usbx_hub_hub_device_disconnect_test_application_define(void *); +void usbx_hub_quick_hub_device_reconnection_test_application_define(void *); +void usbx_hub_hub_device_enumeration_keeps_failing_test_application_define(void *); +void usbx_hub_port_reset_fails_during_hub_device_enumeration_test_application_define(void *); +void usbx_hub_get_port_status_fails_during_hub_device_enumeration_test_application_define(void *); +void usbx_hub_low_speed_hub_device_test_application_define(void *); +void usbx_hub_full_speed_hub_device_test_application_define(void *); +void usbx_hub_quick_hub_device_disconnection_test_application_define(void *); +void usbx_hub_port_change_enable_test_application_define(void *); +void usbx_hub_get_hub_status_fails_during_hub_device_enumeration_test_application_define(void *); +void usbx_hub_port_change_suspend_test_application_define(void *); +void usbx_hub_port_change_over_current_test_application_define(void *); +void usbx_hub_port_change_reset_test_application_define(void *); +void usbx_hub_port_reset_fails_due_to_unset_port_enabled_bit_test_application_define(void *); +void usbx_hub_get_hub_status_fails_during_port_reset_test_application_define(void *); +void usbx_hub_no_power_switching_test_application_define(void *); +void usbx_ux_host_class_hub_status_get_test_application_define(void *); +void usbx_hub_hub_status_get_invalid_length_test_application_define(void *); +void usbx_ux_host_class_hub_transfer_request_completed_test_application_define(void *); + +/* Pictbridge */ + +void usbx_pictbridge_basic_test_application_define(void *); + +/* Audio */ + +void usbx_audio10_device_basic_test_application_define(void *); +void usbx_audio10_iad_device_basic_test_application_define(void *); +void usbx_audio10_iad_device_control_test_application_define(void *); +void usbx_audio20_device_basic_test_application_define(void *); +void usbx_uxe_device_audio_test_application_define(void *); + +/* Video */ + +void usbx_host_class_video_basic_test_application_define(void *); + +/* Printer */ + +void usbx_host_class_printer_basic_test_application_define(void *); +void usbx_uxe_device_printer_test_application_define(void *); + + +/* CTest application define */ + +void test_application_define(void *first_unused_memory); + +/* Define the array of test entry points. */ + +TEST_ENTRY test_control_tests[] = +{ +#ifdef CTEST + test_application_define, +#else + + /* MSC */ + // usbx_storage_tests_application_define, + usbx_host_class_storage_entry_overage_test_application_define, + usbx_host_class_storage_max_lun_get_coverage_test_application_define, + + usbx_host_stack_new_endpoint_create_overage_test_application_define, + usbx_host_stack_class_unregister_coverage_test_application_define, + usbx_storage_basic_memory_test_application_define, + usbx_storage_multi_lun_test_application_define, + usbx_ux_device_class_storage_request_sense_coverage_test_application_define, + usbx_ux_device_class_storage_vendor_strings_test_application_define, + usbx_ux_device_class_storage_test_ready_test_application_define, + usbx_ux_device_class_storage_control_request_test_application_define, + usbx_ux_device_class_storage_entry_test_application_define, + usbx_ux_device_class_storage_format_test_application_define, + usbx_ux_device_class_storage_mode_select_test_application_define, + usbx_ux_device_class_storage_mode_sense_test_application_define, + usbx_ux_device_class_storage_request_sense_test_application_define, + usbx_ux_device_class_storage_start_stop_test_application_define, + usbx_ux_device_class_storage_prevent_allow_media_removal_test_application_define, + usbx_ux_device_class_storage_verify_test_application_define, + usbx_ux_device_class_storage_uninitialize_test_application_define, + usbx_ux_device_class_storage_inquiry_test_application_define, + usbx_ux_device_class_storage_initialize_test_application_define, + usbx_ux_device_class_storage_synchronize_cache_test_application_define, + usbx_ux_device_class_storage_read_test_application_define, + + usbx_ux_device_class_storage_write_test_application_define, + usbx_ux_device_class_storage_thread_test_application_define, + usbx_ux_host_class_storage_configure_overage_test_application_define, + usbx_ux_host_class_storage_request_sense_test_application_define, + usbx_ux_host_class_storage_media_capacity_get_test_application_define, + usbx_ux_host_class_storage_max_lun_get_test_application_define, + usbx_ux_host_class_storage_configure_test_application_define, + usbx_ux_host_class_storage_activate_test_application_define, + usbx_ux_host_class_storage_device_support_check_test_application_define, + usbx_ux_host_class_storage_device_initialize_test_application_define, + usbx_ux_host_class_storage_media_mount_test_application_define, + usbx_ux_host_class_storage_media_open_test_application_define, + usbx_ux_host_class_storage_media_read_test_application_define, + usbx_ux_host_class_storage_media_write_test_application_define, + usbx_ux_host_class_storage_media_protection_check_test_application_define, + usbx_ux_host_class_storage_media_recovery_sense_get_test_application_define, + usbx_ux_host_class_storage_start_stop_test_application_define, + usbx_ux_host_class_storage_transport_bo_test_application_define, + usbx_ux_host_class_storage_driver_entry_test_application_define, + usbx_ux_host_class_storage_thread_entry_test_application_define, + usbx_ux_host_class_storage_entry_test_application_define, + + /* Utility */ + + usbx_ux_utility_descriptor_pack_test_application_define, + usbx_ux_utility_descriptor_parse_test_application_define, + usbx_ux_utility_event_flags_test_application_define, + usbx_ux_utility_memory_safe_test_application_define, + usbx_ux_utility_memory_test_application_define, + usbx_ux_utility_mutex_test_application_define, + usbx_ux_utility_pci_write_test_application_define, + usbx_ux_utility_pci_read_test_application_define, + usbx_ux_utility_pci_class_scan_test_application_define, + usbx_ux_utility_physical_address_test_application_define, + usbx_ux_utility_semaphore_test_application_define, + usbx_ux_utility_string_length_check_test_application_define, + usbx_ux_utility_thread_create_test_application_define, + usbx_ux_utility_thread_schedule_other_test_application_define, + usbx_ux_utility_thread_suspend_test_application_define, + usbx_ux_utility_thread_identify_test_application_define, + usbx_ux_utility_timer_test_application_define, + usbx_ux_utility_unicode_to_string_test_application_define, + + /* Host stack */ + + usbx_ux_host_stack_uninitialize_test_application_define, + usbx_ux_host_stack_hcd_unregister_test_application_define, + usbx_ux_host_stack_class_unregister_test_application_define, + + //usbx_ux_host_stack_transfer_request_abort_test_application_define, + usbx_ux_host_class_stack_device_configuration_reset_coverage_test_application_define, + usbx_ux_host_stack_bandwidth_test_application_define, + usbx_ux_host_stack_class_device_scan_test_application_define, + usbx_ux_host_stack_class_get_test_application_define, + usbx_ux_host_stack_class_instance_destroy_test_application_define, + usbx_ux_host_stack_class_instance_get_test_application_define, + usbx_ux_host_stack_class_interface_scan_test_application_define, + usbx_ux_host_stack_class_register_test_application_define, + usbx_ux_host_stack_configuration_descriptor_parse_test_application_define, + usbx_ux_host_stack_configuration_enumerate_test_application_define, + usbx_ux_host_stack_configuration_instance_delete_test_application_define, + usbx_ux_host_stack_configuration_interface_get_test_application_define, + usbx_ux_host_stack_configuration_set_test_application_define, + usbx_ux_host_stack_device_address_set_test_application_define, + usbx_ux_host_stack_device_get_test_application_define, + usbx_ux_host_stack_device_remove_test_application_define, + usbx_ux_host_stack_endpoint_instance_create_test_application_define, + usbx_ux_host_stack_endpoint_instance_test_application_define, + usbx_ux_host_stack_hcd_transfer_request_test_application_define, + usbx_ux_host_stack_hcd_register_test_application_define, + usbx_ux_host_stack_interface_endpoint_get_test_application_define, + usbx_ux_host_stack_interfaces_scan_test_application_define, + usbx_ux_host_stack_new_device_get_test_application_define, + usbx_ux_host_stack_rh_device_insertion_test_application_define, + usbx_ux_host_stack_device_configuration_get_test_application_define, + usbx_ux_host_stack_device_configuration_reset_select_test_application_define, + usbx_ux_host_stack_hcd_thread_entry_test_application_define, + usbx_ux_host_stack_transfer_request_test_application_define, + + /* Device Stack */ + + usbx_ux_device_stack_alternate_setting_get_test_application_define, + usbx_ux_device_stack_alternate_setting_set_test_application_define, + usbx_ux_device_stack_class_register_test_application_define, + usbx_ux_device_stack_class_unregister_test_application_define, + usbx_ux_device_stack_configuration_set_test_application_define, + usbx_ux_device_stack_control_request_process_coverage_test_application_define, + usbx_ux_device_stack_control_request_process_test_application_define, + usbx_ux_host_stack_device_descriptor_read_test_application_define, + usbx_ux_device_stack_get_status_test_application_define, + usbx_ux_device_stack_interface_delete_test_application_define, + usbx_ux_device_stack_interface_set_test_application_define, + usbx_ux_device_stack_interface_start_test_application_define, + usbx_ux_device_stack_set_feature_test_application_define, + usbx_ux_device_stack_transfer_request_test_application_define, + usbx_ux_device_stack_endpoint_stall_test_application_define, + usbx_ux_device_stack_initialize_test_application_define, + usbx_ux_device_stack_clear_feature_coverage_test_application_define, + +#if !defined(UX_DEVICE_STANDALONE) && !defined(UX_HOST_STANDALONE) + + /* MSC */ + usbx_storage_tests_application_define, + + /* Stack (with CDC ACM) */ + usbx_ux_host_stack_class_instance_verify_test_application_define, + usbx_ux_host_stack_endpoint_reset_test_application_define, + usbx_ux_host_stack_interface_setting_select_test_application_define, + usbx_ux_host_stack_new_configuration_create_test_application_define, + usbx_ux_host_stack_new_device_create_test_application_define, + usbx_ux_host_stack_new_interface_create_test_application_define, + usbx_ux_host_stack_rh_change_process_test_application_define, + + usbx_device_stack_standard_request_test_application_define, + usbx_ux_device_stack_descriptor_send_test_application_define, + usbx_ux_device_stack_remote_wakeup_test_application_define, + + /* Audio */ + usbx_audio10_device_basic_test_application_define, + usbx_audio10_iad_device_basic_test_application_define, + usbx_audio10_iad_device_control_test_application_define, + usbx_audio20_device_basic_test_application_define, + usbx_uxe_device_audio_test_application_define, + + /* Hub */ + usbx_host_class_hub_port_change_connection_process_coverage_test_application_define, + usbx_ux_host_class_hub_transfer_request_completed_test_application_define, + usbx_hub_hub_status_get_invalid_length_test_application_define, + usbx_ux_host_class_hub_status_get_test_application_define, + usbx_hub_no_power_switching_test_application_define, + usbx_hub_get_hub_status_fails_during_port_reset_test_application_define, + usbx_hub_port_reset_fails_due_to_unset_port_enabled_bit_test_application_define, + usbx_hub_port_change_reset_test_application_define, + usbx_hub_port_change_over_current_test_application_define, + usbx_hub_port_change_suspend_test_application_define, + usbx_hub_get_hub_status_fails_during_hub_device_enumeration_test_application_define, + usbx_hub_port_change_enable_test_application_define, + usbx_hub_quick_hub_device_disconnection_test_application_define, + usbx_hub_full_speed_hub_device_test_application_define, + usbx_hub_low_speed_hub_device_test_application_define, + usbx_hub_port_reset_fails_during_hub_device_enumeration_test_application_define, + usbx_hub_get_port_status_fails_during_hub_device_enumeration_test_application_define, + usbx_hub_hub_device_enumeration_keeps_failing_test_application_define, + usbx_hub_quick_hub_device_reconnection_test_application_define, + usbx_hub_hub_device_disconnect_test_application_define, + usbx_hub_non_interrupt_in_endpoint_test_application_define, + usbx_hub_interrupt_out_endpoint_test_application_define, + usbx_hub_no_endpoints_test_application_define, + usbx_hub_request_to_hub_itself_test_application_define, + usbx_ux_host_class_hub_descriptor_get_coverage_test_application_define, + usbx_ux_host_class_hub_entry_test_application_define, + usbx_hub_invalid_device_protocol_test_application_define, + usbx_hub_basic_test_application_define, + usbx_hub_basic_memory_test_application_define, + usbx_hub_get_status_fails_during_configuration_test_application_define, + usbx_bus_powered_hub_connected_to_self_and_bus_powered_hub_test_application_define, + usbx_hub_invalid_hub_descriptor_length_test_application_define, + usbx_hub_full_speed_hub_test_application_define, + usbx_hub_multiple_tt_test_application_define, + + /* CDC-ECM */ + + usbx_cdc_ecm_disconnect_and_reconnect_test_application_define, + usbx_cdc_ecm_alternate_setting_change_to_zero_test_application_define, + usbx_ux_host_class_cdc_ecm_interrupt_notification_test_application_define, + usbx_ux_host_class_cdc_ecm_transmission_callback_test_application_define, + usbx_cdc_ecm_host_bulk_out_transfer_arming_during_link_down_test_application_define, + usbx_cdc_ecm_host_bulk_out_transfer_fail_test_application_define, + usbx_ux_host_class_cdc_ecm_write_test_application_define, + usbx_cdc_ecm_host_bulk_in_transfer_arming_fails_due_to_link_down_and_thread_waiting_test_application_define, + usbx_cdc_ecm_host_non_ip_packet_received_test_application_define, + usbx_cdc_ecm_host_bulk_in_transfer_fail_test_application_define, + usbx_cdc_ecm_host_thread_packet_allocate_fail_test_application_define, + usbx_cdc_ecm_host_thread_link_down_before_transfer_test_application_define, + usbx_cdc_ecm_host_packet_pool_create_fail_test_application_define, + usbx_cdc_ecm_mac_address_test_application_define, + usbx_cdc_ecm_basic_test_application_define, + usbx_cdc_ecm_basic_ipv6_test_application_define, + usbx_cdc_ecm_mac_address_invalid_length_test_application_define, + usbx_cdc_ecm_no_functional_descriptor_test_application_define, + usbx_ux_host_class_cdc_ecm_mac_address_get_test_application_define, + usbx_cdc_ecm_host_bulk_in_transfer_arming_during_link_down_test_application_define, + usbx_ux_host_class_cdc_ecm_entry_test_application_define, + usbx_cdc_ecm_host_bulk_in_transfer_arming_during_deactivate_test_application_define, + usbx_cdc_ecm_host_first_interrupt_transfer_fail_test_application_define, + usbx_cdc_ecm_host_thread_create_fail_test_application_define, + usbx_cdc_ecm_host_interrupt_notification_semaphore_create_fail_test_application_define, + usbx_cdc_ecm_host_bulk_out_semaphore_create_fail_test_application_define, + usbx_cdc_ecm_host_bulk_in_semaphore_create_fail_test_application_define, + usbx_cdc_ecm_control_interface_no_interrupt_endpoint_test_application_define, + usbx_cdc_ecm_data_interface_setting_select_fails_test_application_define, + usbx_cdc_ecm_data_interface_no_bulk_in_endpoint_test_application_define, + usbx_cdc_ecm_data_interface_non_bulk_out_and_non_bulk_in_endpoint_test_application_define, + usbx_cdc_ecm_data_interface_no_bulk_out_endpoint_test_application_define, + usbx_cdc_ecm_one_data_interface_with_no_endpoints_test_application_define, + usbx_cdc_ecm_invalid_alternate_setting_after_zero_endpoint_data_interface_test_application_define, + usbx_cdc_ecm_non_data_interface_after_zero_endpoint_data_interface_test_application_define, + usbx_cdc_ecm_default_data_interface_with_endpoints_test_application_define, + usbx_cdc_ecm_no_control_interface_test_application_define, + usbx_cdc_ecm_interface_before_control_interface_test_application_define, + usbx_cdc_ecm_basic_memory_test_application_define, + usbx_ux_device_class_cdc_ecm_uninitialize_test_application_define, + usbx_ux_device_class_cdc_ecm_deactivate_test_application_define, + usbx_ux_device_class_cdc_ecm_initialize_test_application_define, + usbx_ux_device_class_cdc_ecm_activate_test_application_define, + usbx_ux_device_class_cdc_ecm_interrupt_thread_test_application_define, + usbx_ux_device_class_cdc_ecm_bulkin_thread_test_application_define, + usbx_ux_device_class_cdc_ecm_bulkout_thread_test_application_define, + usbx_ux_device_class_cdc_ecm_control_request_test_application_define, + usbx_ux_device_class_cdc_ecm_change_test_application_define, + usbx_ux_device_class_cdc_ecm_entry_test_application_define, + usbx_cdc_ecm_link_down_while_ongoing_transfers_test_application_define, + + /* RNDIS */ + + usbx_rndis_basic_test_application_define, + + /* CDC-ACM. */ + + usbx_cdc_acm_basic_test_application_define, + usbx_cdc_acm_basic_memory_test_application_define, + usbx_cdc_acm_configure_test_application_define, + usbx_cdc_acm_device_dtr_rts_reset_on_disconnect_test_application_define, + usbx_ux_device_class_cdc_acm_activate_test_application_define, + usbx_ux_device_class_cdc_acm_deactivate_test_application_define, + usbx_ux_device_class_cdc_acm_ioctl_test_application_define, + usbx_ux_device_class_cdc_acm_transmission_test_application_define, + usbx_ux_device_class_cdc_acm_write_test_application_define, + usbx_ux_device_class_cdc_acm_timeout_test_application_define, + usbx_ux_host_class_cdc_acm_activate_test_application_define, + usbx_ux_host_class_cdc_acm_capabilities_get_test_application_define, + usbx_ux_host_class_cdc_acm_deactivate_test_application_define, + usbx_ux_host_class_cdc_acm_endpoints_get_test_application_define, + usbx_ux_host_class_cdc_acm_entry_test_application_define, + usbx_ux_host_class_cdc_acm_read_test_application_define, + usbx_ux_host_class_cdc_acm_transfer_request_completed_test_application_define, + usbx_ux_device_class_cdc_acm_bulkout_thread_test_application_define, + usbx_uxe_device_cdc_acm_test_application_define, + + /* DPUMP. */ + + usbx_dpump_basic_test_application_define, + + /* Printer */ + + usbx_host_class_printer_basic_test_application_define, + usbx_uxe_device_printer_test_application_define, + + /* Host & Device basic. */ + + usbx_host_device_basic_test_application_define, + usbx_host_device_basic_memory_test_application_define, + usbx_host_device_initialize_test_application_define, + + /* HID */ + + usbx_hid_report_descriptor_compress_array_test_application_define, + usbx_hid_remote_control_tests_application_define, + usbx_ux_host_class_hid_remote_control_entry_test_application_define, + usbx_ux_host_class_hid_remote_control_entry_test2_application_define, + usbx_ux_host_class_hid_remote_control_entry_test3_application_define, + usbx_ux_host_class_hid_remote_control_usage_get_test_application_define, + usbx_hid_keyboard_basic_test_application_define, + usbx_hid_keyboard_key_test_application_define, + usbx_ux_device_class_hid_activate_test_application_define, + usbx_ux_device_class_hid_control_request_test_application_define, + usbx_ux_device_class_hid_deactivate_test_application_define, + usbx_ux_device_class_hid_descriptor_send_test_application_define, + usbx_ux_device_class_hid_entry_test_application_define, + usbx_ux_device_class_hid_event_get_AND_set_test_application_define, + usbx_ux_device_class_hid_initialize_test_application_define, + usbx_ux_device_class_hid_interrupt_thread_test_application_define, + usbx_ux_device_class_hid_interrupt_thread_test2_application_define, + usbx_ux_device_class_hid_report_test_application_define, + usbx_ux_host_class_hid_activate_test_application_define, + usbx_ux_host_class_hid_client_register_test_application_define, + usbx_ux_host_class_hid_client_register_test2_application_define, + usbx_ux_host_class_hid_client_search_test_application_define, + usbx_ux_host_class_hid_configure_test_application_define, + usbx_ux_host_class_hid_deactivate_test_application_define, + usbx_ux_host_class_hid_deactivate_test3_application_define, + usbx_ux_host_class_hid_descriptor_parse_coverage_test_application_define, + usbx_ux_host_class_hid_descriptor_parse_test_application_define, + usbx_ux_host_class_hid_descriptor_parse_test2_application_define, + usbx_ux_host_class_hid_descriptor_parse_test4_application_define, + usbx_ux_host_class_hid_descriptor_parse_test5_application_define, + usbx_ux_host_class_hid_entry_test_application_define, + usbx_ux_host_class_hid_idle_get_test_application_define, + usbx_ux_host_class_hid_idle_set_test_application_define, + usbx_ux_host_class_hid_keyboard_activate_test_application_define, + usbx_ux_host_class_hid_keyboard_entry_test_application_define, + usbx_ux_host_class_hid_keyboard_ioctl_test_application_define, + usbx_ux_host_class_hid_keyboard_thread_test_application_define, + usbx_ux_host_class_hid_keyboard_thread_test2_application_define, + usbx_ux_host_class_hid_main_item_parse_test_application_define, + usbx_ux_host_class_hid_main_item_parse_test2_application_define, + usbx_ux_host_class_hid_mouse_activate_test_application_define, + usbx_ux_host_class_hid_mouse_entry_test_application_define, + usbx_ux_host_class_hid_mouse_entry_test3_application_define, + usbx_ux_host_class_hid_mouse_buttons_get_test_application_define, + usbx_ux_host_class_hid_mouse_positions_get_test_application_define, + usbx_ux_host_class_hid_mouse_wheel_get_test_application_define, + usbx_ux_host_class_hid_periodic_report_start_test_application_define, + usbx_ux_host_class_hid_periodic_report_start_test2_application_define, + usbx_ux_host_class_hid_periodic_report_stop_test_application_define, + usbx_ux_host_class_hid_remote_control_activate_test_application_define, + usbx_ux_host_class_hid_report_add_test_application_define, + usbx_ux_host_class_hid_report_callback_register_test_application_define, + usbx_ux_host_class_hid_report_get_test_application_define, + usbx_ux_host_class_hid_report_get_test2_application_define, + usbx_ux_host_class_hid_report_id_get_test_application_define, + usbx_ux_host_class_hid_report_set_test_application_define, + usbx_ux_host_class_hid_transfer_request_completed_test_application_define, + usbx_hid_keyboard_key_get_test_application_define, + usbx_hid_transfer_request_completed_decompressed_test_application_define, + usbx_hid_transfer_request_completed_test_application_define, + usbx_hid_transfer_request_completed_raw_test_application_define, + usbx_hid_report_descriptor_compress_test_application_define, + usbx_hid_report_descriptor_compress_and_decompress_test_application_define, + usbx_hid_report_descriptor_get_zero_length_item_data_test_application_define, + usbx_hid_report_descriptor_global_item_test_application_define, + usbx_hid_report_descriptor_global_item_persist_test_application_define, + usbx_hid_report_descriptor_report_size_overflow_test_application_define, + usbx_hid_report_descriptor_report_count_overflow_test_application_define, + usbx_hid_report_descriptor_pop_underflow_tag_test_application_define, + usbx_hid_report_descriptor_push_overflow_tag_test_application_define, + usbx_hid_report_descriptor_push_pop_test_application_define, + usbx_hid_report_descriptor_unknown_global_tag_test_application_define, + usbx_hid_report_descriptor_end_collection_error_test_application_define, + usbx_hid_report_descriptor_collection_overflow_test_application_define, + usbx_hid_report_descriptor_multiple_collections_test_application_define, + usbx_hid_report_descriptor_unknown_local_tag_test_application_define, + usbx_hid_report_descriptor_incoherent_usage_min_max_test_application_define, + usbx_hid_report_descriptor_delimiter_unknown_test_application_define, + usbx_hid_report_descriptor_delimiter_nested_close_test_application_define, + usbx_hid_report_descriptor_delimiter_nested_open_test_application_define, + usbx_hid_report_descriptor_invalid_length_test_application_define, + usbx_hid_report_descriptor_invalid_item_test_application_define, + usbx_ux_host_class_hid_local_item_parse_test_application_define, + usbx_hid_mouse_basic_test_application_define, + usbx_ux_device_class_hid_basic_memory_test_application_define, + usbx_ux_device_class_hid_idle_rate_test_application_define, + + usbx_host_class_video_basic_test_application_define, + +#endif /* !defined(UX_DEVICE_STANDALONE) && !defined(UX_HOST_STANDALONE) */ +#endif /* CTEST */ + TX_NULL, +}; + +/* Define thread prototypes. */ + +void test_control_thread_entry(ULONG thread_input); +void test_thread_entry(ULONG thread_input); +void test_control_return(UINT status); +void test_control_cleanup(void); + + +/* Define necessary external references. */ + +#ifdef __ghs +extern TX_MUTEX __ghLockMutex; +#endif + +extern TX_TIMER *_tx_timer_created_ptr; +extern ULONG _tx_timer_created_count; +#ifndef TX_TIMER_PROCESS_IN_ISR +extern TX_THREAD _tx_timer_thread; +#endif +extern TX_THREAD *_tx_thread_created_ptr; +extern ULONG _tx_thread_created_count; +extern TX_SEMAPHORE *_tx_semaphore_created_ptr; +extern ULONG _tx_semaphore_created_count; +extern TX_QUEUE *_tx_queue_created_ptr; +extern ULONG _tx_queue_created_count; +extern TX_MUTEX *_tx_mutex_created_ptr; +extern ULONG _tx_mutex_created_count; +extern TX_EVENT_FLAGS_GROUP *_tx_event_flags_created_ptr; +extern ULONG _tx_event_flags_created_count; +extern TX_BYTE_POOL *_tx_byte_pool_created_ptr; +extern ULONG _tx_byte_pool_created_count; +extern TX_BLOCK_POOL *_tx_block_pool_created_ptr; +extern ULONG _tx_block_pool_created_count; + +extern NX_PACKET_POOL * _nx_packet_pool_created_ptr; +extern ULONG _nx_packet_pool_created_count; +extern NX_IP * _nx_ip_created_ptr; +extern ULONG _nx_ip_created_count; + +#ifdef EXTERNAL_EXIT +void external_exit(UINT code); +#endif + + +/* Define the interrupt processing dispatcher. The individual tests will set this up when they desire + asynchrony processing for testing purposes. */ + +void test_interrupt_dispatch(void) +{ + +#ifndef TX_DISABLE_ERROR_CHECKING + + /* Test calling tx_thread_relinquish from ISR to see if the error checking throws it out. */ + tx_thread_relinquish(); +#endif + + /* Check for something to run... */ + if (test_isr_dispatch) + { + + (test_isr_dispatch)(); + } +} + + +/* Define init timer entry. */ + +static void init_timer_entry(ULONG timer_input) +{ + +} + + +/* Define main entry point. */ +#ifndef EXTERNAL_MAIN +void main() +{ + + /* Enter the USBX kernel. */ + tx_kernel_enter(); +} +#endif + + +/* Define what the initial system looks like. */ + +void tx_application_define(void *first_unused_memory) +{ + + /* Initialize the test error/success counters. */ + test_control_successful_tests = 0; + test_control_failed_tests = 0; + test_control_system_errors = 0; + + /* Create the test control thread. */ + tx_thread_create(&test_control_thread, "test control thread", test_control_thread_entry, 0, + test_control_thread_stack, TEST_STACK_SIZE, + 17, 15, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Remember the free memory pointer. */ + test_free_memory_ptr = &tests_memory[0]; +} + + + +/* Define the test control thread. This thread is responsible for dispatching all of the + tests in the USBX test suite. */ + +void test_control_thread_entry(ULONG thread_input) +{ + +ULONG previous_test_control_failed_tests; +ULONG previous_thread_created_count; +UINT i; + + /* Raise the priority of the control thread to 0. */ + tx_thread_priority_change(&test_control_thread, 0, &i); + + /* Print out banner. */ + printf("********************** USBX Validation/Regression Test Suite *********************************\n\n"); + + /* Print version id. */ + printf("Version: %s Data width: x%i\n\n", _ux_version_id, (int)sizeof(void*) * 8); + + /* Print out the tests... */ + printf("Running validation/regression test:\n\n"); + + /* Loop to process all tests... */ + i = 0; + while (test_control_tests[i].test_entry != TX_NULL) + { + + /* Clear the ISR dispatch. */ + test_isr_dispatch = TX_NULL; + + /* Save the number of failed tests for comparison. */ + previous_test_control_failed_tests = test_control_failed_tests; + + /* Save previous thread count. */ + previous_thread_created_count = _tx_thread_created_count; + + /* Dispatch the test. */ + (test_control_tests[i++].test_entry)(test_free_memory_ptr); + + /* Clear the ISR dispatch. */ + test_isr_dispatch = TX_NULL; + + /* Did the test entry run successfully? */ + if (test_control_failed_tests == previous_test_control_failed_tests && + previous_thread_created_count != _tx_thread_created_count) + + /* Suspend control test to allow test to run. */ + tx_thread_suspend(&test_control_thread); + + /* Test finished, cleanup in preparation for the next test. */ + test_control_cleanup(); + } + + /* Finished with all tests, print results and return! */ + printf("**** Testing Complete ****\n"); + printf("**** Test Summary: Tests Passed: %lu Tests Failed: %lu System Errors: %lu\n", test_control_successful_tests, test_control_failed_tests, test_control_system_errors); + +#ifndef EXTERNAL_EXIT + exit(test_control_failed_tests); +#else + external_exit(0); +#endif +} + +static VOID disable_test_actions(VOID) +{ + + /* Note: There shouldn't be any actions left. */ + ux_test_cleanup_everything(); + + ux_test_utility_sim_cleanup(); + ux_test_hcd_sim_host_cleanup(); + ux_test_dcd_sim_slave_cleanup(); +} + + +void test_control_return(UINT status) +{ + +UINT old_posture = TX_INT_ENABLE; + + disable_test_actions(); + + /* Save the status in a global. */ + test_control_return_status = status; + + /* Ensure interrupts are enabled. */ + old_posture = tx_interrupt_control(TX_INT_ENABLE); + + /* Determine if it was successful or not. */ + if (status) + test_control_failed_tests++; + else + test_control_successful_tests++; + + /* Now check for system errors. */ + + /* Is preempt disable flag set? */ + if (_tx_thread_preempt_disable) + { + + /* System error - preempt disable should never be set inside of a thread! */ + printf(" ***** SYSTEM ERROR ***** _tx_thread_preempt_disable is non-zero!\n"); + test_control_system_errors++; + } + + /* Is system state set? */ + if (_tx_thread_system_state) + { + + /* System error - system state should never be set inside of a thread! */ + printf(" ***** SYSTEM ERROR ***** _tx_thread_system_state is non-zero!\n"); + test_control_system_errors++; + } + + /* Are interrupts disabled? */ + if (old_posture == TX_INT_DISABLE) + { + + /* System error - interrupts should always be enabled in our test threads! */ + printf(" ***** SYSTEM ERROR ***** test returned with interrupts disabled!\n"); + test_control_system_errors++; + } + + /* Resume the control thread to fully exit the test. */ + tx_thread_resume(&test_control_thread); +} + + +void test_control_cleanup(void) +{ + +TX_MUTEX *mutex_ptr; +TX_THREAD *thread_ptr; + + + /* FIXME: Cleanup of FileX, and USBX resources should be added here... and perhaps some checks for memory leaks, etc. */ + + /* Disable testing actions generation */ + disable_test_actions(); + + /* Delete all IP instances. */ + while (_nx_ip_created_ptr) + { + + /* Delete all UDP sockets. */ + while (_nx_ip_created_ptr -> nx_ip_udp_created_sockets_ptr) + { + + /* Make sure the UDP socket is unbound. */ + nx_udp_socket_unbind(_nx_ip_created_ptr -> nx_ip_udp_created_sockets_ptr); + + /* Delete the UDP socket. */ + nx_udp_socket_delete(_nx_ip_created_ptr -> nx_ip_udp_created_sockets_ptr); + } + + /* Delete all TCP sockets. */ + while (_nx_ip_created_ptr -> nx_ip_tcp_created_sockets_ptr) + { + + /* When disconnecting TCP sockets, NetX sends a RST packet. Since the link + is down, the driver will report an error. So, turn of errors during this + time. */ + ux_test_ignore_all_errors(); + + /* Disconnect. */ + nx_tcp_socket_disconnect(_nx_ip_created_ptr -> nx_ip_tcp_created_sockets_ptr, NX_NO_WAIT); + + /* Re-enable errors. */ + ux_test_unignore_all_errors(); + + /* Make sure the TCP client socket is unbound. */ + nx_tcp_client_socket_unbind(_nx_ip_created_ptr -> nx_ip_tcp_created_sockets_ptr); + + /* Make sure the TCP server socket is unaccepted. */ + nx_tcp_server_socket_unaccept(_nx_ip_created_ptr -> nx_ip_tcp_created_sockets_ptr); + + /* Delete the TCP socket. */ + nx_tcp_socket_delete(_nx_ip_created_ptr -> nx_ip_tcp_created_sockets_ptr); + } + + /* Clear all listen requests. */ + while (_nx_ip_created_ptr -> nx_ip_tcp_active_listen_requests) + { + + /* Make sure the TCP server socket is unlistened. */ + nx_tcp_server_socket_unlisten(_nx_ip_created_ptr, (_nx_ip_created_ptr -> nx_ip_tcp_active_listen_requests) -> nx_tcp_listen_port); + } + + /* Delete the IP instance. */ + nx_ip_delete(_nx_ip_created_ptr); + } + + /* Delete all the packet pools. */ + while (_nx_packet_pool_created_ptr) + { + nx_packet_pool_delete(_nx_packet_pool_created_ptr); + } + + /* Delete all queues. */ + while(_tx_queue_created_ptr) + { + + /* Delete queue. */ + tx_queue_delete(_tx_queue_created_ptr); + } + + /* Delete all semaphores. */ + while(_tx_semaphore_created_ptr) + { + + /* Delete semaphore. */ + tx_semaphore_delete(_tx_semaphore_created_ptr); + } + + /* Delete all event flag groups. */ + while(_tx_event_flags_created_ptr) + { + + /* Delete event flag group. */ + tx_event_flags_delete(_tx_event_flags_created_ptr); + } + + /* Delete all byte pools. */ + while(_tx_byte_pool_created_ptr) + { + + /* Delete byte pool. */ + tx_byte_pool_delete(_tx_byte_pool_created_ptr); + } + + /* Delete all block pools. */ + while(_tx_block_pool_created_ptr) + { + + /* Delete block pool. */ + tx_block_pool_delete(_tx_block_pool_created_ptr); + } + + /* Delete all timers. */ + while(_tx_timer_created_ptr) + { + + /* Deactivate timer. */ + tx_timer_deactivate(_tx_timer_created_ptr); + + /* Delete timer. */ + tx_timer_delete(_tx_timer_created_ptr); + } + + /* Delete all mutexes (except for system mutex). */ + while(_tx_mutex_created_ptr) + { + + /* Setup working mutex pointer. */ + mutex_ptr = _tx_mutex_created_ptr; + +#ifdef __ghs + + /* Determine if the mutex is the GHS system mutex. If so, don't delete! */ + if (mutex_ptr == &__ghLockMutex) + { + + /* Move to next mutex. */ + mutex_ptr = mutex_ptr -> tx_mutex_created_next; + } + + /* Determine if there are no more mutexes to delete. */ + if (_tx_mutex_created_count == 1) + break; +#endif + + /* Delete mutex. */ + tx_mutex_delete(mutex_ptr); + } + + /* Delete all threads, except for timer thread, and test control thread. */ + while (_tx_thread_created_ptr) + { + + /* Setup working pointer. */ + thread_ptr = _tx_thread_created_ptr; + + +#ifdef TX_TIMER_PROCESS_IN_ISR + + /* Determine if there are more threads to delete. */ + if (_tx_thread_created_count == 1) + break; + + /* Determine if this thread is the test control thread. */ + if (thread_ptr == &test_control_thread) + { + + /* Move to the next thread pointer. */ + thread_ptr = thread_ptr -> tx_thread_created_next; + } +#else + + /* Determine if there are more threads to delete. */ + if (_tx_thread_created_count == 2) + break; + + /* Move to the thread not protected. */ + while ((thread_ptr == &_tx_timer_thread) || (thread_ptr == &test_control_thread)) + { + + /* Yes, move to the next thread. */ + thread_ptr = thread_ptr -> tx_thread_created_next; + } +#endif + + /* First terminate the thread to ensure it is ready for deletion. */ + tx_thread_terminate(thread_ptr); + + /* Delete the thread. */ + tx_thread_delete(thread_ptr); + } + + /* At this point, only the test control thread and the system timer thread and/or mutex should still be + in the system. */ +} + + + + diff --git a/test/regression/ux_device_class_dummy.c b/test/regression/ux_device_class_dummy.c new file mode 100644 index 00000000..4f401d4b --- /dev/null +++ b/test/regression/ux_device_class_dummy.c @@ -0,0 +1,315 @@ + +#include "ux_api.h" +#include "ux_device_class_dummy.h" +#include "ux_device_stack.h" + +UCHAR _ux_device_class_dummy_name[] = "ux_device_class_dummy"; + +static UINT _ux_device_class_dummy_initialize(UX_SLAVE_CLASS_COMMAND *command) +{ + +UX_SLAVE_CLASS *class; +UX_DEVICE_CLASS_DUMMY *dummy; +UX_DEVICE_CLASS_DUMMY_PARAMETER *dummy_parameter; + + + /* Get the class container. */ + class = command -> ux_slave_class_command_class_ptr; + + /* Get pointer to the application parameters. */ + dummy_parameter = (UX_DEVICE_CLASS_DUMMY_PARAMETER *)command -> ux_slave_class_command_parameter; + + /* Create dummy class instance. */ + dummy = (UX_DEVICE_CLASS_DUMMY *)_ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_DEVICE_CLASS_DUMMY)); + if (dummy == UX_NULL) + return(UX_MEMORY_INSUFFICIENT); + + /* Save the address of the Dummy instance inside the Dummy container. */ + class -> ux_slave_class_instance = (VOID *) dummy; + + /* Link to class instance. */ + dummy -> ux_device_class_dummy_class = class; + + /* Save parameters. */ + _ux_utility_memory_copy(&dummy -> ux_device_class_dummy_callbacks, + &dummy_parameter -> ux_device_class_dummy_parameter_callbacks, + sizeof(UX_DEVICE_CLASS_DUMMY_CALLBACKS)); + + if (dummy->ux_device_class_dummy_callbacks.ux_device_class_dummy_initialize) + dummy->ux_device_class_dummy_callbacks.ux_device_class_dummy_initialize(dummy); + + return(UX_SUCCESS); +} + +static UINT _ux_device_class_dummy_uninitialize(UX_SLAVE_CLASS_COMMAND *command) +{ + +UX_DEVICE_CLASS_DUMMY *dummy = NULL; +UX_SLAVE_CLASS *class; + + + /* Get the class container. */ + class = command -> ux_slave_class_command_class_ptr; + + /* Get the class instance in the container. */ + dummy = (UX_DEVICE_CLASS_DUMMY *) class -> ux_slave_class_instance; + + if (dummy->ux_device_class_dummy_callbacks.ux_device_class_dummy_uninitialize) + dummy->ux_device_class_dummy_callbacks.ux_device_class_dummy_uninitialize(dummy); + + if (dummy != UX_NULL) + _ux_utility_memory_free(dummy); + return(UX_SUCCESS); +} + +static UINT _ux_device_class_dummy_query(UX_SLAVE_CLASS_COMMAND *command) +{ + +UINT status = UX_SUCCESS; + + + return(status); +} + +static UINT _ux_device_class_dummy_activate(UX_SLAVE_CLASS_COMMAND *command) +{ + +UX_SLAVE_CLASS *class; +UX_SLAVE_DEVICE *device; +UX_SLAVE_INTERFACE *interface; +UX_DEVICE_CLASS_DUMMY *dummy; + + + /* Get the class container. */ + class = command -> ux_slave_class_command_class_ptr; + + /* Get the class instance in the container. */ + dummy = (UX_DEVICE_CLASS_DUMMY *) class -> ux_slave_class_instance; + + /* Get the interface that owns this instance. */ + interface = (UX_SLAVE_INTERFACE *) command -> ux_slave_class_command_interface; + dummy -> ux_device_class_dummy_interface = interface; + + /* Get the device instance. */ + device = &_ux_system_slave -> ux_system_slave_device; + dummy -> ux_device_class_dummy_device = device; + + /* If there is a activate function call it. */ + if (dummy -> ux_device_class_dummy_callbacks.ux_device_class_dummy_instance_activate) + dummy -> ux_device_class_dummy_callbacks.ux_device_class_dummy_instance_activate(dummy); + return(UX_SUCCESS); +} + +static UINT _ux_device_class_dummy_change(UX_SLAVE_CLASS_COMMAND *command) +{ + +UX_SLAVE_CLASS *class; +UX_SLAVE_INTERFACE *interface; +UX_DEVICE_CLASS_DUMMY *dummy; + + + /* Get the class container. */ + class = command -> ux_slave_class_command_class_ptr; + + /* Get the class instance in the container. */ + dummy = (UX_DEVICE_CLASS_DUMMY *) class -> ux_slave_class_instance; + + /* Get the interface that owns this instance. */ + interface = (UX_SLAVE_INTERFACE *) command -> ux_slave_class_command_interface; + + /* Update the interface. */ + dummy -> ux_device_class_dummy_interface = interface; + + /* Invoke change callback. */ + if (dummy -> ux_device_class_dummy_callbacks.ux_device_class_dummy_change) + dummy -> ux_device_class_dummy_callbacks.ux_device_class_dummy_change(dummy); + return(UX_SUCCESS); +} + +static UINT _ux_device_class_dummy_deactivate(UX_SLAVE_CLASS_COMMAND *command) +{ + +UX_SLAVE_CLASS *class; +UX_DEVICE_CLASS_DUMMY *dummy; + + + /* Get the class container. */ + class = command -> ux_slave_class_command_class_ptr; + + /* Get the class instance in the container. */ + dummy = (UX_DEVICE_CLASS_DUMMY *) class -> ux_slave_class_instance; + + /* If there is a deactivate function call it. */ + if (dummy -> ux_device_class_dummy_callbacks.ux_device_class_dummy_instance_deactivate) + dummy -> ux_device_class_dummy_callbacks.ux_device_class_dummy_instance_deactivate(dummy); + return(UX_SUCCESS); +} + +static UINT _ux_device_class_dummy_request(UX_SLAVE_CLASS_COMMAND *command) +{ + +UX_SLAVE_CLASS *class; +UX_DEVICE_CLASS_DUMMY *dummy; +UX_SLAVE_DEVICE *device; +UX_SLAVE_TRANSFER *transfer_request; + + + /* Get the class container. */ + class = command -> ux_slave_class_command_class_ptr; + + /* Get the audio instance from this class container. */ + dummy = (UX_DEVICE_CLASS_DUMMY *) class -> ux_slave_class_instance; + + /* Get the pointer to the device. */ + device = dummy -> ux_device_class_dummy_device; + + /* Get the pointer to the transfer request associated with the control endpoint. */ + transfer_request = &device -> ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request; + + /* Invoke callback. */ + if (dummy -> ux_device_class_dummy_callbacks.ux_device_class_dummy_control_request) + { + dummy -> ux_device_class_dummy_callbacks.ux_device_class_dummy_control_request(dummy, transfer_request); + return(UX_SUCCESS); + } + + /* By default, not handled, stall the endpoint. */ + _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint); + return(UX_SUCCESS); +} + +UINT _ux_device_class_dummy_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + +UINT status; + + + switch(command -> ux_slave_class_command_request) + { + + case UX_SLAVE_CLASS_COMMAND_INITIALIZE: + status = _ux_device_class_dummy_initialize(command); + break; + + case UX_SLAVE_CLASS_COMMAND_UNINITIALIZE: + status = _ux_device_class_dummy_uninitialize(command); + break; + + case UX_SLAVE_CLASS_COMMAND_QUERY: + status = _ux_device_class_dummy_query(command); + break; + + case UX_SLAVE_CLASS_COMMAND_ACTIVATE: + status = _ux_device_class_dummy_activate(command); + break; + + case UX_SLAVE_CLASS_COMMAND_CHANGE: + status = _ux_device_class_dummy_change(command); + break; + + case UX_SLAVE_CLASS_COMMAND_DEACTIVATE: + status = _ux_device_class_dummy_deactivate(command); + break; + + case UX_SLAVE_CLASS_COMMAND_REQUEST: + status = _ux_device_class_dummy_request(command); + break; + + default: + status = UX_FUNCTION_NOT_SUPPORTED; + break; + + } + return(status); +} + +VOID *_ux_device_class_dummy_get_arg(UX_DEVICE_CLASS_DUMMY *dummy) +{ + return dummy -> ux_device_class_dummy_callbacks.ux_device_class_dummy_arg; +} + +ULONG _ux_device_class_dummy_get_max_packet_size(UX_DEVICE_CLASS_DUMMY *dummy, UCHAR endpoint_address) +{ + +UX_SLAVE_ENDPOINT *endpoint = _ux_device_class_dummy_get_endpoint(dummy, endpoint_address); + + + if (endpoint == UX_NULL) + return 0; + return endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize; +} + +UX_SLAVE_ENDPOINT *_ux_device_class_dummy_get_endpoint(UX_DEVICE_CLASS_DUMMY *dummy, UCHAR endpoint_address) +{ + +UX_SLAVE_ENDPOINT *endpoint; +UX_SLAVE_INTERFACE *interface; + + if (dummy == UX_NULL) + return(UX_NULL); + if (endpoint_address == 0 || endpoint_address == 0x80) + return(&dummy -> ux_device_class_dummy_device -> ux_slave_device_control_endpoint); + + interface = dummy -> ux_device_class_dummy_interface; + if (interface == UX_NULL) + return((UX_SLAVE_ENDPOINT *)UX_NULL); + + endpoint = interface -> ux_slave_interface_first_endpoint; + while(endpoint) + { + if (endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress == endpoint_address) + break; + endpoint = endpoint -> ux_slave_endpoint_next_endpoint; + } + return endpoint; +} + +UX_SLAVE_TRANSFER *_ux_device_class_dummy_get_transfer_request(UX_DEVICE_CLASS_DUMMY *dummy, UCHAR endpoint_address) +{ + +UX_SLAVE_ENDPOINT *endpoint = _ux_device_class_dummy_get_endpoint(dummy, endpoint_address); + + + return &endpoint -> ux_slave_endpoint_transfer_request; +} + +UINT _ux_device_class_dummy_transfer(UX_DEVICE_CLASS_DUMMY *dummy, UCHAR endpoint_address, UCHAR *buffer, ULONG length, ULONG *actual_length) +{ + +UINT status; +UX_SLAVE_TRANSFER *transfer_request = _ux_device_class_dummy_get_transfer_request(dummy, endpoint_address); + + + if (transfer_request == UX_NULL) + return(UX_ERROR); + + if (length > UX_SLAVE_REQUEST_DATA_MAX_LENGTH) + length = UX_SLAVE_REQUEST_DATA_MAX_LENGTH; + + if (endpoint_address & 0x80) /* Device to host */ + { + if (length) + _ux_utility_memory_copy(transfer_request -> ux_slave_transfer_request_data_pointer, + buffer, length); + + status = _ux_device_stack_transfer_request(transfer_request, length, length); + } + + else /* Host to Device */ + { + status = _ux_device_stack_transfer_request(transfer_request, length, length); + + if (status == UX_SUCCESS && buffer != UX_NULL) + { + if (length) + _ux_utility_memory_copy(buffer, + transfer_request -> ux_slave_transfer_request_data_pointer, + length); + } + } + + if (actual_length) + *actual_length = transfer_request -> ux_slave_transfer_request_actual_length; + + return(status); +} diff --git a/test/regression/ux_device_class_dummy.h b/test/regression/ux_device_class_dummy.h new file mode 100644 index 00000000..924d49b4 --- /dev/null +++ b/test/regression/ux_device_class_dummy.h @@ -0,0 +1,53 @@ + +#ifndef UX_DEVICE_CLASS_DUMMY_H +#define UX_DEVICE_CLASS_DUMMY_H + +/* Define Data Pump Class instance structure. */ + +struct UX_DEVICE_CLASS_DUMMY_STRUCT; +typedef struct UX_DEVICE_CLASS_DUMMY_CALLBACKS_STRUCT +{ + VOID (*ux_device_class_dummy_initialize)(VOID *); + VOID (*ux_device_class_dummy_uninitialize)(VOID *); + + VOID (*ux_device_class_dummy_instance_activate)(VOID *); + VOID (*ux_device_class_dummy_instance_deactivate)(VOID *); + + VOID (*ux_device_class_dummy_change)(struct UX_DEVICE_CLASS_DUMMY_STRUCT *); + VOID (*ux_device_class_dummy_control_request)(struct UX_DEVICE_CLASS_DUMMY_STRUCT *, UX_SLAVE_TRANSFER *); + + VOID *ux_device_class_dummy_arg; +} UX_DEVICE_CLASS_DUMMY_CALLBACKS; + +typedef struct UX_DEVICE_CLASS_DUMMY_PARAMETER_STRUCT +{ + UX_DEVICE_CLASS_DUMMY_CALLBACKS ux_device_class_dummy_parameter_callbacks; +} UX_DEVICE_CLASS_DUMMY_PARAMETER; + +typedef struct UX_DEVICE_CLASS_DUMMY_STRUCT +{ + + UX_SLAVE_CLASS *ux_device_class_dummy_class; + UX_SLAVE_DEVICE *ux_device_class_dummy_device; + UX_SLAVE_INTERFACE *ux_device_class_dummy_interface; + + VOID *ux_device_class_dummy_instance; + + UX_DEVICE_CLASS_DUMMY_CALLBACKS ux_device_class_dummy_callbacks; +} UX_DEVICE_CLASS_DUMMY; + +extern UCHAR _ux_device_class_dummy_name[]; + +UINT _ux_device_class_dummy_entry(UX_SLAVE_CLASS_COMMAND *command); + +VOID *_ux_device_class_dummy_get_arg(UX_DEVICE_CLASS_DUMMY *dummy); + +UX_SLAVE_ENDPOINT *_ux_device_class_dummy_get_endpoint(UX_DEVICE_CLASS_DUMMY *dummy, UCHAR endpoint_address); +UX_SLAVE_TRANSFER *_ux_device_class_dummy_get_transfer_request(UX_DEVICE_CLASS_DUMMY *dummy, UCHAR endpoint_address); + +ULONG _ux_device_class_dummy_get_max_packet_size(UX_DEVICE_CLASS_DUMMY *dummy, UCHAR endpoint_address); + +UINT _ux_device_class_dummy_transfer(UX_DEVICE_CLASS_DUMMY *dummy, UCHAR endpoint_address, UCHAR *buffer, ULONG length, ULONG *actual_length); +UINT _ux_device_class_dummy_abort(UX_DEVICE_CLASS_DUMMY *dummy, UCHAR endpoint_address); + +#endif diff --git a/test/regression/ux_device_class_dummy_hub.c b/test/regression/ux_device_class_dummy_hub.c new file mode 100644 index 00000000..1bca5c20 --- /dev/null +++ b/test/regression/ux_device_class_dummy_hub.c @@ -0,0 +1,387 @@ +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_device_stack.h" +#include "ux_test.h" +#include "ux_host_class_hub.h" +#include "ux_device_class_dummy_hub.h" + +#define PORT_START 1 +#define PORT_STATUS_PORT_POWER_BIT 8 + +UCHAR _ux_device_class_hub_name[] = "_ux_device_class_hub_name"; + +static VOID _ux_device_class_hub_thread_entry(ULONG param) +{ +UX_DEVICE_CLASS_HUB *hub; +UX_SLAVE_CLASS *hub_class; +UX_SLAVE_ENDPOINT *endpoint; +UX_SLAVE_TRANSFER *transfer; +UINT status; + UX_THREAD_EXTENSION_PTR_GET(hub_class ,UX_SLAVE_CLASS, param); + hub = (UX_DEVICE_CLASS_HUB *)hub_class->ux_slave_class_instance; + while(1) + { + endpoint = hub->interrupt_endpoint; + if (endpoint) + { + transfer = &endpoint->ux_slave_endpoint_transfer_request; + status = _ux_device_stack_transfer_request(transfer, + transfer -> ux_slave_transfer_request_requested_length, + transfer -> ux_slave_transfer_request_requested_length); + _ux_utility_memory_set(transfer->ux_slave_transfer_request_data_pointer, 0, transfer->ux_slave_transfer_request_transfer_length); + } + _ux_device_thread_suspend(&hub->hub_thread); + } +} + +static VOID _ux_device_class_hub_initialize(UX_SLAVE_CLASS_COMMAND *command) +{ + +UX_SLAVE_CLASS *hub_class = (UX_SLAVE_CLASS *)command->ux_slave_class_command_class_ptr; +UX_DEVICE_CLASS_HUB_PARAMS *hub_params = (UX_DEVICE_CLASS_HUB_PARAMS *)command->ux_slave_class_command_parameter; +UX_DEVICE_CLASS_HUB *hub; + + hub = (UX_DEVICE_CLASS_HUB *) _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_DEVICE_CLASS_HUB)); + UX_TEST_ASSERT(hub != UX_NULL); + + hub_class->ux_slave_class_instance = hub; + hub->hub_class = hub_class; + + hub->hub_thread_stack = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, UX_THREAD_STACK_SIZE); + UX_TEST_ASSERT(hub->hub_thread_stack != UX_NULL); + UX_TEST_CHECK_SUCCESS(_ux_device_thread_create( + &hub->hub_thread, "hub_thread", + _ux_device_class_hub_thread_entry, (ULONG)(ALIGN_TYPE)hub_class, + hub->hub_thread_stack, UX_THREAD_STACK_SIZE, + 30, 30, 0, UX_DONT_START)); + UX_THREAD_EXTENSION_PTR_SET(&hub->hub_thread, hub_class); + + /* Save parameters. */ + _ux_utility_memory_copy(&hub->params, hub_params, sizeof(*hub_params)); +} + +static VOID _ux_device_class_hub_uninitialize(UX_SLAVE_CLASS_COMMAND *command) +{ +} +VOID _ux_device_class_hub_notify_changes(UX_DEVICE_CLASS_HUB *hub, UCHAR *changes, UINT rpt_size) +{ +UX_SLAVE_ENDPOINT *endpoint; +UX_SLAVE_TRANSFER *transfer; +UCHAR *buff; + endpoint = hub->interrupt_endpoint; + if (endpoint == UX_NULL || rpt_size == 0) + return; + transfer = &endpoint->ux_slave_endpoint_transfer_request; + buff = transfer->ux_slave_transfer_request_data_pointer; + if (rpt_size > transfer->ux_slave_transfer_request_transfer_length) + rpt_size = transfer->ux_slave_transfer_request_transfer_length; + transfer -> ux_slave_transfer_request_requested_length = rpt_size; + _ux_utility_memory_copy(buff, changes, rpt_size); + tx_thread_resume(&hub->hub_thread); +} +VOID _ux_device_class_hub_notify_change(UX_DEVICE_CLASS_HUB *hub, UINT change_pos, UINT rpt_size) +{ +UX_SLAVE_ENDPOINT *endpoint; +UX_SLAVE_TRANSFER *transfer; +UCHAR *buff; +UINT byte_pos, bit_pos; + endpoint = hub->interrupt_endpoint; + if (endpoint == UX_NULL || rpt_size == 0) + return; + transfer = &endpoint->ux_slave_endpoint_transfer_request; + buff = transfer->ux_slave_transfer_request_data_pointer; + byte_pos = change_pos >> 3; + bit_pos = change_pos & 0x7u; + if (rpt_size >= transfer->ux_slave_transfer_request_transfer_length) + rpt_size = transfer->ux_slave_transfer_request_transfer_length; + if (byte_pos >= rpt_size) + return; + buff[byte_pos] |= 1u << bit_pos; + transfer -> ux_slave_transfer_request_requested_length = rpt_size; + tx_thread_resume(&hub->hub_thread); +} + +static UINT _ux_device_class_hub_activate(UX_SLAVE_CLASS_COMMAND *command) +{ + +UX_SLAVE_CLASS *hub_class = command->ux_slave_class_command_class_ptr; +UX_SLAVE_INTERFACE *interface = (UX_SLAVE_INTERFACE *)command->ux_slave_class_command_interface; +UX_SLAVE_ENDPOINT *endpoint; +UX_SLAVE_TRANSFER *transfer; +UX_DEVICE_CLASS_HUB *hub; +UINT i; + + hub = (UX_DEVICE_CLASS_HUB *)hub_class->ux_slave_class_instance; + + /* Our dummy hub has one port. When the host sends the SetPortFeature request, + wIndex contains the port number, which is 1-based. USBX uses wIndex to + pick which class/interface to send the command to. The problem is that + in this case, wIndex is not an interface number! So we have to manually + link the port number (1 in this case) to this class. We just set every + entry since we don't expect there to be any other classes registered. + If we do start expecting that, then we'll handle it then (as opposed to now). */ + for (i = 0; i < UX_MAX_SLAVE_INTERFACES; i++) + { + _ux_system_slave->ux_system_slave_interface_class_array[i] = hub_class; + } + + /* We need to get the interrupt in endpoint. */ + endpoint = interface->ux_slave_interface_first_endpoint; + while (endpoint) + { + /* Is this interrupt in? */ + if (endpoint->ux_slave_endpoint_descriptor.bmAttributes == 0x03 && + (endpoint->ux_slave_endpoint_descriptor.bEndpointAddress & 0x80) == 0x80) + { + /* Found it. */ + break; + } + + endpoint = endpoint->ux_slave_endpoint_next_endpoint; + } + /* Note that we don't always expect there to be an endpoint since some tests + depend on no endpoint. */ + if (endpoint) + { + hub->interrupt_endpoint = endpoint; + + /* If there is interrupt endpoint, create notify thread for notification support. */ + if (endpoint != UX_NULL) + { + transfer = &endpoint->ux_slave_endpoint_transfer_request; + transfer->ux_slave_transfer_request_data_pointer = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY, transfer->ux_slave_transfer_request_transfer_length); + if(transfer->ux_slave_transfer_request_data_pointer == UX_NULL) + return(UX_MEMORY_INSUFFICIENT); + } + } + + if (hub->params.instance_activate) + { + hub->params.instance_activate(hub); + } + return(UX_SUCCESS); +} + +static VOID _ux_device_class_hub_deactivate(UX_SLAVE_CLASS_COMMAND *command) +{ + +UX_SLAVE_CLASS *hub_class = command->ux_slave_class_command_class_ptr; +UX_DEVICE_CLASS_HUB *hub; + + hub = (UX_DEVICE_CLASS_HUB *)hub_class->ux_slave_class_instance; + if (hub->interrupt_endpoint) + { + _ux_device_stack_transfer_abort(&hub->interrupt_endpoint->ux_slave_endpoint_transfer_request, UX_TRANSFER_BUS_RESET); + _ux_utility_memory_free(hub->interrupt_endpoint->ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer); + } + + if (hub->params.instance_deactivate) + { + hub->params.instance_deactivate(hub); + } +} + +static VOID _ux_device_class_hub_change(UX_SLAVE_CLASS_COMMAND *command) +{ + UX_TEST_ASSERT(0); +} + +static VOID _ux_device_class_hub_control_request(UX_SLAVE_CLASS_COMMAND *command) +{ + +UCHAR *setup_data; +UCHAR bmRequestType; +UCHAR bRequest; +USHORT wValue; +USHORT wIndex; +USHORT wLength; +UCHAR port_index; +UCHAR descriptor_type; +UCHAR *data_ptr; +UX_SLAVE_DEVICE *device; +UX_SLAVE_TRANSFER *transfer_request; +UX_SLAVE_CLASS *hub_class = (UX_SLAVE_CLASS *)command->ux_slave_class_command_class_ptr; +UX_DEVICE_CLASS_HUB *dummy_hub = (UX_DEVICE_CLASS_HUB *)hub_class->ux_slave_class_instance; + + /* Get the pointer to the device. */ + device = &_ux_system_slave->ux_system_slave_device; + + /* Get the pointer to the transfer request associated with the control endpoint. */ + transfer_request = &device->ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request; + + setup_data = transfer_request->ux_slave_transfer_request_setup; + bmRequestType = setup_data[0]; + bRequest = setup_data[1]; + wValue = (USHORT)_ux_utility_short_get(&setup_data[2]); + wIndex = (USHORT)_ux_utility_short_get(&setup_data[4]); + wLength = (USHORT)_ux_utility_short_get(&setup_data[6]); + + data_ptr = transfer_request->ux_slave_transfer_request_data_pointer; + + switch (bRequest) + { + + case UX_SET_FEATURE: + + /* Get the port. */ + port_index = (UCHAR) (wValue & 0x00ff); + + /* What feature? */ + switch (wValue) + { + + case UX_HOST_CLASS_HUB_PORT_RESET: + + if (!dummy_hub->dont_reset_port_when_commanded_to) + { + + /* Tell the host we reset. */ + dummy_hub->port_change |= UX_HOST_CLASS_HUB_PORT_CHANGE_RESET; + _ux_device_class_hub_notify_change(dummy_hub, 1, 1); + } + + /* Note that the speed is in port_status, and should've been + set by the application. */ + + break; + + case UX_HOST_CLASS_HUB_PORT_POWER: + + /* Do nothing. */ + break; + + default: + + UX_TEST_ASSERT(0); + break; + } + + break; + + case UX_CLEAR_FEATURE: + + /* What feature? */ + switch (wValue) + { + + case UX_HOST_CLASS_HUB_C_PORT_RESET: + + /* Clear it. */ + dummy_hub->port_change &= (~UX_HOST_CLASS_HUB_PORT_CHANGE_RESET); + + break; + + case UX_HOST_CLASS_HUB_C_PORT_ENABLE: + + /* Clear it. */ + dummy_hub->port_change &= (~UX_HOST_CLASS_HUB_PORT_CHANGE_ENABLE); + + break; + + case UX_HOST_CLASS_HUB_C_PORT_SUSPEND: + + /* Clear it. */ + dummy_hub->port_change &= (~UX_HOST_CLASS_HUB_PORT_CHANGE_SUSPEND); + + break; + + case UX_HOST_CLASS_HUB_C_PORT_OVER_CURRENT: + + /* Clear it. */ + dummy_hub->port_change &= (~UX_HOST_CLASS_HUB_PORT_CHANGE_OVER_CURRENT); + + break; + + case UX_HOST_CLASS_HUB_C_PORT_CONNECTION: + + /* Clear it. */ + dummy_hub->port_change &= (~UX_HOST_CLASS_HUB_PORT_CHANGE_CONNECTION); + break; + + case UX_HOST_CLASS_HUB_PORT_ENABLE: + + /* Do nothing. */ + break; + + default: + + UX_TEST_ASSERT(0); + break; + } + + break; + + case UX_HOST_CLASS_HUB_GET_STATUS: + + /* Setup the data. */ + *((USHORT *)&data_ptr[0]) = dummy_hub->port_status; + *((USHORT *)&data_ptr[2]) = dummy_hub->port_change; + + UX_TEST_CHECK_SUCCESS(_ux_device_stack_transfer_request(transfer_request, UX_HUB_DESCRIPTOR_LENGTH, UX_HUB_DESCRIPTOR_LENGTH)); + + break; + + case UX_GET_DESCRIPTOR: + + /* Ensure this is for the hub descriptor and send it. */ + + descriptor_type = (wValue & 0xff00) >> 8; + UX_TEST_ASSERT(descriptor_type == UX_HUB_DESCRIPTOR_ITEM); + UX_TEST_ASSERT(wLength == UX_HUB_DESCRIPTOR_LENGTH); + + _ux_utility_memory_copy(transfer_request->ux_slave_transfer_request_data_pointer, dummy_hub->params.descriptor, dummy_hub->params.descriptor_length); + + UX_TEST_CHECK_SUCCESS(_ux_device_stack_transfer_request(transfer_request, UX_HUB_DESCRIPTOR_LENGTH, UX_HUB_DESCRIPTOR_LENGTH)); + + break; + + default: + + UX_TEST_ASSERT(0); + break; + } +} + +UINT _ux_device_class_hub_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + + switch(command -> ux_slave_class_command_request) + { + + case UX_SLAVE_CLASS_COMMAND_INITIALIZE: + _ux_device_class_hub_initialize(command); + break; + + case UX_SLAVE_CLASS_COMMAND_UNINITIALIZE: + _ux_device_class_hub_uninitialize(command); + break; + + case UX_SLAVE_CLASS_COMMAND_QUERY: + /* For now, always return success. */ + break; + + case UX_SLAVE_CLASS_COMMAND_ACTIVATE: + return _ux_device_class_hub_activate(command); + + case UX_SLAVE_CLASS_COMMAND_CHANGE: + UX_TEST_ASSERT(0); + break; + + case UX_SLAVE_CLASS_COMMAND_DEACTIVATE: + _ux_device_class_hub_deactivate(command); + break; + + case UX_SLAVE_CLASS_COMMAND_REQUEST: + _ux_device_class_hub_control_request(command); + break; + + default: + UX_TEST_ASSERT(0); + break; + + } + return(UX_SUCCESS); +} diff --git a/test/regression/ux_device_class_dummy_hub.h b/test/regression/ux_device_class_dummy_hub.h new file mode 100644 index 00000000..c0860e36 --- /dev/null +++ b/test/regression/ux_device_class_dummy_hub.h @@ -0,0 +1,49 @@ +#ifndef UX_DEVICE_CLASS_DUMMY_HUB_H +#define UX_DEVICE_CLASS_DUMMY_HUB_H + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_device_stack.h" +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test.h" +#include "ux_device_class_dummy.h" +#include "ux_host_class_hub.h" + +typedef struct UX_DEVICE_CLASS_HUB_PARAMS_STRUCT +{ + UCHAR *descriptor; + ULONG descriptor_length; + + VOID (*instance_activate)(VOID *); + VOID (*instance_deactivate)(VOID *); +} UX_DEVICE_CLASS_HUB_PARAMS; + +typedef struct UX_DEVICE_CLASS_HUB_STRUCT +{ + UX_SLAVE_CLASS *hub_class; + UX_SLAVE_ENDPOINT *interrupt_endpoint; + + /* Test dummy not depends on standalone switch. */ + TX_THREAD hub_thread; + UCHAR *hub_thread_stack; + + ULONG status_change_bitmap; + USHORT port_status; + USHORT port_change; + + UCHAR dont_reset_port_when_commanded_to; + + UX_DEVICE_CLASS_HUB_PARAMS params; +} UX_DEVICE_CLASS_HUB; + +extern UCHAR _ux_device_class_hub_name[]; + +UINT _ux_device_class_hub_entry(UX_SLAVE_CLASS_COMMAND *); +VOID _ux_device_class_hub_notify_changes(UX_DEVICE_CLASS_HUB *hub, UCHAR *changes, UINT rpt_size); +VOID _ux_device_class_hub_notify_change(UX_DEVICE_CLASS_HUB *hub, UINT change_pos, UINT rpt_size); + +#endif \ No newline at end of file diff --git a/test/regression/ux_device_class_dummy_printer.c b/test/regression/ux_device_class_dummy_printer.c new file mode 100644 index 00000000..a5667ca0 --- /dev/null +++ b/test/regression/ux_device_class_dummy_printer.c @@ -0,0 +1,263 @@ +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_device_stack.h" +#include "ux_test.h" +#include "ux_host_class_printer.h" +#include "ux_device_class_dummy_printer.h" + +#define PORT_START 1 +#define PORT_STATUS_PORT_POWER_BIT 8 + +UCHAR _ux_device_class_printer_name[] = "_ux_device_class_printer"; + +static VOID _ux_device_class_printer_initialize(UX_SLAVE_CLASS_COMMAND *command) +{ + +UX_SLAVE_CLASS *printer_class = (UX_SLAVE_CLASS *)command->ux_slave_class_command_class_ptr; +UX_DEVICE_CLASS_PRINTER_PARAMS *printer_params = (UX_DEVICE_CLASS_PRINTER_PARAMS *)command->ux_slave_class_command_parameter; +UX_DEVICE_CLASS_PRINTER *printer; + + printer = (UX_DEVICE_CLASS_PRINTER *) _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_DEVICE_CLASS_PRINTER)); + UX_TEST_ASSERT(printer != UX_NULL); + + printer_class->ux_slave_class_instance = printer; + + /* Save parameters. */ + _ux_utility_memory_copy(&printer->params, printer_params, sizeof(*printer_params)); +} + +static VOID _ux_device_class_printer_uninitialize(UX_SLAVE_CLASS_COMMAND *command) +{ +UX_DEVICE_CLASS_PRINTER *printer = NULL; +UX_SLAVE_CLASS *class; + + + /* Get the class container. */ + class = command -> ux_slave_class_command_class_ptr; + + /* Get the class instance in the container. */ + printer = (UX_DEVICE_CLASS_PRINTER *) class -> ux_slave_class_instance; + + if (printer != UX_NULL) + _ux_utility_memory_free(printer); + return; +} + +static UINT _ux_device_class_printer_activate(UX_SLAVE_CLASS_COMMAND *command) +{ + +UX_SLAVE_CLASS *printer_class = command->ux_slave_class_command_class_ptr; +UX_SLAVE_INTERFACE *interface = (UX_SLAVE_INTERFACE *)command->ux_slave_class_command_interface; +UX_SLAVE_ENDPOINT *endpoint; +UX_DEVICE_CLASS_PRINTER *printer; +UINT i; + + printer = (UX_DEVICE_CLASS_PRINTER *)printer_class->ux_slave_class_instance; + interface -> ux_slave_interface_class_instance = (VOID *)printer; + printer -> interface = interface; + + /* We need to get the bulk endpoints. */ + printer -> bulk_in_endpoint = UX_NULL; + printer -> bulk_out_endpoint = UX_NULL; + endpoint = interface->ux_slave_interface_first_endpoint; + while (endpoint) + { + /* Is this bulk endpoint? */ + if (endpoint->ux_slave_endpoint_descriptor.bmAttributes == UX_BULK_ENDPOINT) + { + /* Is this endpoint IN? */ + if (endpoint->ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_IN) + { + printer -> bulk_in_endpoint = endpoint; + if (printer -> bulk_out_endpoint) + break; + } + else + { + printer -> bulk_out_endpoint = endpoint; + if (printer -> bulk_in_endpoint) + break; + } + } + endpoint = endpoint->ux_slave_endpoint_next_endpoint; + } + /* Endpoints must be available. */ + if (printer->bulk_in_endpoint == UX_NULL || printer->bulk_out_endpoint == UX_NULL) + return(UX_ERROR); + /* Invoke activate callback. */ + if (printer->params.instance_activate) + { + printer->params.instance_activate(printer); + } + return(UX_SUCCESS); +} + +static VOID _ux_device_class_printer_deactivate(UX_SLAVE_CLASS_COMMAND *command) +{ + +UX_SLAVE_CLASS *printer_class = command->ux_slave_class_command_class_ptr; +UX_DEVICE_CLASS_PRINTER *printer; + + printer = (UX_DEVICE_CLASS_PRINTER *)printer_class->ux_slave_class_instance; + _ux_device_stack_transfer_all_request_abort(printer->bulk_in_endpoint, UX_TRANSFER_BUS_RESET); + _ux_device_stack_transfer_all_request_abort(printer->bulk_out_endpoint, UX_TRANSFER_BUS_RESET); + if (printer->params.instance_deactivate) + { + printer->params.instance_deactivate(printer); + } +} + +static VOID _ux_device_class_printer_change(UX_SLAVE_CLASS_COMMAND *command) +{ + UX_TEST_ASSERT(0); +} + +static UINT _configure_index_value(ULONG index) +{ +UCHAR *descriptor; +ULONG configuration_index; +ULONG length; +UCHAR type; + descriptor = _ux_system_slave->ux_system_slave_device_framework; + configuration_index = 0; + while(1) + { + length = descriptor[0]; + type = descriptor[1]; + + if (type == UX_CONFIGURATION_DESCRIPTOR_ITEM) + { + if (configuration_index == index) + return(descriptor[5]); + /* Length is total length. */ + length = _ux_utility_short_get(&descriptor[2]); + /* Next configuration. */ + configuration_index ++; + } + + /* Next descriptor. */ + descriptor += length; + } +} + +static UINT _ux_device_class_printer_control_request(UX_SLAVE_CLASS_COMMAND *command) +{ + +UCHAR *setup_data; +UCHAR bmRequestType; +UCHAR bRequest; +USHORT wValue; +USHORT wIndex; +USHORT wLength; +UCHAR port_index; +UCHAR descriptor_type; +UCHAR *data_ptr; +UX_SLAVE_DEVICE *device; +UX_SLAVE_TRANSFER *transfer_request; +UX_SLAVE_CLASS *printer_class = (UX_SLAVE_CLASS *)command->ux_slave_class_command_class_ptr; +UX_DEVICE_CLASS_PRINTER *printer = (UX_DEVICE_CLASS_PRINTER *)printer_class->ux_slave_class_instance; +UX_SLAVE_INTERFACE *interface=printer->interface; +ULONG length; + + /* Get the pointer to the device. */ + device = &_ux_system_slave->ux_system_slave_device; + + /* Get the pointer to the transfer request associated with the control endpoint. */ + transfer_request = &device->ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request; + + setup_data = transfer_request->ux_slave_transfer_request_setup; + bmRequestType = setup_data[0]; + bRequest = setup_data[1]; + wValue = (USHORT)_ux_utility_short_get(&setup_data[2]); + wIndex = (USHORT)_ux_utility_short_get(&setup_data[4]); + wLength = (USHORT)_ux_utility_short_get(&setup_data[6]); + + data_ptr = transfer_request->ux_slave_transfer_request_data_pointer; + + switch (bRequest) + { + case UX_HOST_CLASS_PRINTER_GET_DEVICE_ID: + /* Check configuration INDEX (wValue), interface (HIGH wIndex), alt (LOW wIndex). */ + if (_configure_index_value(wValue) != interface->ux_slave_interface_class->ux_slave_class_configuration_number || + setup_data[4] != interface->ux_slave_interface_descriptor.bAlternateSetting || + setup_data[5] != interface->ux_slave_interface_descriptor.bInterfaceNumber) + return(UX_ERROR); + /* Send device ID. */ + transfer_request->ux_slave_transfer_request_phase = UX_TRANSFER_PHASE_DATA_OUT; + length = UX_MIN(UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH, wLength); + length = UX_MIN(length, printer->params.device_id_length + 2); + if (length) + { + _ux_utility_short_put_big_endian(data_ptr, length - 2); + _ux_utility_memory_copy(data_ptr + 2, printer->params.device_id, length - 2); + } + return _ux_device_stack_transfer_request(transfer_request, length, wLength); + + case UX_HOST_CLASS_PRINTER_GET_STATUS: + /* Check interface number. */ + if (wIndex != interface->ux_slave_interface_descriptor.bInterfaceNumber) + return(UX_ERROR); + /* Send status. */ + transfer_request->ux_slave_transfer_request_phase = UX_TRANSFER_PHASE_DATA_OUT; + *data_ptr = printer->port_status; + return _ux_device_stack_transfer_request(transfer_request, 1, wLength); + + case UX_HOST_CLASS_PRINTER_SOFT_RESET: + /* Check interface number. */ + if (wIndex != interface->ux_slave_interface_descriptor.bInterfaceNumber) + return(UX_ERROR); + /* Execute soft reset. */ + _ux_device_stack_transfer_all_request_abort(printer->bulk_in_endpoint, UX_TRANSFER_BUS_RESET); + _ux_device_stack_transfer_all_request_abort(printer->bulk_out_endpoint, UX_TRANSFER_BUS_RESET); + printer->soft_reset = UX_TRUE; + return(UX_SUCCESS); + + default: + + UX_TEST_ASSERT(0); + break; + } +} + +UINT _ux_device_class_printer_entry(UX_SLAVE_CLASS_COMMAND *command) +{ + + switch(command -> ux_slave_class_command_request) + { + + case UX_SLAVE_CLASS_COMMAND_INITIALIZE: + _ux_device_class_printer_initialize(command); + break; + + case UX_SLAVE_CLASS_COMMAND_UNINITIALIZE: + _ux_device_class_printer_uninitialize(command); + break; + + case UX_SLAVE_CLASS_COMMAND_QUERY: + /* For now, always return success. */ + break; + + case UX_SLAVE_CLASS_COMMAND_ACTIVATE: + return _ux_device_class_printer_activate(command); + + case UX_SLAVE_CLASS_COMMAND_CHANGE: + UX_TEST_ASSERT(0); + break; + + case UX_SLAVE_CLASS_COMMAND_DEACTIVATE: + _ux_device_class_printer_deactivate(command); + break; + + case UX_SLAVE_CLASS_COMMAND_REQUEST: + return _ux_device_class_printer_control_request(command); + + default: + UX_TEST_ASSERT(0); + break; + + } + return(UX_SUCCESS); +} diff --git a/test/regression/ux_device_class_dummy_printer.h b/test/regression/ux_device_class_dummy_printer.h new file mode 100644 index 00000000..e51adf3d --- /dev/null +++ b/test/regression/ux_device_class_dummy_printer.h @@ -0,0 +1,41 @@ +#ifndef UX_DEVICE_CLASS_DUMMY_PRINTER_H +#define UX_DEVICE_CLASS_DUMMY_PRINTER_H + +#include +#include "tx_api.h" +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_device_stack.h" +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test.h" +#include "ux_device_class_dummy.h" +#include "ux_host_class_printer.h" + +typedef struct UX_DEVICE_CLASS_PRINTER_PARAMS_STRUCT +{ + UCHAR *device_id; + ULONG device_id_length; + + VOID (*instance_activate)(VOID *); + VOID (*instance_deactivate)(VOID *); +} UX_DEVICE_CLASS_PRINTER_PARAMS; + +typedef struct UX_DEVICE_CLASS_PRINTER_STRUCT +{ + UX_SLAVE_INTERFACE *interface; + UX_SLAVE_ENDPOINT *bulk_in_endpoint; + UX_SLAVE_ENDPOINT *bulk_out_endpoint; + UX_DEVICE_CLASS_PRINTER_PARAMS params; + UCHAR port_status; + UCHAR soft_reset; + UCHAR reserved[2]; + +} UX_DEVICE_CLASS_PRINTER; + +extern UCHAR _ux_device_class_printer_name[]; + +UINT _ux_device_class_printer_entry(UX_SLAVE_CLASS_COMMAND *); + +#endif \ No newline at end of file diff --git a/test/regression/ux_host_class_dummy.c b/test/regression/ux_host_class_dummy.c new file mode 100644 index 00000000..c4e963e0 --- /dev/null +++ b/test/regression/ux_host_class_dummy.c @@ -0,0 +1,555 @@ + +#include "ux_test.h" +#include "ux_api.h" +#include "ux_host_class_dummy.h" +#include "ux_host_stack.h" + +static UINT _ux_host_class_dummy_activate(UX_HOST_CLASS_COMMAND *command); +static UINT _ux_host_class_dummy_deactivate(UX_HOST_CLASS_COMMAND *command); + +static UINT _ux_host_class_dummy_device_activate(UX_HOST_CLASS_COMMAND *command); +static UINT _ux_host_class_dummy_device_deactivate(UX_HOST_CLASS_COMMAND *command); + +UCHAR _ux_host_class_dummy_name[] = "ux_host_class_dummy"; + +static UX_HOST_CLASS_DUMMY_QUERY *_ux_host_class_dummy_query_list; + +static UCHAR _ux_host_class_dummy_query_reject_unknown = UX_FALSE; + +VOID _ux_host_class_dummy_query_reject_unknown_set(UCHAR yes_no) +{ + _ux_host_class_dummy_query_reject_unknown = yes_no; +} + +VOID _ux_host_class_dummy_query_list_set(UX_HOST_CLASS_DUMMY_QUERY *query_list) +{ + _ux_host_class_dummy_query_list = query_list; +} + +UINT _ux_host_class_dummy_command_query_list_check(UX_HOST_CLASS_COMMAND *command) +{ +UX_HOST_CLASS_DUMMY_QUERY *query; + if (_ux_host_class_dummy_query_list == UX_NULL) + return(UX_NO_CLASS_MATCH); + query = _ux_host_class_dummy_query_list; + while(query -> ux_host_class_query_on) + { + if (query -> ux_host_class_query_entry != 0 && + query -> ux_host_class_query_entry != + command -> ux_host_class_command_class_ptr -> ux_host_class_entry_function) + { + query ++; + continue; + } + if (query -> ux_host_class_query_usage != 0 && + query -> ux_host_class_query_usage != command -> ux_host_class_command_usage) + { + query ++; + continue; + } + if (query -> ux_host_class_query_vid != 0 && + query -> ux_host_class_query_vid != command -> ux_host_class_command_vid) + { + query ++; + continue; + } + if (query -> ux_host_class_query_pid != 0 && + query -> ux_host_class_query_pid != command -> ux_host_class_command_pid) + { + query ++; + continue; + } + if (query -> ux_host_class_query_class != 0 && + query -> ux_host_class_query_class != command -> ux_host_class_command_class) + { + query ++; + continue; + } + if (query -> ux_host_class_query_subclass != 0 && + query -> ux_host_class_query_subclass != command -> ux_host_class_command_subclass) + { + query ++; + continue; + } + if (query -> ux_host_class_query_protocol != 0 && + query -> ux_host_class_query_protocol != command -> ux_host_class_command_protocol) + { + query ++; + continue; + } + if (query -> ux_host_class_query_iad_class != 0 && + query -> ux_host_class_query_iad_class != command -> ux_host_class_command_iad_class) + { + query ++; + continue; + } + if (query -> ux_host_class_query_iad_subclass != 0 && + query -> ux_host_class_query_iad_subclass != command -> ux_host_class_command_iad_subclass) + { + query ++; + continue; + } + if (query -> ux_host_class_query_iad_protocol != 0 && + query -> ux_host_class_query_iad_protocol != command -> ux_host_class_command_iad_protocol) + { + query ++; + continue; + } + return(UX_SUCCESS); + } + return(UX_NO_CLASS_MATCH); +} + +UINT _ux_host_class_dummy_entry(UX_HOST_CLASS_COMMAND *command) +{ + + /* The command request will tell us we need to do here, either a enumeration + query, an activation or a deactivation. */ + switch (command -> ux_host_class_command_request) + { + + case UX_HOST_CLASS_COMMAND_QUERY: + if (_ux_host_class_dummy_command_query_list_check(command) == UX_SUCCESS) + return(UX_SUCCESS); + + /* Only for interface : class subclass protocol. */ + if (command -> ux_host_class_command_usage != UX_HOST_CLASS_COMMAND_USAGE_CSP) + return(UX_NO_CLASS_MATCH); + + /* Skip undefined or composite. */ + if (command -> ux_host_class_command_class == 0 || + command -> ux_host_class_command_class == 0xFE) + return(UX_NO_CLASS_MATCH); + + if (!_ux_host_class_dummy_query_reject_unknown) + return(UX_SUCCESS); + return(UX_NO_CLASS_MATCH); + + case UX_HOST_CLASS_COMMAND_ACTIVATE: + return _ux_host_class_dummy_activate(command); + + /* Standalone activate wait support. */ + case UX_HOST_CLASS_COMMAND_ACTIVATE_WAIT: + return (UX_STATE_NEXT); + + case UX_HOST_CLASS_COMMAND_DEACTIVATE: + return _ux_host_class_dummy_deactivate(command); + + default: + + /* Error trap. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_FUNCTION_NOT_SUPPORTED); + + /* If trace is enabled, insert this event into the trace buffer. */ + UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_FUNCTION_NOT_SUPPORTED, 0, 0, 0, UX_TRACE_ERRORS, 0, 0) + + return(UX_FUNCTION_NOT_SUPPORTED); + } +} + +UINT _ux_host_class_dummy_activate(UX_HOST_CLASS_COMMAND *command) +{ + +UX_INTERFACE *interface; +UX_ENDPOINT *endpoint; +UX_HOST_CLASS_DUMMY *dummy; + + + interface = (UX_INTERFACE *) command -> ux_host_class_command_container; + dummy = (UX_HOST_CLASS_DUMMY *)_ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_HOST_CLASS_DUMMY)); + if (dummy == UX_NULL) + return(UX_MEMORY_INSUFFICIENT); + + dummy -> ux_host_class_dummy_class = command -> ux_host_class_command_class_ptr; + dummy -> ux_host_class_dummy_interface = interface; + dummy -> ux_host_class_dummy_device = UX_NULL; + interface -> ux_interface_class_instance = (VOID *)dummy; + + _ux_host_stack_class_instance_create(dummy -> ux_host_class_dummy_class, (VOID *)dummy); + + endpoint = interface -> ux_interface_first_endpoint; + while(endpoint) + { + endpoint -> ux_endpoint_transfer_request.ux_transfer_request_type = + (endpoint->ux_endpoint_descriptor.bEndpointAddress & + UX_ENDPOINT_DIRECTION) ? + UX_REQUEST_IN : UX_REQUEST_OUT; + endpoint -> ux_endpoint_transfer_request.ux_transfer_request_timeout_value = + UX_WAIT_FOREVER; + endpoint = endpoint -> ux_endpoint_next_endpoint; + } + + dummy -> ux_host_class_dummy_state = UX_HOST_CLASS_INSTANCE_LIVE; + + if (_ux_system_host -> ux_system_host_change_function != UX_NULL) + _ux_system_host -> ux_system_host_change_function(UX_DEVICE_INSERTION, dummy -> ux_host_class_dummy_class, (VOID *) dummy); + + return(UX_SUCCESS); +} + +UINT _ux_host_class_dummy_deactivate(UX_HOST_CLASS_COMMAND *command) +{ + +UX_HOST_CLASS_DUMMY *dummy; +UX_ENDPOINT *endpoint; + + + dummy = (UX_HOST_CLASS_DUMMY *)command -> ux_host_class_command_instance; + + dummy -> ux_host_class_dummy_state = UX_HOST_CLASS_INSTANCE_SHUTDOWN; + + endpoint = dummy -> ux_host_class_dummy_interface -> ux_interface_first_endpoint; + while(endpoint) + { + _ux_host_stack_endpoint_transfer_abort(endpoint); + endpoint = endpoint -> ux_endpoint_next_endpoint; + } + + /* If the class instance was busy, let it finish properly and not return. */ + _ux_host_thread_sleep(UX_ENUMERATION_THREAD_WAIT); + + /* Destroy the instance. */ + _ux_host_stack_class_instance_destroy(dummy -> ux_host_class_dummy_class, (VOID *) dummy); + + /* Notify application. */ + if (_ux_system_host -> ux_system_host_change_function != UX_NULL) + _ux_system_host -> ux_system_host_change_function(UX_DEVICE_REMOVAL, dummy -> ux_host_class_dummy_class, (VOID *) dummy); + + /* Free instance memory. */ + _ux_utility_memory_free(dummy); + + return(UX_SUCCESS); +} + +UINT _ux_host_class_dummy_device_entry(UX_HOST_CLASS_COMMAND *command) +{ + + /* The command request will tell us we need to do here, either a enumeration + query, an activation or a deactivation. */ + switch (command -> ux_host_class_command_request) + { + + case UX_HOST_CLASS_COMMAND_QUERY: + if (_ux_host_class_dummy_command_query_list_check(command) == UX_SUCCESS) + return(UX_SUCCESS); + + /* Only for device : class subclass protocol. */ + if (command -> ux_host_class_command_usage != UX_HOST_CLASS_COMMAND_USAGE_DCSP) + return(UX_NO_CLASS_MATCH); + + /* Skip undefined or composite. */ + if (command -> ux_host_class_command_class == 0 || + command -> ux_host_class_command_class == 0xFE) + return(UX_NO_CLASS_MATCH); + + if (!_ux_host_class_dummy_query_reject_unknown) + return(UX_SUCCESS); + return(UX_NO_CLASS_MATCH); + + case UX_HOST_CLASS_COMMAND_ACTIVATE: + return _ux_host_class_dummy_device_activate(command); + + /* Standalone activate wait support. */ + case UX_HOST_CLASS_COMMAND_ACTIVATE_WAIT: + return (UX_STATE_NEXT); + + case UX_HOST_CLASS_COMMAND_DEACTIVATE: + return _ux_host_class_dummy_device_deactivate(command); + + default: + + /* Error trap. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_FUNCTION_NOT_SUPPORTED); + + /* If trace is enabled, insert this event into the trace buffer. */ + UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_FUNCTION_NOT_SUPPORTED, 0, 0, 0, UX_TRACE_ERRORS, 0, 0) + + return(UX_FUNCTION_NOT_SUPPORTED); + } +} + +static UINT _ux_host_class_dummy_device_configure(UX_HOST_CLASS_DUMMY *dummy) +{ +UINT status; +UX_DEVICE *device; + + device = dummy -> ux_host_class_dummy_device; + status = _ux_host_stack_device_configuration_select(device -> ux_device_first_configuration); + return(UX_SUCCESS); +} + +UINT _ux_host_class_dummy_device_activate(UX_HOST_CLASS_COMMAND *command) +{ +UX_DEVICE *device; +UX_HOST_CLASS_DUMMY *dummy; + + device = (UX_DEVICE *) command -> ux_host_class_command_container; + dummy = (UX_HOST_CLASS_DUMMY *)_ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_HOST_CLASS_DUMMY)); + if (dummy == UX_NULL) + return(UX_MEMORY_INSUFFICIENT); + + dummy -> ux_host_class_dummy_class = command -> ux_host_class_command_class_ptr; + dummy -> ux_host_class_dummy_interface = UX_NULL; + dummy -> ux_host_class_dummy_device = device; + device -> ux_device_class_instance = (VOID *)dummy; + + _ux_host_stack_class_instance_create(dummy -> ux_host_class_dummy_class, (VOID *)dummy); + + if (_ux_host_class_dummy_device_configure(dummy) != UX_SUCCESS) + { + _ux_utility_memory_free(dummy); + return(UX_ERROR); + } + + dummy -> ux_host_class_dummy_state = UX_HOST_CLASS_INSTANCE_LIVE; + + if (_ux_system_host -> ux_system_host_change_function != UX_NULL) + _ux_system_host -> ux_system_host_change_function(UX_DEVICE_INSERTION, dummy -> ux_host_class_dummy_class, (VOID *) dummy); + + return(UX_SUCCESS); +} + +UINT _ux_host_class_dummy_device_deactivate(UX_HOST_CLASS_COMMAND *command) +{ +UX_HOST_CLASS_DUMMY *dummy; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +UX_ENDPOINT *endpoint; + + + dummy = (UX_HOST_CLASS_DUMMY *)command -> ux_host_class_command_instance; + + dummy -> ux_host_class_dummy_state = UX_HOST_CLASS_INSTANCE_SHUTDOWN; + + /* Abort all transfer of current configuration. */ + configuration = dummy -> ux_host_class_dummy_device -> ux_device_current_configuration; + interface = configuration -> ux_configuration_first_interface; + while(interface) + { + endpoint = interface -> ux_interface_first_endpoint; + while(endpoint) + { + _ux_host_stack_endpoint_transfer_abort(endpoint); + endpoint = endpoint -> ux_endpoint_next_endpoint; + } + interface = interface -> ux_interface_next_interface; + } + + /* If the class instance was busy, let it finish properly and not return. */ + _ux_host_thread_sleep(UX_ENUMERATION_THREAD_WAIT); + + /* Destroy the instance. */ + _ux_host_stack_class_instance_destroy(dummy -> ux_host_class_dummy_class, (VOID *) dummy); + + if (_ux_system_host -> ux_system_host_change_function != UX_NULL) + _ux_system_host -> ux_system_host_change_function(UX_DEVICE_REMOVAL, dummy -> ux_host_class_dummy_class, (VOID *) dummy); + + return(UX_SUCCESS); +} +#if 0 +UX_CONFIGURATION *_ux_host_class_dummy_get_configuration(UX_HOST_CLASS_DUMMY *dummy, UCHAR configuration_value) +{ +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; + if (dummy == UX_NULL) + return(UX_NULL); + if (dummy -> ux_host_class_dummy_device) + device = dummy -> ux_host_class_dummy_device; + else if (dummy -> ux_host_class_dummy_interface) + { + interface = dummy -> ux_host_class_dummy_interface; + configuration = interface -> ux_interface_configuration; + device = dummy -> ux_host_class_dummy_device; + } + else + return(UX_NULL); + configuration = device -> ux_device_first_configuration; + while(configuration) + { + if (configuration -> ux_configuration_descriptor.bConfigurationValue == configuration_value) + return(configuration); + configuration = configuration -> ux_configuration_next_configuration; + } + return(UX_NULL); +} +#endif +static UX_INTERFACE *_ux_host_class_dummy_get_interface(UX_HOST_CLASS_DUMMY *dummy, UCHAR interface_number, UCHAR alternate_setting) +{ +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; + if (dummy == UX_NULL) + return(UX_NULL); + if (dummy -> ux_host_class_dummy_device) + { + device = dummy -> ux_host_class_dummy_device; + configuration = device -> ux_device_current_configuration; + } + else if (dummy -> ux_host_class_dummy_interface) + { + interface = dummy -> ux_host_class_dummy_interface; + configuration = interface -> ux_interface_configuration; + } + else + return(UX_NULL); + interface = configuration -> ux_configuration_first_interface; + while(interface) + { + if (interface -> ux_interface_descriptor.bInterfaceNumber == (ULONG)interface_number && + interface -> ux_interface_descriptor.bAlternateSetting == (ULONG)alternate_setting) + return(interface); + interface = interface -> ux_interface_next_interface; + } + return(UX_NULL); +} + +UINT _ux_host_class_dummy_select_interface(UX_HOST_CLASS_DUMMY *dummy, UCHAR interface_number, UCHAR alternate_setting) +{ +UX_INTERFACE *interface = _ux_host_class_dummy_get_interface(dummy, interface_number, alternate_setting); + if (interface == UX_NULL) + return(UX_ERROR); + return(ux_host_stack_interface_setting_select(interface)); +} + +static UX_ENDPOINT *_ux_host_class_dummy_device_get_endpoint(UX_HOST_CLASS_DUMMY *dummy, UCHAR endpoint_address, UCHAR alternate_setting) +{ +UX_CONFIGURATION *configuration; +UX_INTERFACE *interface; +UX_ENDPOINT *endpoint; + if (dummy == UX_NULL) + return(UX_NULL); + if (endpoint_address == 0) + return(&dummy -> ux_host_class_dummy_device -> ux_device_control_endpoint); + configuration = dummy -> ux_host_class_dummy_device -> ux_device_current_configuration; + if (configuration == UX_NULL) + return(UX_NULL); + interface = configuration -> ux_configuration_first_interface; + while(interface) + { + if (interface -> ux_interface_descriptor.bAlternateSetting == alternate_setting) + { + endpoint = interface -> ux_interface_first_endpoint; + while(endpoint) + { + if (endpoint -> ux_endpoint_descriptor.bEndpointAddress == endpoint_address) + return(endpoint); + endpoint = endpoint -> ux_endpoint_next_endpoint; + } + } + interface = interface -> ux_interface_next_interface; + } + return(UX_NULL); +} +UX_ENDPOINT *_ux_host_class_dummy_get_endpoint(UX_HOST_CLASS_DUMMY *dummy, UCHAR endpoint_address, UCHAR alternate_setting) +{ +UX_INTERFACE *interface; +UX_ENDPOINT *endpoint; + if (dummy == UX_NULL) + return(UX_NULL); + if (dummy -> ux_host_class_dummy_device) + return(_ux_host_class_dummy_device_get_endpoint(dummy, endpoint_address, alternate_setting)); + interface = dummy -> ux_host_class_dummy_interface; + if (endpoint_address == 0) + return(&interface -> ux_interface_configuration -> ux_configuration_device -> ux_device_control_endpoint); + if (interface -> ux_interface_descriptor.bAlternateSetting != (ULONG)alternate_setting) + return(UX_NULL); + endpoint = interface -> ux_interface_first_endpoint; + while(endpoint) + { + if (endpoint -> ux_endpoint_descriptor.bEndpointAddress == (ULONG)endpoint_address) + { + return(endpoint); + } + endpoint = endpoint -> ux_endpoint_next_endpoint; + } + return(UX_NULL); +} + +UX_TRANSFER *_ux_host_class_dummy_get_transfer_request(UX_HOST_CLASS_DUMMY *dummy, UCHAR endpoint_address, UCHAR alternate_setting) +{ +UX_ENDPOINT *endpoint; + endpoint = _ux_host_class_dummy_get_endpoint(dummy, endpoint_address, alternate_setting); + if (endpoint == UX_NULL) + return(UX_NULL); + return(&endpoint -> ux_endpoint_transfer_request); +} + +VOID _ux_host_class_dummy_set_timeout(UX_HOST_CLASS_DUMMY *dummy, UCHAR endpoint_address, UCHAR alternate_setting, ULONG timeout) +{ +UX_TRANSFER *transfer = _ux_host_class_dummy_get_transfer_request(dummy, endpoint_address, alternate_setting); + UX_TEST_ASSERT(transfer); + transfer -> ux_transfer_request_timeout_value = timeout; +} + +ULONG _ux_host_class_dummy_get_max_packet_size(UX_HOST_CLASS_DUMMY *dummy, UCHAR endpoint_address, UCHAR alternate_setting) +{ +UX_ENDPOINT *endpoint = _ux_host_class_dummy_get_endpoint(dummy, endpoint_address, alternate_setting); + UX_TEST_ASSERT(endpoint); + return(endpoint->ux_endpoint_descriptor.wMaxPacketSize & UX_MAX_PACKET_SIZE_MASK); +} + +ULONG _ux_host_class_dummy_get_max_payload_size(UX_HOST_CLASS_DUMMY *dummy, UCHAR endpoint_address, UCHAR alternate_setting) +{ +UX_ENDPOINT *endpoint = _ux_host_class_dummy_get_endpoint(dummy, endpoint_address, alternate_setting); +ULONG trans, size; + UX_TEST_ASSERT(endpoint); + size = endpoint->ux_endpoint_descriptor.wMaxPacketSize & UX_MAX_PACKET_SIZE_MASK; + trans = endpoint->ux_endpoint_descriptor.wMaxPacketSize & UX_MAX_NUMBER_OF_TRANSACTIONS_MASK; + if (trans) + { + trans >>= UX_MAX_NUMBER_OF_TRANSACTIONS_SHIFT; + UX_TEST_ASSERT(trans < 3); + size *= (trans + 1); + } + return(size); +} +#if !defined(UX_HOST_STANDALONE) +UINT _ux_host_class_dummy_transfer(UX_HOST_CLASS_DUMMY *dummy, UCHAR endpoint_address, UCHAR alternate_setting, UCHAR *buffer, ULONG length, ULONG *actual_length) +{ +UX_TRANSFER *transfer = _ux_host_class_dummy_get_transfer_request(dummy, endpoint_address, alternate_setting); +ULONG payload_size = _ux_host_class_dummy_get_max_payload_size(dummy, endpoint_address, alternate_setting); +ULONG transfer_size; +UINT status; + UX_TEST_ASSERT(transfer); + *actual_length = 0; + do { + transfer_size = UX_MIN(payload_size, length); + transfer->ux_transfer_request_requested_length = transfer_size; + transfer->ux_transfer_request_data_pointer = buffer; + status = ux_host_stack_transfer_request(transfer); + + /* Error check. */ + if (status != UX_SUCCESS) + return(status); + + /* Semaphore wait. */ + status = _ux_utility_semaphore_get(&transfer->ux_transfer_request_semaphore, transfer->ux_transfer_request_timeout_value); + *actual_length += transfer->ux_transfer_request_actual_length; + + /* Semaphore error. */ + if (status != UX_SUCCESS) + { + ux_host_stack_transfer_request_abort(transfer); + transfer->ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT; + return(UX_TRANSFER_TIMEOUT); + } + + /* Short packet check. */ + if (transfer_size != transfer->ux_transfer_request_actual_length) + return(UX_SUCCESS); + + /* Update transfer. */ + buffer += transfer_size; + length -= transfer_size; + + } while(length); + return(UX_SUCCESS); +} +#endif +UINT _ux_host_class_dummy_abort(UX_HOST_CLASS_DUMMY *dummy, UCHAR endpoint_address, UCHAR alternate_setting) +{ +UX_TRANSFER *transfer = _ux_host_class_dummy_get_transfer_request(dummy, endpoint_address, alternate_setting); + UX_TEST_ASSERT(transfer); + return ux_host_stack_transfer_request_abort(transfer); +} diff --git a/test/regression/ux_host_class_dummy.h b/test/regression/ux_host_class_dummy.h new file mode 100644 index 00000000..1fff3560 --- /dev/null +++ b/test/regression/ux_host_class_dummy.h @@ -0,0 +1,67 @@ + +#ifndef UX_HOST_CLASS_DUMMY_H +#define UX_HOST_CLASS_DUMMY_H + +/* Define Data Pump Class instance structure. */ + +typedef struct UX_HOST_CLASS_DUMMY_STRUCT +{ + + struct UX_HOST_CLASS_DUMMY_STRUCT + *ux_host_class_dummy_next_instance; + + UX_HOST_CLASS *ux_host_class_dummy_class; + UX_DEVICE *ux_host_class_dummy_device; + UX_INTERFACE *ux_host_class_dummy_interface; + + UINT ux_host_class_dummy_state; +} UX_HOST_CLASS_DUMMY; + +typedef struct UX_HOST_CLASS_DUMMY_QUERY_STRUCT +{ + ULONG ux_host_class_query_on; /* 0x0 to end list. */ + UINT (*ux_host_class_query_entry)(UX_HOST_CLASS_COMMAND *); /* 0x0 for any. */ + UINT ux_host_class_query_usage; /* 0x0 for any. */ + UINT ux_host_class_query_pid; /* 0x0 for any. */ + UINT ux_host_class_query_vid; /* 0x0 for any. */ + UINT ux_host_class_query_class; /* 0x0 for any. */ + UINT ux_host_class_query_subclass; /* 0x0 for any. */ + UINT ux_host_class_query_protocol; /* 0x0 for any. */ + UINT ux_host_class_query_iad_class; /* 0x0 for any. */ + UINT ux_host_class_query_iad_subclass; /* 0x0 for any. */ + UINT ux_host_class_query_iad_protocol; /* 0x0 for any. */ +} UX_HOST_CLASS_DUMMY_QUERY; + +extern UCHAR _ux_host_class_dummy_name[]; + +UINT _ux_host_class_dummy_entry(UX_HOST_CLASS_COMMAND *command); /* For function/interface class. */ +UINT _ux_host_class_dummy_device_entry(UX_HOST_CLASS_COMMAND *command); /* For device class. */ + +VOID _ux_host_class_dummy_query_reject_unknown_set(UCHAR yes_no); +VOID _ux_host_class_dummy_query_list_set(UX_HOST_CLASS_DUMMY_QUERY *query_list); /* {..., {UX_NULL}} */ + +UINT _ux_host_class_dummy_select_interface(UX_HOST_CLASS_DUMMY *dummy, + UCHAR interface_number, UCHAR alternate_setting); + +UX_ENDPOINT *_ux_host_class_dummy_get_endpoint(UX_HOST_CLASS_DUMMY *dummy, + UCHAR endpoint_address, UCHAR alternate_setting); +UX_TRANSFER *_ux_host_class_dummy_get_transfer_request(UX_HOST_CLASS_DUMMY *dummy, + UCHAR endpoint_address, UCHAR alternate_setting); + +ULONG _ux_host_class_dummy_get_max_packet_size(UX_HOST_CLASS_DUMMY *dummy, + UCHAR endpoint_address, UCHAR alternate_setting); +ULONG _ux_host_class_dummy_get_max_payload_size(UX_HOST_CLASS_DUMMY *dummy, + UCHAR endpoint_address, UCHAR alternate_setting); + +VOID _ux_host_class_dummy_set_timeout(UX_HOST_CLASS_DUMMY *dummy, + UCHAR endpoint_address, UCHAR alternate_setting, + ULONG timeout); + +UINT _ux_host_class_dummy_transfer(UX_HOST_CLASS_DUMMY *dummy, + UCHAR endpoint_address, UCHAR alternate_setting, + UCHAR *buffer, ULONG length, ULONG *actual_length); +UINT _ux_host_class_dummy_abort(UX_HOST_CLASS_DUMMY *dummy, + UCHAR endpoint_address, UCHAR alternate_setting); + + +#endif diff --git a/test/regression/ux_test.c b/test/regression/ux_test.c new file mode 100644 index 00000000..aaf845aa --- /dev/null +++ b/test/regression/ux_test.c @@ -0,0 +1,1838 @@ +#include "ux_test.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_dcd_sim_slave.h" + +#ifndef _ux_utility_time_elapsed +#define _ux_utility_time_elapsed(t0,t1) ((t1)>=(t0) ? ((t1)-(t0)) : (0xFFFFFFFF - (t0) + (t1))) +#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); + +UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); +UINT _ux_dcd_sim_slave_function(UX_SLAVE_DCD *dcd, UINT function, VOID *parameter); +void test_control_return(UINT); +extern ULONG ux_test_port_status; + +static UX_TEST_ACTION *ux_test_hook_action_list; /* Link list, with .next NULL as end. */ +static UX_TEST_ACTION *ux_test_main_action_list; /* Link list, with .next NULL as end. */ +static UX_TEST_ACTION *ux_test_user_list_actions;/* Link list, with .created_list_next NULL as end. */ +static UCHAR ux_test_expedient = 1; +static UCHAR ignore_all_errors = 0; +static UCHAR exit_on_errors = 0; +static ULONG ux_test_memory_test_no_device_memory_free_amount; + +static UCHAR ux_test_assert_hit_hint_off = 0; +static UCHAR ux_test_assert_hit_exit_off = 0; +static ULONG ux_test_assert_hit_count = 0; +static UINT ux_test_assert_hit_exit_code = 1; + +VOID _ux_test_main_action_list_thread_update(TX_THREAD *old, TX_THREAD *new) +{ + UX_TEST_ACTION *list = ux_test_main_action_list; + if (old != new) + { + while(list) + { + if (list->thread_ptr == old) + list->thread_ptr == new; + list = list->next; + } + } +} + +VOID _ux_test_main_action_list_semaphore_update(TX_SEMAPHORE *old, TX_SEMAPHORE *new) +{ + UX_TEST_ACTION *list = ux_test_main_action_list; + if (old != new) + { + while(list) + { + if (list->semaphore_ptr == old) + list->semaphore_ptr == new; + list = list->next; + } + } +} + +VOID _ux_test_main_action_list_mutex_update(TX_MUTEX *old, TX_MUTEX *new) +{ + UX_TEST_ACTION *list = ux_test_main_action_list; + if (old != new) + { + while(list) + { + if (list->mutex_ptr == old) + list->mutex_ptr == new; + list = list->next; + } + } +} + + +UCHAR _ux_test_check_action_function(UX_TEST_ACTION *new_actions) +{ + +UCHAR result; + + +#ifndef UX_TEST_RACE_CONDITION_TESTS_ON + result = (new_actions->usbx_function > 0 && new_actions->usbx_function < (ULONG)UX_TEST_OVERRIDE_RACE_CONDITION_OVERRIDES); +#else + result = (new_actions->_usbx_function > 0 && new_actions->_usbx_function < (ULONG)UX_TEST_NUMBER_OVERRIDES); +#endif + + return result; +} + +VOID _ux_test_append_action(UX_TEST_ACTION *list, UX_TEST_ACTION *new_action) +{ + +UX_TEST_ACTION *tail; + + + tail = list; + while (tail->next != UX_NULL) + tail = tail->next; + tail->next = new_action; +} + +UINT ux_test_list_action_compare(UX_TEST_ACTION *list_item, UX_TEST_ACTION *action) +{ +UX_TEST_ACTION temp; +UINT status; + + /* It's created one, check its contents. */ + if (list_item->created_list_next == list_item) + { + /* Copy action contents to test. */ + temp = *action; + + /* Set action next, created to match. */ + temp.next = list_item->next; + temp.created_list_next = list_item->created_list_next; + + /* Compare. */ + status = ux_utility_memory_compare(list_item, &temp, sizeof(temp)); + + /* Return success if equal. */ + if (status == UX_SUCCESS) + return status; + } + else + { + + /* It's static one, check address. */ + if (list_item == action) + return UX_SUCCESS; + } + + /* No, they do not match. */ + return UX_NO_CLASS_MATCH; +} + +VOID ux_test_remove_hook(UX_TEST_ACTION *action) +{ +UX_TEST_ACTION *item; +UX_TEST_ACTION *previous; + + item = ux_test_hook_action_list; + while(item) + { + if (ux_test_list_action_compare(item, action) != UX_SUCCESS) + { + previous = item; + item = item->next; + continue; + } + + /* Remove action from head. */ + if (item == ux_test_hook_action_list) + { + ux_test_hook_action_list = item->next; + } + + /* Remove action from list. */ + else + { + previous->next = action->next; + } + + /* Free if it's created. */ + if (action->created_list_next == action) + free(action); + + /* Remove is done. */ + return; + } +} + +UINT ux_test_link_hook(UX_TEST_ACTION *action) +{ +UX_TEST_ACTION *tail; + + if (ux_test_hook_action_list == UX_NULL) + { + ux_test_hook_action_list = action; + } + else + { + tail = ux_test_hook_action_list; + while(tail) + { + /* Check existing. */ + if (ux_test_list_action_compare(tail, action) == UX_SUCCESS) + return UX_ERROR; + + /* Check next. */ + if (tail->next == UX_NULL) + break; + + tail = tail->next; + } + tail->next = action; + } + return UX_SUCCESS; +} + +UINT ux_test_add_hook(UX_TEST_ACTION action) +{ +UX_TEST_ACTION *created_action; +UINT status; + + created_action = (UX_TEST_ACTION *)malloc(sizeof(UX_TEST_ACTION)); + UX_TEST_ASSERT(created_action); + + *created_action = action; + + created_action->next = UX_NULL; + + /* We use the memory pointer to indicate it's added by memory allocation. + * On clean up or free we should free allocated memory. + */ + created_action->created_list_next = created_action; + + status = ux_test_link_hook(created_action); + if (status != UX_SUCCESS) + { + free(created_action); + } + return status; +} + +VOID ux_test_remove_hooks_from_array(UX_TEST_ACTION *actions) +{ +UX_TEST_ACTION *action; + + action = actions; + while(action->usbx_function) + { + //printf("rm %p\n", action); + UX_TEST_ASSERT(_ux_test_check_action_function(action)); + ux_test_remove_hook(action); + action ++; + } +} + +VOID ux_test_remove_hooks_from_list(UX_TEST_ACTION *actions) +{ +UX_TEST_ACTION *action; +UX_TEST_ACTION *next; + + action = actions; + while(action) + { + UX_TEST_ASSERT(_ux_test_check_action_function(action)); + next = action->next; + ux_test_remove_hook(action); + action = next; + } +} + +VOID ux_test_link_hooks_from_array(UX_TEST_ACTION *actions) +{ +UX_TEST_ACTION *action; + + action = actions; + while(action->usbx_function) + { + UX_TEST_ASSERT(_ux_test_check_action_function(action)); + ux_test_link_hook(action); + action ++; + } +} + +VOID ux_test_link_hooks_from_list(UX_TEST_ACTION *actions) +{ +UX_TEST_ACTION *action; + + action = actions; + while(action) + { + UX_TEST_ASSERT(_ux_test_check_action_function(action)); + ux_test_link_hook(action); + action = action->next; + } +} + +VOID ux_test_add_hooks_from_array(UX_TEST_ACTION *actions) +{ +UX_TEST_ACTION *action; + + action = actions; + while(action->usbx_function) + { + UX_TEST_ASSERT(_ux_test_check_action_function(action)); + ux_test_add_hook(*action); + action ++; + } +} + +VOID ux_test_add_hooks_from_list(UX_TEST_ACTION *actions) +{ +UX_TEST_ACTION *action; + + action = actions; + while(action) + { + UX_TEST_ASSERT(_ux_test_check_action_function(action)); + ux_test_add_hook(*action); + action = action->next; + } +} + +ULONG ux_test_do_hooks_before(UX_TEST_FUNCTION usbx_function, VOID *params) +{ +UX_TEST_ACTION *list; +UX_TEST_ACTION action; +ULONG action_count = 0; +ULONG action_return = 0; + + list = ux_test_hook_action_list; + while(list) + { + action = ux_test_action_handler_check(list, usbx_function, params, UX_FALSE); + if (action.matched && !action.do_after) + { + action_count ++; + if (!action.no_return) + action_return = 0x80000000u; + } + ux_test_do_action_before(&action, params); + list = list->next; + } + return (action_count | action_return); +} + +VOID ux_test_do_hooks_after(UX_TEST_FUNCTION usbx_function, VOID *params) +{ +UX_TEST_ACTION *list; +UX_TEST_ACTION action; +ULONG action_count = 0; + + list = ux_test_hook_action_list; + while(list) + { + action = ux_test_action_handler_check(list, usbx_function, params, UX_FALSE); + if (action.matched) + action_count ++; + ux_test_do_action_after(&action, params); + list = list->next; + } +} + +VOID ux_test_free_hook_actions() +{ +UX_TEST_ACTION *action; + + while(ux_test_hook_action_list) + { + action = ux_test_hook_action_list; + ux_test_hook_action_list = ux_test_hook_action_list->next; + + /* If this action is added/created, free allocated memory. */ + if (action->created_list_next == action) + { + free(action); + } + } +} + +VOID _ux_test_add_action_to_list(UX_TEST_ACTION *list, UX_TEST_ACTION action) +{ + +UX_TEST_ACTION *new_action = UX_NULL; +UX_TEST_ACTION *tail; + + + /* Do some idiot-proof checks. */ + { + /* Check the function. */ +#ifndef UX_TEST_RACE_CONDITION_TESTS_ON + UX_TEST_ASSERT((action.usbx_function > 0 && action.usbx_function < (ULONG)UX_TEST_OVERRIDE_RACE_CONDITION_OVERRIDES)); +#else + UX_TEST_ASSERT((action._usbx_function > 0 && action._usbx_function < (ULONG)UX_TEST_NUMBER_OVERRIDES)); +#endif + + /* Make sure expedient is on when it should be. */ + if (action.no_return == 0 && + /* For user callbacks, it's okay. */ + action.usbx_function < UX_TEST_OVERRIDE_USER_CALLBACKS) + { + /* Allowed if flow stopped to avoid low level operations. */ + #if 0 + UX_TEST_ASSERT(ux_test_is_expedient_on()); + #endif + } + } + + if (/* Is this the main list? */ + list == ux_test_main_action_list || + /* Is the head of user-list already an action? */ + list->usbx_function) + { + new_action = (UX_TEST_ACTION *)malloc(sizeof(UX_TEST_ACTION)); + *new_action = action; + new_action->next = UX_NULL; + } + + if (list == ux_test_main_action_list) + { + + if (!ux_test_main_action_list) + ux_test_main_action_list = new_action; + else + _ux_test_append_action(list, new_action); + } + else + { + + if (!list->usbx_function) + *list = action; + else + { + + /* Append to user created list. */ + if (!ux_test_user_list_actions) + ux_test_user_list_actions = new_action; + else + { + + tail = ux_test_user_list_actions; + while (tail->created_list_next) + tail = tail->created_list_next; + tail->created_list_next = new_action; + } + + _ux_test_append_action(list, new_action); + } + } +} + +VOID ux_test_add_action_to_main_list(UX_TEST_ACTION new_action) +{ + + _ux_test_add_action_to_list(ux_test_main_action_list, new_action); +} + +VOID ux_test_add_action_to_main_list_multiple(UX_TEST_ACTION new_action, UINT num) +{ + + while (num--) + _ux_test_add_action_to_list(ux_test_main_action_list, new_action); +} + +VOID ux_test_add_action_to_user_list(UX_TEST_ACTION *list, UX_TEST_ACTION new_action) +{ + + _ux_test_add_action_to_list(list, new_action); +} + +VOID ux_test_set_main_action_list_from_list(UX_TEST_ACTION *new_actions) +{ + + UX_TEST_ASSERT(!ux_test_main_action_list); + while (new_actions) + { + + ux_test_add_action_to_main_list(*new_actions); + new_actions = new_actions->next; + } +} + +VOID ux_test_set_main_action_list_from_array(UX_TEST_ACTION *new_actions) +{ + + UX_TEST_ASSERT(!ux_test_main_action_list); + while (new_actions->usbx_function) + { + + ux_test_add_action_to_main_list(*new_actions); + new_actions++; + } +} + +VOID ux_test_free_user_list_actions() +{ + +UX_TEST_ACTION *action; + + + while (ux_test_user_list_actions) + { + + action = ux_test_user_list_actions; + ux_test_user_list_actions = ux_test_user_list_actions->created_list_next; + free(action); + } +} + +static VOID _ux_test_advance_actions() +{ + +UX_TEST_ACTION *action; + + + UX_TEST_ASSERT(ux_test_main_action_list != UX_NULL); + action = ux_test_main_action_list; + ux_test_main_action_list = ux_test_main_action_list->next; + free(action); +} + +VOID ux_test_clear_main_list_actions() +{ + + while (ux_test_main_action_list) + _ux_test_advance_actions(); +} + +VOID _ux_test_set_actions_and_set_function(UX_TEST_ACTION *new_actions, UX_TEST_FUNCTION function) +{ + + UX_TEST_ASSERT(new_actions != UX_NULL); + + while (new_actions->function || new_actions->usbx_function) + { + + if (new_actions->function && !new_actions->usbx_function) + new_actions->usbx_function = function; + ux_test_add_action_to_main_list(*new_actions); + new_actions++; + } +} + +VOID ux_test_hcd_sim_host_set_actions(UX_TEST_ACTION *new_actions) +{ + + ux_test_clear_main_list_actions(); + + if (new_actions != UX_NULL) + _ux_test_set_actions_and_set_function(new_actions, UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY); +} + +VOID ux_test_dcd_sim_slave_set_actions(UX_TEST_ACTION *new_actions) +{ + + ux_test_clear_main_list_actions(); + + if (new_actions != UX_NULL) + _ux_test_set_actions_and_set_function(new_actions, UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION); +} + +/* Returns whether there are any actions in the list. */ +UCHAR ux_test_check_actions_empty() +{ + return(ux_test_main_action_list == UX_NULL ? UX_TRUE : UX_FALSE); +} + +UINT ux_test_wait_for_empty_actions() +{ + return ux_test_wait_for_null((VOID **)&ux_test_main_action_list); +} + +UINT ux_test_wait_for_empty_actions_wait_time(UINT wait_time_ms) +{ + return ux_test_wait_for_null_wait_time((VOID **)&ux_test_main_action_list, wait_time_ms); +} + +UINT ux_test_get_num_actions_left() +{ + +UINT num_actions_remaining = 0; +UX_TEST_ACTION *action = ux_test_main_action_list; + + + while (action) + { + num_actions_remaining++; + action = action->next; + } + + return(num_actions_remaining); +} + +VOID _ux_host_class_storage_driver_read_write_notify(VOID *func); + +VOID ux_test_cleanup_everything(VOID) +{ + + /* Free main list actions. */ + ux_test_clear_main_list_actions(); + + /* Free allocated user list actions. */ + ux_test_free_user_list_actions(); + + /* Free added hook actions. */ + ux_test_free_hook_actions(); + + /* Reset expedient value. */ + ux_test_expedient = UX_TRUE; + + /* Reset free memory test amount. */ + ux_test_memory_test_no_device_memory_free_amount = 0; + + /* Assert related. */ + ux_test_assert_hit_count = 0; + ux_test_assert_hit_hint_off = 0; + ux_test_assert_hit_exit_off = 0; + ux_test_assert_hit_exit_code = 1; + +#if defined(UX_HOST_CLASS_STORAGE_NO_FILEX) + _ux_host_class_storage_driver_read_write_notify(UX_NULL); +#endif +} + +VOID ux_test_do_action_before(UX_TEST_ACTION *action, VOID *params) +{ + + if (action->matched && !action->do_after) + { + if (action->action_func) + { + action->action_func(action, params); + } + } +} + +VOID ux_test_do_action_after(UX_TEST_ACTION *action, VOID *params) +{ + + if (action->matched && action->do_after) + { + if (action->action_func) + { + action->action_func(action, params); + } + } +} + +VOID ux_test_turn_on_expedient(UCHAR *original_expedient) +{ + + if (original_expedient) + { + *original_expedient = ux_test_expedient; + } + ux_test_expedient = 1; +} + +VOID ux_test_turn_off_expedient(UCHAR *original_expedient) +{ + + if (original_expedient) + { + *original_expedient = ux_test_expedient; + } + ux_test_expedient = 0; +} + +VOID ux_test_set_expedient(UCHAR value) +{ + + ux_test_expedient = value; +} + +UCHAR ux_test_is_expedient_on() +{ + + return(ux_test_expedient); +} + +UX_TEST_ACTION ux_test_action_handler(UX_TEST_FUNCTION usbx_function, void *params) +{ + return ux_test_action_handler_check(ux_test_main_action_list, usbx_function, params, UX_TRUE); +} + +static UX_TEST_ACTION ux_test_action_handler_check(UX_TEST_ACTION *list, UX_TEST_FUNCTION usbx_function, void *params, UCHAR advance) +{ + +UINT i; +UINT min; +UX_TEST_ACTION *this = list; +UX_TEST_ACTION result = { 0 }; +UCHAR act = 0; +UX_TRANSFER *host_req; +UX_SLAVE_TRANSFER *slave_req; +ULONG *slave_req_code = UX_NULL; +UINT *req_code = UX_NULL; +ULONG *req_actual_len = UX_NULL; +UX_ENDPOINT *ep; +TX_THREAD *this_thread; +UX_TEST_SETUP req_setup; +UX_TEST_SIM_ENTRY_ACTION generic_transfer_parameter = { 0 }; +UX_TEST_GENERIC_CD *generic_cd_params; +UX_TEST_GENERIC_CD _generic_cd_params; +UINT str_len0; +UINT str_len1; +UCHAR ignore_param_checks = 0; +UX_TEST_OVERRIDE_TX_SEMAPHORE_GET_PARAMS *semaphore_get_params; +UX_TEST_OVERRIDE_TX_SEMAPHORE_CREATE_PARAMS *semaphore_create_params; +UX_TEST_OVERRIDE_TX_THREAD_CREATE_PARAMS *thread_create_params; +UX_TEST_ERROR_CALLBACK_PARAMS *error_callback_params; +UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ_WRITE_FLUSH_PARAMS*device_media_read_write_flush_params; +UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_STATUS_PARAMS *device_media_status_params; +UX_TEST_OVERRIDE_UX_HOST_STACK_TRANSFER_REQUEST_PARAMS *host_stack_transfer_request_params; +UX_TEST_OVERRIDE_TX_THREAD_PREEMPTION_CHANGE_PARAMS *thread_preemption_change_params; +UX_TEST_OVERRIDE_UX_HOST_STACK_INTERFACE_SET_PARAMS *host_stack_interface_set_params; +UX_TEST_OVERRIDE_TX_MUTEX_GET_PARAMS *mutex_get_params; +UX_TEST_OVERRIDE_TX_MUTEX_PUT_PARAMS *mutex_put_params; +UX_TEST_OVERRIDE_TX_MUTEX_CREATE_PARAMS *mutex_create_params; +UX_TEST_OVERRIDE_NX_PACKET_POOL_CREATE_PARAMS *packet_pool_create_params; +UX_TEST_OVERRIDE_NX_PACKET_ALLOCATE_PARAMS *packet_allocate_params; + + + if (this) + { + + if (this->usbx_function == usbx_function) + { + + /* If appropriate, setup generic controller driver (CD) parameter. */ + if (this->usbx_function == UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY || + this->usbx_function == UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION || + this->usbx_function == UX_TEST_OVERRIDE_UX_HOST_STACK_TRANSFER_REQUEST) + { + /* Treat a transfer request action like an HCD action. */ + if (usbx_function == UX_TEST_OVERRIDE_UX_HOST_STACK_TRANSFER_REQUEST) + { + host_stack_transfer_request_params = params; + generic_cd_params = &_generic_cd_params; + generic_cd_params->parameter = host_stack_transfer_request_params->transfer_request; + generic_cd_params->function = UX_HCD_TRANSFER_REQUEST; + } + else + { + generic_cd_params = params; + } + } + + /* Should we ignore the param checking? */ + if (this->ignore_params) + { + if (this->usbx_function == UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY || + this->usbx_function == UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION) + { + /* Check the sub-function. */ + if (this->function == generic_cd_params->function) + { + ignore_param_checks = 1; + } + } + else + { + /* There is no sub-function. */ + ignore_param_checks = 1; + } + } + + act = 1; + if (!ignore_param_checks) + { + switch (usbx_function) + { + + case UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY: + case UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION: + case UX_TEST_OVERRIDE_UX_HOST_STACK_TRANSFER_REQUEST: + + act = 0; + if (this->function == generic_cd_params->function) + { + + act = 1; + switch (generic_cd_params->function) + { + + /* We have action on endpoint entries */ + case UX_HCD_CREATE_ENDPOINT: + //case UX_DCD_CREATE_ENDPOINT: + case UX_HCD_DESTROY_ENDPOINT: + //case UX_DCD_DESTROY_ENDPOINT: + case UX_HCD_RESET_ENDPOINT: + //case UX_DCD_RESET_ENDPOINT: + case UX_DCD_ENDPOINT_STATUS: + case UX_DCD_STALL_ENDPOINT: + + ep = generic_cd_params->parameter; + + if ((this->req_action & UX_TEST_MATCH_EP) && + this->req_ep_address != ep->ux_endpoint_descriptor.bEndpointAddress) + act = 0; + + break; + + /* We have action on transfer request abort */ + case UX_HCD_TRANSFER_ABORT: + //case UX_DCD_TRANSFER_ABORT: + + if (UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION != usbx_function) + { + + host_req = (UX_TRANSFER *)generic_cd_params->parameter; + if ((this->req_action & UX_TEST_MATCH_EP) && + this->req_ep_address != host_req->ux_transfer_request_endpoint->ux_endpoint_descriptor.bEndpointAddress) + act = 0; + } + else + { + + slave_req = (UX_SLAVE_TRANSFER *)generic_cd_params->parameter; + if ((this->req_action & UX_TEST_MATCH_EP) && + this->req_ep_address != slave_req->ux_slave_transfer_request_endpoint->ux_slave_endpoint_descriptor.bEndpointAddress) + act = 0; + } + break; + + /* We have action on transfer request */ + case UX_HCD_TRANSFER_REQUEST: + //case UX_DCD_TRANSFER_REQUEST: + + generic_transfer_parameter.req_setup = &req_setup; + + if (usbx_function == UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY || + usbx_function == UX_TEST_OVERRIDE_UX_HOST_STACK_TRANSFER_REQUEST) + { + host_req = generic_cd_params->parameter; + + generic_transfer_parameter.req_actual_len = host_req->ux_transfer_request_actual_length; + generic_transfer_parameter.req_data = host_req->ux_transfer_request_data_pointer; + generic_transfer_parameter.req_ep_address = host_req->ux_transfer_request_endpoint->ux_endpoint_descriptor.bEndpointAddress; + generic_transfer_parameter.req_requested_len = host_req->ux_transfer_request_requested_length; + generic_transfer_parameter.req_status = host_req->ux_transfer_request_status; + generic_transfer_parameter.req_setup->ux_test_setup_index = host_req->ux_transfer_request_index; + generic_transfer_parameter.req_setup->ux_test_setup_request = host_req->ux_transfer_request_function; + generic_transfer_parameter.req_setup->ux_test_setup_type = host_req->ux_transfer_request_type; + generic_transfer_parameter.req_setup->ux_test_setup_value = host_req->ux_transfer_request_value; + + req_actual_len = &host_req->ux_transfer_request_actual_length; + req_code = &host_req->ux_transfer_request_completion_code; + } + else + { + slave_req = generic_cd_params->parameter; + + generic_transfer_parameter.req_actual_len = slave_req->ux_slave_transfer_request_actual_length; + generic_transfer_parameter.req_data = slave_req->ux_slave_transfer_request_data_pointer; + generic_transfer_parameter.req_ep_address = slave_req->ux_slave_transfer_request_endpoint->ux_slave_endpoint_descriptor.bEndpointAddress; + generic_transfer_parameter.req_requested_len = slave_req->ux_slave_transfer_request_requested_length; + generic_transfer_parameter.req_status = slave_req->ux_slave_transfer_request_status; + generic_transfer_parameter.req_setup->ux_test_setup_type = (UCHAR)slave_req->ux_slave_transfer_request_type; + + req_actual_len = &slave_req->ux_slave_transfer_request_actual_length; + slave_req_code = &slave_req->ux_slave_transfer_request_completion_code; + } + + if (this->req_action & UX_TEST_MATCH_EP && + this->req_ep_address != generic_transfer_parameter.req_ep_address) + act = 0; + + /* We must confirm request setup is matching */ + if (this->req_setup) + { + + if ((this->req_action & UX_TEST_SETUP_MATCH_REQUEST) && + (generic_transfer_parameter.req_setup->ux_test_setup_type != this->req_setup->ux_test_setup_type)) + act = 0; + + if ((this->req_action & UX_TEST_SETUP_MATCH_REQUEST) && + (generic_transfer_parameter.req_setup->ux_test_setup_request != this->req_setup->ux_test_setup_request)) + act = 0; + + if ((this->req_action & UX_TEST_SETUP_MATCH_VALUE) && + (generic_transfer_parameter.req_setup->ux_test_setup_value != this->req_setup->ux_test_setup_value)) + act = 0; + + if ((this->req_action & UX_TEST_SETUP_MATCH_INDEX) && + (generic_transfer_parameter.req_setup->ux_test_setup_index != this->req_setup->ux_test_setup_index)) + act = 0; + } + + /* Compare data. We only do the comparison if this action is not meant for substituting data. */ + if (!(this->req_action & UX_TEST_SIM_REQ_ANSWER) && this->req_data) + { + if (generic_transfer_parameter.req_data == UX_NULL || + /* Make sure we don't go off the end during the compare. */ + generic_transfer_parameter.req_requested_len < this->req_actual_len) + act = 0; + else + { + + /* Is there no mask? */ + if (!this->req_data_match_mask) + { + if (ux_utility_memory_compare(generic_transfer_parameter.req_data, this->req_data, this->req_actual_len) == UX_ERROR) + { + act = 0; + } + } + else + { + /* Compare with mask. */ + for (i = 0; i < this->req_actual_len; i++) + { + if (this->req_data_match_mask[i] && + this->req_data[i] != generic_transfer_parameter.req_data[i]) + { + act = 0; + break; + } + } + } + } + } + + /* Compare requested lengths. */ + if ((this->req_action & UX_TEST_MATCH_REQ_LEN) && + (generic_transfer_parameter.req_requested_len != this->req_requested_len)) + act = 0; + + /* Do additional check. */ + if (this->check_func && !this->check_func()) + act = 0; + + break; + + case UX_DCD_CHANGE_STATE: + case UX_HCD_RESET_PORT: + case UX_HCD_ENABLE_PORT: + case UX_HCD_GET_PORT_STATUS: + + /* AFAIK, there's nothing to check here. */ + + break; + + /* The other entries are not handled now */ + default: + UX_TEST_ASSERT(0); + break; + } + } + break; + + #if 0 + case UX_TEST_OVERRIDE_UX_UTILITY_MEMORY_ALLOCATE: + + memory_allocate_params = params; + if (memory_allocate_params->memory_alignment != this->memory_alignment || + memory_allocate_params->memory_cache_flag != this->memory_cache_flag || + memory_allocate_params->memory_size_requested != this->memory_size_requested) + { + act = 0; + } + break; + #endif + + case UX_TEST_OVERRIDE_TX_SEMAPHORE_GET: + + semaphore_get_params = params; + + if (this->semaphore_ptr != UX_NULL && semaphore_get_params->semaphore_ptr != this->semaphore_ptr || + semaphore_get_params->wait_option != this->wait_option) + { + act = 0; + } + break; + + case UX_TEST_OVERRIDE_ERROR_CALLBACK: + + error_callback_params = params; + if ((this->error_code && error_callback_params->error_code != this->error_code) || + (this->system_context && error_callback_params->system_context != this->system_context) || + (this->system_level && error_callback_params->system_level != this->system_level)) + { + act = 0; + } + break; + + case UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ: + + device_media_read_write_flush_params = params; + if ((device_media_read_write_flush_params->lba != this->lba || + device_media_read_write_flush_params->lun != this->lun || + device_media_read_write_flush_params->number_blocks != this->number_blocks)) + { + act = 0; + } + break; + + case UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_WRITE: + + device_media_read_write_flush_params = params; + if ((device_media_read_write_flush_params->lba != this->lba || + device_media_read_write_flush_params->lun != this->lun || + device_media_read_write_flush_params->number_blocks != this->number_blocks)) + { + act = 0; + } + break; + + case UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_FLUSH: + + device_media_read_write_flush_params = params; + if ((device_media_read_write_flush_params->lba != this->lba || + device_media_read_write_flush_params->lun != this->lun || + device_media_read_write_flush_params->number_blocks != this->number_blocks)) + { + act = 0; + } + break; + + case UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_STATUS: + + device_media_status_params = params; + if ((device_media_status_params->lun != this->lun || + device_media_status_params->media_id != this->media_id)) + { + act = 0; + } + break; + + case UX_TEST_OVERRIDE_NX_PACKET_POOL_CREATE: + + packet_pool_create_params = params; + + /* We just compare names. */ + + UX_TEST_ASSERT(this->name_ptr != UX_NULL); + + if (strcmp(packet_pool_create_params->name_ptr, this->name_ptr)) + { + act = 0; + } + + break; + + case UX_TEST_OVERRIDE_NX_PACKET_ALLOCATE: + + packet_allocate_params = params; + + /* We just compare names. */ + + UX_TEST_ASSERT(this->name_ptr != UX_NULL); + + if (strcmp(packet_allocate_params->pool_ptr->nx_packet_pool_name, this->name_ptr)) + { + act = 0; + } + + break; + + case UX_TEST_OVERRIDE_TX_THREAD_CREATE: + + thread_create_params = params; + + /* We just compare names. */ + + UX_TEST_ASSERT(this->name_ptr != UX_NULL); + + if (strcmp(thread_create_params->name_ptr, this->name_ptr)) + { + act = 0; + } + + break; + + case UX_TEST_OVERRIDE_TX_SEMAPHORE_CREATE: + + semaphore_create_params = params; + + /* We just compare names. */ + + UX_TEST_ASSERT(this->semaphore_name != UX_NULL); + + if (strcmp(semaphore_create_params->semaphore_name, this->semaphore_name)) + { + act = 0; + } + + break; + + case UX_TEST_OVERRIDE_TX_THREAD_PREEMPTION_CHANGE: + + thread_preemption_change_params = params; + if (this->thread_ptr != thread_preemption_change_params->thread_ptr || + this->new_threshold != thread_preemption_change_params->new_threshold) + { + act = 0; + } + break; + + case UX_TEST_OVERRIDE_UX_HOST_STACK_INTERFACE_SET: + + host_stack_interface_set_params = params; + if (this->interface->ux_interface_descriptor.bInterfaceNumber != host_stack_interface_set_params->interface->ux_interface_descriptor.bInterfaceNumber || + this->interface->ux_interface_descriptor.bAlternateSetting != host_stack_interface_set_params->interface->ux_interface_descriptor.bAlternateSetting) + { + act = 0; + } + break; + + case UX_TEST_OVERRIDE_TX_MUTEX_GET: + + mutex_get_params = params; + if (this->mutex_ptr && + this->mutex_ptr != mutex_get_params->mutex_ptr) + { + act = 0; + } + if (mutex_get_params->wait_option != this->wait_option) + { + act = 0; + } + break; + + case UX_TEST_OVERRIDE_TX_MUTEX_CREATE: + + mutex_create_params = params; + if (this->mutex_ptr && + this->mutex_ptr != mutex_create_params->mutex_ptr) + { + act = 0; + } + if (mutex_create_params->inherit != this->inherit) + { + act = 0; + } + if (this->name_ptr != UX_NULL) + { + str_len0 = 0; + _ux_utility_string_length_check(this->name_ptr, &str_len0, 2048); + if (mutex_create_params->name_ptr != UX_NULL) + { + str_len1 = 0; + _ux_utility_string_length_check(mutex_create_params->name_ptr, &str_len1, 2048); + } + else + { + str_len1 = 0; + } + if (str_len0 != str_len1) + { + act = 0; + } + if (str_len0 == str_len1 && + ux_utility_memory_compare(this->name_ptr, mutex_create_params->name_ptr, str_len0) != UX_SUCCESS) + { + act = 0; + } + } + break; + + case UX_TEST_OVERRIDE_TX_MUTEX_PUT: + + mutex_put_params = params; + if (this->mutex_ptr != UX_NULL && + this->mutex_ptr != mutex_put_params->mutex_ptr) + { + act = 0; + } + break; + } + } + + /* Non-param checks - these checks happen regardless of the "ignore_params" + value. */ + + if (this->thread_to_match) + { + this_thread = tx_thread_identify(); + if (this_thread != this->thread_to_match) + act = 0; + } + + if (this->check_func && this->check_func(params) != UX_TRUE) + { + act = 0; + } + } + } + + if (act) + { + + //stepinfo(" action matched; usbx_function: %d\n", usbx_function); + + if (usbx_function == UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY || + usbx_function == UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION || + usbx_function == UX_TEST_OVERRIDE_UX_HOST_STACK_TRANSFER_REQUEST) + { + + /* Apply to port status */ + if (this -> port_action) + { + + UX_TEST_ASSERT(!this->no_return); + + ux_test_port_status = this -> port_status; + // printf("Port status -> %lx\n", port_status); + /* Signal change on the port (HCD0.RH.PORT0). */ + _ux_system_host -> ux_system_host_hcd_array -> ux_hcd_root_hub_signal[0] = 1; + /* Signal detach to host enum thread. */ + _ux_host_semaphore_put(&_ux_system_host -> ux_system_host_enum_semaphore); + } + + /* Apply to transfer */ + if (this -> req_action & UX_TEST_SIM_REQ_ANSWER) + { + + /* We should always return, otherwise the data we copy will just + get overridden by the actual transfer request. */ + UX_TEST_ASSERT(!this->no_return); + + /* Is there data to copy? */ + if (this->req_data) + { + /* Make sure we don't overflow. */ + min = generic_transfer_parameter.req_requested_len < this->req_actual_len ? generic_transfer_parameter.req_requested_len : this->req_actual_len; + + /* Copy the data. */ + _ux_utility_memory_copy(generic_transfer_parameter.req_data, this->req_data, min); + } + + /* Set actual length */ + if (this->req_actual_len == (~0)) + *req_actual_len = generic_transfer_parameter.req_requested_len; + else + *req_actual_len = this->req_actual_len; + + /* Set status code */ + if (usbx_function == UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY || + usbx_function == UX_TEST_OVERRIDE_UX_HOST_STACK_TRANSFER_REQUEST) + *req_code = this->req_status; + else + *slave_req_code = this->req_status; + } + } + + result = *this; + result.matched = 1; + + if (advance) + _ux_test_advance_actions(); + } + + return result; +} + +#define SLEEP_STEP 1 +UINT ux_test_breakable_sleep(ULONG tick, UINT (*sleep_break_check_callback)(VOID)) +{ + +UINT status; +ULONG t; + + while(tick) { + + /* Sleep for a while. */ + t = (tick > SLEEP_STEP) ? SLEEP_STEP : tick; +#if defined(UX_HOST_STANDALONE) || defined(UX_DEVICE_STANDALONE) + ux_system_tasks_run(); +#endif + tx_thread_sleep(t); + + /* Check if we want to break. */ + if (sleep_break_check_callback) + { + + status = sleep_break_check_callback(); + if (status != UX_SUCCESS) + { + + /* We break sleep loop! + Status is returned for use to check. */ + return status; + } + } + + /* Update remaining ticks. */ + tick -= t; + } + + /* Normal end. */ + return UX_SUCCESS; +} +UINT ux_test_sleep_break_if(ULONG tick, UINT (*check)(VOID), + UINT break_on_match_or_not, + UINT rc_to_check) +{ +ULONG t0, t1; +UINT status; + + t0 = tx_time_get(); + while(1) + { +#if defined(UX_HOST_STANDALONE) + ux_system_tasks_run(); + tx_thread_relinquish(); +#else + tx_thread_sleep(1); +#endif + if (check) + { + status = check(); + if (break_on_match_or_not) + { + /* If RC match expected, break. */ + if (status == rc_to_check) + break; + } + else + { + /* If RC not match expected, break. */ + if (status != rc_to_check) + break; + } + } + t1 = tx_time_get(); + if (_ux_utility_time_elapsed(t0, t1) >= tick) + { + return(UX_TIMEOUT); + } + } + return(UX_SUCCESS); +} + +/* Error callback */ + +UX_TEST_ERROR_CALLBACK_ERROR ux_error_hcd_transfer_stalled = { UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HCD, UX_TRANSFER_STALLED }; + +VOID ux_test_ignore_all_errors() +{ + ignore_all_errors = UX_TRUE; +} + +VOID ux_test_unignore_all_errors() +{ + ignore_all_errors = UX_FALSE; +} + +void test_control_return(UINT status); +VOID ux_test_error_callback(UINT system_level, UINT system_context, UINT error_code) +{ + +UX_TEST_ERROR_CALLBACK_PARAMS params = { system_level, system_context, error_code }; +UX_TEST_ACTION action; + + + if (ignore_all_errors == UX_TRUE) + { + return; + } + + if (ux_test_do_hooks_before(UX_TEST_OVERRIDE_ERROR_CALLBACK, ¶ms)) + return; + + action = ux_test_action_handler(UX_TEST_OVERRIDE_ERROR_CALLBACK, ¶ms); + if (action.matched) + { + return; + } + + /* Failed test. Windows has some stupid printf bug where it stalls + everything if other threads are printing as well. Doesn't matter anyways, + since I use breakpoints for debugging this error. */ +#ifndef WIN32 + printf("%s:%d Unexpected error: 0x%x, 0x%x, 0x%x\n", __FILE__, __LINE__, system_level, system_context, error_code); +#endif + + if (exit_on_errors) + test_control_return(1); +} + +/* Utility methods. */ + +static ULONG ux_test_memory_test_no_device_memory_free_amount; + +void ux_test_memory_test_initialize() +{ + +UCHAR connected_when_started = 0; + + /* Are we connected? */ + if (_ux_system_host->ux_system_host_hcd_array[0].ux_hcd_nb_devices != 0) + { + /* Yes. */ + connected_when_started = 1; + + /* Then disconnect. */ + ux_test_disconnect_slave_and_host_wait_for_enum_completion(); + } + + /* Get normal amount of free memory when disconnected. This is to detect + memory leaks. */ + ux_test_memory_test_no_device_memory_free_amount = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + ux_test_connect_slave_and_host_wait_for_enum_completion(); + + /* With basic free memory amount, do basic memory test. */ + ux_test_disconnect_slave_and_host_wait_for_enum_completion(); + ux_test_connect_slave_and_host_wait_for_enum_completion(); + + /* (Let's be nice to the user.) Hello user! :) */ + if (!connected_when_started) + { + ux_test_disconnect_slave_and_host_wait_for_enum_completion(); + } +} + +void ux_test_memory_test_check() +{ + + /* Has the memory check value not been initialized yet? */ + if (ux_test_memory_test_no_device_memory_free_amount == 0) + return; + UX_TEST_ASSERT(_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available == ux_test_memory_test_no_device_memory_free_amount); +} + +#if defined(UX_HOST_STANDALONE) +static UINT _host_enum_is_pending(void) +{ +UX_DEVICE *enum_device = _ux_system_host -> ux_system_host_enum_device; + /* Case 1 : there is nothing in enum list, nothing pending. */ + if (enum_device == UX_NULL) + return(UX_ERROR); + /* Case 2 : enum list is not NULL, check enum flags each device. */ + while(enum_device) + { + if (enum_device -> ux_device_flags & UX_DEVICE_FLAG_ENUM) + return(UX_SUCCESS); + enum_device = enum_device -> ux_device_enum_next; + } + return(UX_ERROR); +} +static UINT _host_rh_removal_is_pending(void) +{ +UX_HCD *hcd = &_ux_system_host -> ux_system_host_hcd_array[0]; + /* If device connected, pending. */ + if (hcd -> ux_hcd_rh_device_connection) + return(UX_SUCCESS); + return(UX_ERROR); +} +#endif + +/* Wait for the enum thread to finish whatever it's currently doing. Note that + this implies it's actually _doing_ something when this is called. + + Specifics: We do this by simply waiting for the the enum thread's semaphore's + suspended count to be non-zero. */ +VOID ux_test_wait_for_enum_thread_completion() +{ +#if !defined(UX_HOST_STANDALONE) + /* Is it actually running? */ + if (_ux_system_host -> ux_system_host_enum_semaphore.tx_semaphore_suspended_count == 0) + { + + /* Wait for enum thread to complete. */ + UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uint(&_ux_system_host -> ux_system_host_enum_semaphore.tx_semaphore_suspended_count, 1)); + } +#else + { + UINT status; + if (ux_test_port_status & UX_PS_CCS) + { + /* Loop a while to confirm enumeration start. */ + status = ux_test_sleep_break_on_success(10, _host_enum_is_pending); + if (status == UX_SUCCESS) + { + /* Loop a while to confirm enumeration end. */ + status = ux_test_sleep_break_on_error(100, _host_enum_is_pending); + UX_ASSERT(status == UX_SUCCESS); + } + } + else + { + /* Loop a while to confirm device removal. */ + status = ux_test_sleep_break_on_error(100, _host_rh_removal_is_pending); + UX_ASSERT(status == UX_SUCCESS); + } + } +#endif +} + +VOID ux_test_disconnect_host_no_wait() +{ + + ux_test_hcd_sim_host_disconnect_no_wait(); +} + +VOID ux_test_disconnect_host_wait_for_enum_completion() +{ + + /* No wait because ux_test_wait_for_enum_completion() expects the enum thread + to be running when it's called. */ + ux_test_hcd_sim_host_disconnect_no_wait(); + ux_test_wait_for_enum_thread_completion(); + ux_test_memory_test_check(); +} + +/* This function should not be called from inside USBX because we wait for the + deactivation to finish. If we have a semaphore the deactivation routine requires, + then we have deadlock. */ +void ux_test_disconnect_slave_and_host_wait_for_enum_completion() +{ + +UX_HCD *hcd = &_ux_system_host->ux_system_host_hcd_array[0]; + + ux_test_dcd_sim_slave_disconnect(); + /* No wait because below. */ + ux_test_disconnect_host_wait_for_enum_completion(); + ux_test_memory_test_check(); +} + +VOID ux_test_disconnect_slave() +{ + + ux_test_dcd_sim_slave_disconnect(); +} + +VOID ux_test_connect_slave() +{ + + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); +} + +VOID ux_test_connect_host_wait_for_enum_completion() +{ + + /* No wait because ux_test_wait_for_enum_completion() expects the enum thread + to be running when it's called. */ + ux_test_hcd_sim_host_connect_no_wait(UX_FULL_SPEED_DEVICE); + ux_test_wait_for_enum_thread_completion(); +} + +VOID ux_test_connect_slave_and_host_wait_for_enum_completion() +{ + + ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE); + ux_test_connect_host_wait_for_enum_completion(); +} + +/* This is supposed to only change these parameters. In other words, the same + classes should still be registered after calling this. */ +VOID ux_test_change_device_parameters(UCHAR * device_framework_high_speed, ULONG device_framework_length_high_speed, + UCHAR * device_framework_full_speed, ULONG device_framework_length_full_speed, + UCHAR * string_framework, ULONG string_framework_length, + UCHAR * language_id_framework, ULONG language_id_framework_length, + UINT(*ux_system_slave_change_function)(ULONG)) +{ + +UX_SLAVE_CLASS *class; +UX_SLAVE_CLASS classes_copy[UX_MAX_SLAVE_CLASS_DRIVER]; +ULONG class_index; + + /* Disconnect device. */ + ux_test_dcd_sim_slave_disconnect(); + + /* First, save the classes. */ + memcpy(classes_copy, _ux_system_slave->ux_system_slave_class_array, sizeof(classes_copy)); + + /* Uninitialize classes. */ + for (class_index = 0; class_index < UX_SYSTEM_DEVICE_MAX_CLASS_GET(); class_index++) + { + + class = &_ux_system_slave->ux_system_slave_class_array[class_index]; + if (class->ux_slave_class_status == UX_USED) + UX_TEST_CHECK_SUCCESS(ux_device_stack_class_unregister((UCHAR *)class->ux_slave_class_name, class->ux_slave_class_entry_function)); + } + + /* Uninitialize the stack. */ + UX_TEST_CHECK_SUCCESS(ux_device_stack_uninitialize()); + + /* Now re-initialize stack with correct stuff. */ + UX_TEST_CHECK_SUCCESS(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_system_slave_change_function)); + + /* Now re-register the classes. */ + for (class_index = 0; class_index < UX_SYSTEM_DEVICE_MAX_CLASS_GET(); class_index++) + { + + class = &classes_copy[class_index]; + if (class->ux_slave_class_status == UX_USED) + UX_TEST_CHECK_SUCCESS(ux_device_stack_class_register((UCHAR *)class->ux_slave_class_name, + class->ux_slave_class_entry_function, + class->ux_slave_class_configuration_number, + class->ux_slave_class_interface_number, + class->ux_slave_class_interface_parameter)); + } +} + +UINT ux_test_host_stack_class_instance_get(UX_HOST_CLASS *host_class, UINT class_index, VOID **class_instance) +{ + +UINT status; +UINT timeout_ms = UX_TEST_TIMEOUT_MS; +#if defined(UX_HOST_STANDALONE) +ULONG t0, t, elapsed; + t0 = ux_utility_time_get(); +#endif + + do + { + + status = ux_host_stack_class_instance_get(host_class, class_index, class_instance); +#if defined(UX_HOST_STANDALONE) + ux_system_tasks_run(); + tx_thread_relinquish(); + t = ux_utility_time_get(); + elapsed = ux_utility_time_elapsed(t0, t); + if (elapsed >= UX_MS_TO_TICK_NON_ZERO(timeout_ms)) + return(UX_ERROR); +#else + tx_thread_sleep(MS_TO_TICK(10)); + timeout_ms -= 10; +#endif + + } while (status != UX_SUCCESS && timeout_ms); + + if (timeout_ms == 0) + return UX_ERROR; + + return UX_SUCCESS; +} + +UINT ux_test_wait_for_value_uint(UINT *current_value_ptr, UINT desired_value) +{ + +UINT timeout_ms = UX_TEST_TIMEOUT_MS; +#if defined(UX_HOST_STANDALONE) +ULONG t0, t, elapsed; + t0 = ux_utility_time_get(); +#endif + + while (*current_value_ptr != desired_value && timeout_ms) + { + +#if defined(UX_HOST_STANDALONE) + ux_system_tasks_run(); + tx_thread_relinquish(); + t = ux_utility_time_get(); + elapsed = ux_utility_time_elapsed(t0, t); + if (elapsed >= UX_MS_TO_TICK_NON_ZERO(timeout_ms)) + return(UX_ERROR); +#else + tx_thread_sleep(MS_TO_TICK(10)); + timeout_ms -= 10; +#endif + } + + if (timeout_ms == 0) + return UX_ERROR; + + return UX_SUCCESS; +} + +UINT ux_test_wait_for_value_ulong(ULONG *current_value_ptr, ULONG desired_value) +{ + +UINT timeout_ms = UX_TEST_TIMEOUT_MS; +#if defined(UX_HOST_STANDALONE) +ULONG t0, t, elapsed; + t0 = ux_utility_time_get(); +#endif + + while (*current_value_ptr != desired_value && timeout_ms) + { + +#if defined(UX_HOST_STANDALONE) + ux_system_tasks_run(); + tx_thread_relinquish(); + t = ux_utility_time_get(); + elapsed = ux_utility_time_elapsed(t0, t); + if (elapsed >= UX_MS_TO_TICK_NON_ZERO(timeout_ms)) + return(UX_ERROR); +#else + tx_thread_sleep(MS_TO_TICK(10)); + timeout_ms -= 10; +#endif + } + + if (timeout_ms == 0) + return UX_ERROR; + + return UX_SUCCESS; +} + +UINT ux_test_wait_for_value_uchar(UCHAR *current_value_ptr, UCHAR desired_value) +{ + +UINT timeout_ms = UX_TEST_TIMEOUT_MS; +#if defined(UX_HOST_STANDALONE) +ULONG t0, t, elapsed; + t0 = ux_utility_time_get(); +#endif + + while (*current_value_ptr != desired_value && timeout_ms) + { + +#if defined(UX_HOST_STANDALONE) + ux_system_tasks_run(); + tx_thread_relinquish(); + t = ux_utility_time_get(); + elapsed = ux_utility_time_elapsed(t0, t); + if (elapsed >= UX_MS_TO_TICK_NON_ZERO(timeout_ms)) + return(UX_ERROR); +#else + tx_thread_sleep(MS_TO_TICK(10)); + timeout_ms -= 10; +#endif + } + + if (timeout_ms == 0) + return UX_ERROR; + + return UX_SUCCESS; +} + +UINT ux_test_wait_for_non_null(VOID **current_value_ptr) +{ + +UINT timeout_ms = UX_TEST_TIMEOUT_MS; +#if defined(UX_HOST_STANDALONE) +ULONG t0, t, elapsed; + t0 = ux_utility_time_get(); +#endif + + while (*current_value_ptr == UX_NULL && timeout_ms) + { + +#if defined(UX_HOST_STANDALONE) + ux_system_tasks_run(); + tx_thread_relinquish(); + t = ux_utility_time_get(); + elapsed = ux_utility_time_elapsed(t0, t); + if (elapsed >= UX_MS_TO_TICK_NON_ZERO(timeout_ms)) + return(UX_ERROR); +#else + tx_thread_sleep(MS_TO_TICK(10)); + timeout_ms -= 10; +#endif + } + + if (timeout_ms == 0) + return UX_ERROR; + + return UX_SUCCESS; +} + +UINT ux_test_wait_for_null_wait_time(VOID **current_value_ptr, UINT wait_time_ms) +{ + +UINT timeout_ms = wait_time_ms; +#if defined(UX_HOST_STANDALONE) +ULONG t0, t, elapsed; + t0 = ux_utility_time_get(); +#endif + + while (*current_value_ptr != UX_NULL && timeout_ms) + { + +#if defined(UX_HOST_STANDALONE) + ux_system_tasks_run(); + tx_thread_relinquish(); + t = ux_utility_time_get(); + elapsed = ux_utility_time_elapsed(t0, t); + if (elapsed >= UX_MS_TO_TICK_NON_ZERO(timeout_ms)) + return(UX_ERROR); +#else + tx_thread_sleep(MS_TO_TICK(10)); + timeout_ms -= 10; +#endif + } + + if (*current_value_ptr == UX_NULL) + return(UX_SUCCESS); + + return UX_ERROR; +} + +UINT ux_test_wait_for_null(VOID **current_value_ptr) +{ + return ux_test_wait_for_null_wait_time(current_value_ptr, UX_TEST_TIMEOUT_MS); +} + +char *ux_test_file_base_name(char *path, int n) +{ + char *ptr = path, *slash = path; + int i; + for (i = 0; i < n; i ++) + { + if (*ptr == 0) + break; + if (*ptr == '\\' || *ptr == '/') + slash = ptr + 1; + ptr ++; + } + return(slash); +} + +void ux_test_assert_hit_hint(UCHAR on_off) +{ + ux_test_assert_hit_hint_off = !on_off; +} +void ux_test_assert_hit_exit(UCHAR on_off) +{ + ux_test_assert_hit_exit_off = !on_off; +} +ULONG ux_test_assert_hit_count_get(void) +{ + return ux_test_assert_hit_count; +} +void ux_test_assert_hit_count_reset(void) +{ + ux_test_assert_hit_count = 0; +} +void ux_test_assert_hit(char* file, INT line) +{ + ux_test_assert_hit_count ++; + if (!ux_test_assert_hit_hint_off) + printf("%s:%d Assert HIT!\n", file, line); + if (!ux_test_assert_hit_exit_off) + test_control_return(ux_test_assert_hit_exit_code); +} + +UINT ux_test_host_endpoint_write(UX_ENDPOINT *endpoint, UCHAR *buffer, ULONG length, ULONG *actual_length) +{ +UINT status; +UX_TRANSFER *transfer = &endpoint->ux_endpoint_transfer_request; + transfer->ux_transfer_request_data_pointer = buffer; + transfer->ux_transfer_request_requested_length = length; + status = ux_host_stack_transfer_request(transfer); +#if !defined(UX_HOST_STANDALONE) + if (status == UX_SUCCESS) + { + status = tx_semaphore_get(&transfer->ux_transfer_request_semaphore, + transfer->ux_transfer_request_timeout_value); + if (status != TX_SUCCESS) + { + ux_host_stack_transfer_request_abort(transfer); + status = UX_TRANSFER_TIMEOUT; + } + } +#endif + if (actual_length) + *actual_length = transfer->ux_transfer_request_actual_length; + return(status); +} diff --git a/test/regression/ux_test.h b/test/regression/ux_test.h new file mode 100644 index 00000000..a496aa23 --- /dev/null +++ b/test/regression/ux_test.h @@ -0,0 +1,540 @@ +/* USBX common things for testing. */ + +#ifndef _UX_TEST_H +#define _UX_TEST_H + +#include "nx_api.h" +#include "ux_api.h" + +#if 0 +#define stepinfo printf +#else +#define stepinfo(...) +#endif + + +/* Compile options check. */ +/* +UX_MAX_HCD=1 +UX_MAX_CLASS_DRIVER=1 +UX_MAX_DEVICES=1 +UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE +UX_MAX_DEVICE_ENDPOINTS=2 +UX_MAX_DEVICE_INTERFACES=1 +UX_MAX_SLAVE_INTERFACES=1 +UX_MAX_SLAVE_CLASS_DRIVER=1 +UX_MAX_SLAVE_LUN=1 +*/ +#define UX_TEST_MULTI_HCD_ON (UX_MAX_HCD > 1) +#define UX_TEST_MULTI_IFC_OVER(n) ( \ + (UX_MAX_SLAVE_INTERFACES > (n)) && \ + (!defined(UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE) || \ + (UX_MAX_DEVICE_INTERFACES > (n))) ) +#define UX_TEST_MULTI_IFC_ON UX_TEST_MULTI_IFC_OVER(1) +#define UX_TEST_MULTI_ALT_ON ( \ + !defined(UX_DEVICE_ALTERNATE_SETTING_SUPPORT_DISABLE)) +#define UX_TEST_MULTI_CLS_OVER(n) ( \ + UX_MAX_CLASS_DRIVER > (n) && \ + UX_MAX_SLAVE_CLASS_DRIVER > (n) ) +#define UX_TEST_MULTI_CLS_ON UX_TEST_MULTI_CLS_OVER(1) +#define UX_TEST_MULTI_DEV_ON (UX_MAX_DEVICES > 1) +#define UX_TEST_MULTI_EP_OVER(n) ( \ + (UX_MAX_DEVICE_ENDPOINTS > (n)) || \ + (!defined(UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE))) + +/* Define macros. */ +#define ARRAY_COUNT(array) (sizeof(array)/sizeof(array[0])) + +extern char *ux_test_file_base_name(char *path, int n); +#define UX_TEST_FILE_BASE_NAME(s) (ux_test_file_base_name(s, sizeof(s))) +#define UX_TEST_FILE UX_TEST_FILE_BASE_NAME(__FILE__) + +#define UX_TEST_ASSERT(expression) if (!(expression)) { printf("%s:%d Assert failed\n", UX_TEST_FILE, __LINE__); test_control_return(1); } +#define UX_TEST_ASSERT_MESSAGE(expression, ...) if (!(expression)) { printf("%s:%d Assert failed; ", UX_TEST_FILE, __LINE__); printf(__VA_ARGS__); test_control_return(1); } +#define UX_TEST_CHECK_CODE(code, expression) \ + { \ + UINT __status__ = (expression); \ + if (__status__ != (code)) \ + { \ + printf("%s : %d, error: 0x%x\n", UX_TEST_FILE_BASE_NAME(__FILE__), __LINE__, __status__); \ + test_control_return(1); \ + } \ + } +#define UX_TEST_CHECK_NOT_CODE(code, expression) \ + { \ + UINT __status__ = (expression); \ + if (__status__ == (code)) \ + { \ + printf("%s:%d error: 0x%x\n", UX_TEST_FILE, __LINE__, __status__); \ + test_control_return(1); \ + } \ + } +#define UX_TEST_CHECK_SUCCESS(expression) UX_TEST_CHECK_CODE(UX_SUCCESS, expression) +#define UX_TEST_CHECK_NOT_SUCCESS(expression) UX_TEST_CHECK_NOT_CODE(UX_SUCCESS, expression) + +typedef struct UX_TEST_ERROR_CALLBACK_ERROR_STRUCT +{ + UINT system_level; + UINT system_context; + UINT error_code; + + struct UX_TEST_ERROR_CALLBACK_ERROR_STRUCT *next; +} UX_TEST_ERROR_CALLBACK_ERROR; + +typedef struct UX_TEST_ERROR_CALLBACK_ACTION_STRUCT +{ + UX_TEST_ERROR_CALLBACK_ERROR *error; + VOID (*entry_func_error_callback_action)(); + UINT do_return; + + struct UX_TEST_ERROR_CALLBACK_ACTION *next; +} UX_TEST_ERROR_CALLBACK_ACTION; + +/* General setup request */ + +typedef struct _UX_TEST_SETUP_STRUCT { + UCHAR ux_test_setup_type; + UCHAR ux_test_setup_request; + USHORT ux_test_setup_value; + USHORT ux_test_setup_index; +} UX_TEST_SETUP; + +/* Interaction descriptor to insert action on specific entry function call. */ +/* function, request to match, port action, port status, request action, request EP, request data, request actual length, request status, status, additional callback, no return, thread */ + +typedef struct UX_TEST_ACTION_STRUCT { + + /* Function code to match */ + ULONG function; + /* Setup request to match */ + UX_TEST_SETUP *req_setup; + + /* Port action flags */ + ULONG port_action; + ULONG port_status; + + /* Request action flags */ + ULONG req_action; + ULONG req_ep_address; + UCHAR *req_data; + /* For comparing data, use this, not req_requested_len. */ + ULONG req_actual_len; + ULONG req_status; + + /* Status to return */ + ULONG status; + + /* Additional callback */ + VOID (*action_func)(struct UX_TEST_ACTION_STRUCT *action, VOID *params); + + /* No return */ + ULONG no_return; + + ULONG req_requested_len; + + /* _ux_host_stack_class_instance_create */ + UCHAR *class_name; + UINT class_name_length; + + /* _ux_device_stack_transfer_request */ + UCHAR endpoint_address; + ULONG slave_length; + ULONG host_length; + + /* ux_host_stack_transfer_request_action */ + ULONG requested_length; + UINT type; + UINT value; + UINT index; + UCHAR *data; + /* For matching parts of a transfer. */ + UCHAR *req_data_match_mask; + + /* _ux_device_stack_transfer_abort (none) */ + + /* _ux_host_class_storage_media_write */ + ULONG sector_start; + ULONG sector_count; + UCHAR *data_pointer; + + /* _ux_host_stack_interface_set */ + ULONG bInterfaceNumber; + ULONG bAlternateSetting; + + /* _ux_utility_memory_allocate */ + ULONG memory_alignment; + ULONG memory_cache_flag; + ULONG memory_size_requested; + + /* if there is name. */ + CHAR *name_ptr; + + /* tx_semaphore_get */ + TX_SEMAPHORE *semaphore_ptr; + ULONG wait_option; + + /* tx_semaphore_get */ + TX_MUTEX *mutex_ptr; + UINT inherit; + + /* tx_semaphore_create */ + CHAR *semaphore_name; + + /* ux_test_error_callback */ + UINT system_level; + UINT system_context; + UINT error_code; + + /* ux_slave_class_storage_media_read/write */ + VOID *storage; + ULONG lun; + USHORT number_blocks; + ULONG lba; + ULONG *media_status; + + /* ux_slave_class_storage_media_status */ + ULONG media_id; + + /* tx_thread_preemption_change */ + TX_THREAD *thread_ptr; + UINT new_threshold; + + /* _ux_host_stack_interface_set */ + UX_INTERFACE *interface; + + /* Thread to match. Necessary due to the following case: The storage class has a background thread that runs every 2 + seconds and performs a bulk transaction. What could happen is that we call ux_test_hcd_sim_host_set_actions and + get preempted before actually starting the test. This could cause the action to match a transaction made by + storage's background thread. */ + TX_THREAD *thread_to_match; + + /* Whether we invoke our callback before or after we call the real HCD. */ + UCHAR do_after; + + /* User data. */ + ALIGN_TYPE user_data; + + /* Additional check. */ + UCHAR (*check_func)(); + + /* If set, the params are ignored. */ + UCHAR ignore_params; + + struct UX_TEST_ACTION_STRUCT *next; + struct UX_TEST_ACTION_STRUCT *created_list_next; + UCHAR matched; + ULONG usbx_function; +} UX_TEST_ACTION; + +typedef UX_TEST_ACTION UX_TEST_SIM_ENTRY_ACTION; + +typedef enum UX_TEST_FUNCTIONS +{ + UX_TEST_NULL, + UX_TEST_OVERRIDE_TX_SEMAPHORE_GET, + UX_TEST_OVERRIDE_TX_SEMAPHORE_CREATE, + UX_TEST_OVERRIDE_TX_THREAD_PREEMPTION_CHANGE, + UX_TEST_OVERRIDE_TX_THREAD_CREATE, + UX_TEST_OVERRIDE_NX_PACKET_POOL_CREATE, + UX_TEST_OVERRIDE_NX_PACKET_ALLOCATE, + UX_TEST_OVERRIDE_TX_MUTEX_CREATE, + UX_TEST_OVERRIDE_TX_MUTEX_PUT, + UX_TEST_OVERRIDE_TX_MUTEX_GET, + UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, + UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, + UX_TEST_OVERRIDE_UX_UTILITY_MEMORY_ALLOCATE, + + /* Define functions where it's okay to return/change the logic. This should + only include user callbacks. */ + UX_TEST_OVERRIDE_USER_CALLBACKS, + UX_TEST_OVERRIDE_ERROR_CALLBACK, + UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ, + UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_WRITE, + UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_FLUSH, + UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_STATUS, + + /* Only for race condition tests. */ + UX_TEST_OVERRIDE_RACE_CONDITION_OVERRIDES, + UX_TEST_OVERRIDE_UX_HOST_STACK_TRANSFER_REQUEST, + UX_TEST_OVERRIDE_UX_HOST_STACK_INTERFACE_SET, + + UX_TEST_NUMBER_OVERRIDES, +} UX_TEST_FUNCTION; + +typedef struct UX_TEST_OVERRIDE_NX_PACKET_ALLOCATE_PARAMS +{ + NX_PACKET_POOL *pool_ptr; +} UX_TEST_OVERRIDE_NX_PACKET_ALLOCATE_PARAMS; + +typedef struct UX_TEST_OVERRIDE_NX_PACKET_POOL_CREATE_PARAMS +{ + CHAR *name_ptr; +} UX_TEST_OVERRIDE_NX_PACKET_POOL_CREATE_PARAMS; + +typedef struct UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ_WRITE_PARAMS +{ + VOID *storage; + ULONG lun; + UCHAR *data_pointer; + ULONG number_blocks; + ULONG lba; + ULONG *media_status; +} UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ_WRITE_FLUSH_PARAMS; + +typedef struct UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_STATUS_PARAMS +{ + VOID *storage; + ULONG lun; + ULONG media_id; + ULONG *media_status; +} UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_STATUS_PARAMS; + +typedef struct UX_TEST_OVERRIDE_UX_UTILITY_MEMORY_ALLOCATE_PARAMS +{ + ULONG memory_alignment; + ULONG memory_cache_flag; + ULONG memory_size_requested; +} UX_TEST_OVERRIDE_UX_UTILITY_MEMORY_ALLOCATE_PARAMS; + +typedef struct UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS +{ + UX_SLAVE_DCD *dcd; + UINT function; + VOID *parameter; +} UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS; + +typedef struct UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS +{ + UX_HCD *hcd; + UINT function; + VOID *parameter; +} UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS; + +typedef struct UX_TEST_OVERRIDE_TX_SEMAPHORE_GET_PARAMS +{ + TX_SEMAPHORE *semaphore_ptr; + ULONG wait_option; +} UX_TEST_OVERRIDE_TX_SEMAPHORE_GET_PARAMS; + +typedef struct UX_TEST_OVERRIDE_TX_MUTEX_CREATE_PARAMS +{ + TX_MUTEX *mutex_ptr; + CHAR *name_ptr; + UINT inherit; +} UX_TEST_OVERRIDE_TX_MUTEX_CREATE_PARAMS; + +typedef struct UX_TEST_OVERRIDE_TX_MUTEX_GET_PARAMS +{ + TX_MUTEX *mutex_ptr; + ULONG wait_option; +} UX_TEST_OVERRIDE_TX_MUTEX_GET_PARAMS; + +typedef struct UX_TEST_OVERRIDE_TX_MUTEX_PUT_PARAMS +{ + TX_MUTEX *mutex_ptr; +} UX_TEST_OVERRIDE_TX_MUTEX_PUT_PARAMS; + +typedef struct UX_TEST_OVERRIDE_TX_SEMAPHORE_CREATE_PARAMS +{ + TX_SEMAPHORE *semaphore; + CHAR *semaphore_name; + UINT initial_count; +} UX_TEST_OVERRIDE_TX_SEMAPHORE_CREATE_PARAMS; + +typedef struct UX_TEST_OVERRIDE_TX_THREAD_CREATE_PARAMS +{ + /* We only care about the name. */ + CHAR *name_ptr; +} UX_TEST_OVERRIDE_TX_THREAD_CREATE_PARAMS; + +typedef struct UX_TEST_OVERRIDE_UX_HOST_STACK_TRANSFER_REQUEST_PARAMS +{ + UX_TRANSFER *transfer_request; +} UX_TEST_OVERRIDE_UX_HOST_STACK_TRANSFER_REQUEST_PARAMS; + +typedef struct UX_TEST_OVERRIDE_TX_THREAD_PREEMPTION_CHANGE_PARAMS +{ + TX_THREAD *thread_ptr; + UINT new_threshold; +} UX_TEST_OVERRIDE_TX_THREAD_PREEMPTION_CHANGE_PARAMS; + +typedef struct UX_TEST_OVERRIDE_UX_HOST_STACK_INTERFACE_SET_PARAMS +{ + UX_INTERFACE *interface; +} UX_TEST_OVERRIDE_UX_HOST_STACK_INTERFACE_SET_PARAMS; + +typedef struct UX_TEST_OVERRIDE_NX_PACKET_TRANSMIT_RELEASE_PARAMS +{ + NX_PACKET **packet_ptr_ptr; +} UX_TEST_OVERRIDE_NX_PACKET_TRANSMIT_RELEASE_PARAMS; + +typedef struct UX_TEST_ERROR_CALLBACK_PARAMS +{ + UINT system_level; + UINT system_context; + UINT error_code; +} UX_TEST_ERROR_CALLBACK_PARAMS; + +typedef struct UX_TEST_GENERIC_CD +{ + VOID *controller_driver; + UINT function; + VOID *parameter; +} UX_TEST_GENERIC_CD; + +typedef struct UX_MEMORY_BLOCK_STRUCT +{ + struct UX_MEMORY_BLOCK_STRUCT *ux_memory_block_next; + UX_MEMORY_BYTE_POOL *ux_memory_byte_pool; +} UX_MEMORY_BLOCK; + +UINT ux_test_list_action_compare(UX_TEST_ACTION *list_item, UX_TEST_ACTION *action); + +VOID ux_test_remove_hook(UX_TEST_ACTION *action); +VOID ux_test_remove_hooks_from_array(UX_TEST_ACTION *actions); +VOID ux_test_remove_hooks_from_list(UX_TEST_ACTION *actions); + +UINT ux_test_link_hook(UX_TEST_ACTION *action); +VOID ux_test_link_hooks_from_array(UX_TEST_ACTION *actions); +VOID ux_test_link_hooks_from_list(UX_TEST_ACTION *actions); + +UINT ux_test_add_hook(UX_TEST_ACTION action); +VOID ux_test_add_hooks_from_array(UX_TEST_ACTION *actions); +VOID ux_test_add_hooks_from_list(UX_TEST_ACTION *actions); + +ULONG ux_test_do_hooks_before(UX_TEST_FUNCTION usbx_function, VOID *params); +VOID ux_test_do_hooks_after(UX_TEST_FUNCTION usbx_function, VOID *params); + +VOID ux_test_free_hook_actions(); + +VOID ux_test_free_user_list_actions(); +VOID ux_test_set_main_action_list_from_array(UX_TEST_ACTION *action); +VOID ux_test_set_main_action_list_from_list(UX_TEST_ACTION *new_actions); +VOID ux_test_add_action_to_user_list(UX_TEST_ACTION *list, UX_TEST_ACTION new_action); +VOID ux_test_add_action_to_main_list(UX_TEST_ACTION action); +VOID ux_test_add_action_to_main_list_multiple(UX_TEST_ACTION action, UINT); +VOID ux_test_hcd_sim_host_set_actions(UX_TEST_ACTION *action); +VOID ux_test_dcd_sim_slave_set_actions(UX_TEST_ACTION *action); +UX_TEST_ACTION ux_test_action_handler(UX_TEST_FUNCTION usbx_function, void *_params); +VOID ux_test_do_action_before(UX_TEST_ACTION *action, VOID *params); +VOID ux_test_do_action_after(UX_TEST_ACTION *action, VOID *params); +VOID ux_test_ignore_all_errors(); +VOID ux_test_unignore_all_errors(); +VOID ux_test_clear_main_list_actions(); +VOID ux_test_cleanup_everything(VOID); +VOID ux_test_turn_off_expedient(UCHAR *); +VOID ux_test_turn_on_expedient(UCHAR *); +UCHAR ux_test_is_expedient_on(); +VOID ux_test_set_expedient(UCHAR); +ULONG ux_test_calc_total_memory_allocated(ULONG memory_alignment, ULONG memory_cache_flag, ULONG memory_size_requested); +UCHAR ux_test_check_actions_empty(); +UINT ux_test_wait_for_empty_actions(); +UINT ux_test_get_num_actions_left(); +extern UX_TEST_ERROR_CALLBACK_ERROR ux_error_hcd_transfer_stalled; +VOID ux_test_error_callback(UINT system_level, UINT system_context, UINT error_code); +void ux_test_disconnect_slave_and_host_wait_for_enum_completion(); +VOID ux_test_connect_slave_and_host_wait_for_enum_completion(); +void ux_test_memory_test_initialize(); +void ux_test_memory_test_check(); +void ux_test_disconnect_slave_and_host_wait_for_enum_completion(); +VOID ux_test_wait_for_enum_thread_completion(); +UINT ux_test_host_stack_class_instance_get(UX_HOST_CLASS *host_class, UINT class_index, VOID **class_instance); +UINT ux_test_wait_for_value_uint(UINT *current_value, UINT desired_value); +UINT ux_test_wait_for_value_ulong(ULONG *current_value, ULONG desired_value); +UINT ux_test_wait_for_value_uchar(UCHAR *current_value_ptr, UCHAR desired_value); +UINT ux_test_wait_for_non_null(VOID **current_value_ptr); +UINT ux_test_wait_for_null(VOID **current_value_ptr); +VOID ux_test_connect_host_wait_for_enum_completion(); +VOID ux_test_disconnect_host_no_wait(); +VOID ux_test_disconnect_slave(); +VOID ux_test_connect_slave(); +VOID ux_test_disconnect_host_wait_for_enum_completion(); +VOID ux_test_change_device_parameters(UCHAR * device_framework_high_speed, ULONG device_framework_length_high_speed, + UCHAR * device_framework_full_speed, ULONG device_framework_length_full_speed, + UCHAR * string_framework, ULONG string_framework_length, + UCHAR * language_id_framework, ULONG language_id_framework_length, + UINT(*ux_system_slave_change_function)(ULONG)); +UINT ux_test_wait_for_empty_actions_wait_time(UINT wait_time_ms); +UINT ux_test_wait_for_null_wait_time(VOID **current_value_ptr, UINT wait_time_ms); + +VOID _ux_test_main_action_list_thread_update(TX_THREAD *old, TX_THREAD *new); +VOID _ux_test_main_action_list_semaphore_update(TX_SEMAPHORE *old, TX_SEMAPHORE *new); +VOID _ux_test_main_action_list_mutex_update(TX_MUTEX *old, TX_MUTEX *new); + +UINT ux_test_host_endpoint_write(UX_ENDPOINT *endpoint, UCHAR *buffer, ULONG length, ULONG *actual_length); + +/* Action flags */ + +#define UX_TEST_SIM_REQ_ANSWER 0x80 + +#define UX_TEST_MATCH_EP 0x01 +#define UX_TEST_MATCH_REQ_LEN 0x40 + +#define UX_TEST_SETUP_MATCH_REQUEST 0x02 +#define UX_TEST_SETUP_MATCH_VALUE 0x04 +#define UX_TEST_SETUP_MATCH_INDEX 0x08 + +#define UX_TEST_SETUP_MATCH_REQ (UX_TEST_SETUP_MATCH_REQUEST) +#define UX_TEST_SETUP_MATCH_REQ_V (UX_TEST_SETUP_MATCH_REQ | UX_TEST_SETUP_MATCH_VALUE) +#define UX_TEST_SETUP_MATCH_REQ_V_I (UX_TEST_SETUP_MATCH_REQ_V | UX_TEST_SETUP_MATCH_INDEX) + +#define UX_TEST_SETUP_MATCH_EP_REQ (UX_TEST_SETUP_MATCH_REQUEST | UX_TEST_MATCH_EP) +#define UX_TEST_SETUP_MATCH_EP_REQ_V (UX_TEST_SETUP_MATCH_EP_REQ | UX_TEST_SETUP_MATCH_VALUE) +#define UX_TEST_SETUP_MATCH_EP_REQ_V_I (UX_TEST_SETUP_MATCH_EP_REQ_V | UX_TEST_SETUP_MATCH_INDEX) + +/* Expected Requests */ + +#define UX_TEST_SETUP_SetAddress {0x00,0x05,0x0001,0x0000} +#define UX_TEST_SETUP_GetDevDescr {0x80,0x06,0x0100,0x0000} +#define UX_TEST_SETUP_GetCfgDescr {0x80,0x06,0x0200,0x0000} +#define UX_TEST_SETUP_SetConfigure {0x00,0x09,0x0001,0x0000} + +#define UX_TEST_SETUP_CDCACM_GetLineCoding {0xa1, 0x21, 0x0000, 0x0000} +#define UX_TEST_SETUP_CDCACM_SetLineCoding {0x21, 0x20, 0x0000, 0x0000} +#define UX_TEST_SETUP_CDCACM_SetLineState {0x21, 0x22, 0x0003, 0x0000} + +#define UX_TEST_SETUP_STORAGE_GetMaxLun {0xa1, 0xfe, 0x0000, 0x0001} +#define UX_TEST_SETUP_STORAGE_Reset {0x21, 0xff, 0x0000, 0x0000} + +#define UX_TEST_PORT_STATUS_DISC 0 +#define UX_TEST_PORT_STATUS_LS_CONN UX_PS_CCS | UX_PS_DS_LS +#define UX_TEST_PORT_STATUS_FS_CONN UX_PS_CCS | UX_PS_DS_FS +#define UX_TEST_PORT_STATUS_HS_CONN UX_PS_CCS | UX_PS_DS_HS + + + +UINT ux_test_breakable_sleep(ULONG tick, UINT (*sleep_break_check_callback)(VOID)); +UINT ux_test_sleep_break_if(ULONG tick, UINT (*check)(VOID), UINT break_on_match_or_not, UINT rc_to_match); +#define ux_test_sleep(t) ux_test_sleep_break_if(t, UX_NULL, 1, UX_SUCCESS) +#define ux_test_sleep_break_on_success(t,c) ux_test_sleep_break_if(t, c, 1, UX_SUCCESS) +#define ux_test_sleep_break_on_error(t,c) ux_test_sleep_break_if(t, c, 0, UX_SUCCESS) + +void test_control_return(UINT status); + +void ux_test_assert_hit_hint(UCHAR on_off); +void ux_test_assert_hit_exit(UCHAR on_off); +ULONG ux_test_assert_hit_count_get(void); +void ux_test_assert_hit_count_reset(void); + +static inline int ux_test_memory_is_freed(void *memory) +{ +UCHAR *work_ptr; +UCHAR *temp_ptr; +ALIGN_TYPE *free_ptr; +int is_free = 0; + UX_TEST_ASSERT(memory); + _ux_system_mutex_on(&_ux_system -> ux_system_mutex); + work_ptr = UX_VOID_TO_UCHAR_POINTER_CONVERT(memory); + { + work_ptr = UX_UCHAR_POINTER_SUB(work_ptr, UX_MEMORY_BLOCK_HEADER_SIZE); + temp_ptr = UX_UCHAR_POINTER_ADD(work_ptr, (sizeof(UCHAR *))); + free_ptr = UX_UCHAR_TO_ALIGN_TYPE_POINTER_CONVERT(temp_ptr); + if ((*free_ptr) == UX_BYTE_BLOCK_FREE) + is_free = 1; + } + _ux_system_mutex_off(&_ux_system -> ux_system_mutex); + return(is_free); +} +#define ux_test_regular_memory_free() _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available + +#endif /* _UX_TEST_H */ diff --git a/test/regression/ux_test_actions.h b/test/regression/ux_test_actions.h new file mode 100644 index 00000000..bbe0f067 --- /dev/null +++ b/test/regression/ux_test_actions.h @@ -0,0 +1,21 @@ +#ifndef UX_TEST_ACTIONS_H +#define UX_TEST_ACTIONS_H + +#include "ux_test.h" + +static UX_TEST_ACTION create_error_match_action(UINT system_level, UINT system_context, UINT error_code) +{ + +UX_TEST_ACTION action = { 0 }; + + + action.usbx_function = UX_TEST_OVERRIDE_ERROR_CALLBACK; + action.system_level = system_level; + action.system_context = system_context; + action.error_code = error_code; + action.no_return = 1; + + return action; +} + +#endif \ No newline at end of file diff --git a/test/regression/ux_test_dcd_sim_slave.c b/test/regression/ux_test_dcd_sim_slave.c new file mode 100644 index 00000000..ffda484e --- /dev/null +++ b/test/regression/ux_test_dcd_sim_slave.c @@ -0,0 +1,265 @@ +/* This test simulator is designed to redirect simulate ux_hcd_sim_slave_ APIs for test. */ + +#include "tx_api.h" +#include "tx_thread.h" + +#include "ux_api.h" +#include "ux_dcd_sim_slave.h" + +#include "ux_test_dcd_sim_slave.h" +#include "ux_test_utility_sim.h" + +static ULONG _ux_dcd_sim_slave_speed = UX_FULL_SPEED_DEVICE; +static UCHAR *_ux_dcd_sim_framework = UX_NULL; +static ULONG _ux_dcd_sim_framework_length = 0; + +static UX_TEST_DCD_SIM_ACTION *ux_test_actions = UX_NULL; +static UX_TEST_DCD_SIM_ACTION *ux_test_main_action_list; + +VOID ux_test_dcd_sim_slave_cleanup(VOID) +{ + _ux_dcd_sim_slave_speed = UX_FULL_SPEED_DEVICE; + + _ux_dcd_sim_framework = UX_NULL; + _ux_dcd_sim_framework_length = 0; + + ux_test_actions = UX_NULL; + ux_test_main_action_list = UX_NULL; +} + +VOID ux_test_dcd_sim_slave_disconnect(VOID) +{ + +#if 1 +UINT old_threshold; +#else +TX_INTERRUPT_SAVE_AREA +#endif + +#if 1 + /* Disconnection is usually handled in an ISR, which cannot be preempted. Copy behavior. + Note that the regular TX_DISABLE doesn't work on Windows. Might not work for Linux + either. */ + tx_thread_preemption_change(tx_thread_identify(), 0, &old_threshold); +#else + TX_DISABLE +#endif + + ux_device_stack_disconnect(); + +#if 1 + tx_thread_preemption_change(tx_thread_identify(), old_threshold, &old_threshold); +#else + TX_RESTORE +#endif +} + +VOID ux_test_dcd_sim_slave_connect(ULONG speed) +{ + _ux_dcd_sim_slave_speed = speed; + //_ux_dcd_sim_slave_initialize_complete(); +} + +VOID ux_test_dcd_sim_slave_connect_framework(UCHAR * framework, ULONG framework_length) +{ + _ux_dcd_sim_framework = framework; + _ux_dcd_sim_framework_length = framework_length; + //_ux_dcd_sim_slave_initialize_complete(); +} + +/* Fork and modified to replace _ux_dcd_sim_slave_initialize_complete in lib for testing control. */ +UINT _ux_dcd_sim_slave_initialize_complete(VOID) +{ + +UX_SLAVE_DCD *dcd; +UX_SLAVE_DEVICE *device; +UCHAR * device_framework; +UX_SLAVE_TRANSFER *transfer_request; + + /* Get the pointer to the DCD. */ + dcd = &_ux_system_slave -> ux_system_slave_dcd; + + /* Get the pointer to the device. */ + device = &_ux_system_slave -> ux_system_slave_device; + + if (_ux_dcd_sim_framework != UX_NULL && _ux_dcd_sim_framework_length != 0) + { + + /* Initialize customized framework. */ + _ux_system_slave -> ux_system_slave_device_framework = _ux_dcd_sim_framework; + _ux_system_slave -> ux_system_slave_device_framework_length = _ux_dcd_sim_framework_length; + } + else + { + /* Slave simulator is a Full/high speed controller. */ + if (_ux_dcd_sim_slave_speed == UX_HIGH_SPEED_DEVICE) + { + + _ux_system_slave -> ux_system_slave_device_framework = _ux_system_slave -> ux_system_slave_device_framework_high_speed; + _ux_system_slave -> ux_system_slave_device_framework_length = _ux_system_slave -> ux_system_slave_device_framework_length_high_speed; + } + else + { + + _ux_system_slave -> ux_system_slave_device_framework = _ux_system_slave -> ux_system_slave_device_framework_full_speed; + _ux_system_slave -> ux_system_slave_device_framework_length = _ux_system_slave -> ux_system_slave_device_framework_length_full_speed; + } + /* Save device speed. */ + _ux_system_slave->ux_system_slave_speed = _ux_dcd_sim_slave_speed; + } + + /* Get the device framework pointer. */ + device_framework = _ux_system_slave -> ux_system_slave_device_framework; + + /* And create the decompressed device descriptor structure. */ + _ux_utility_descriptor_parse(device_framework, + _ux_system_device_descriptor_structure, + UX_DEVICE_DESCRIPTOR_ENTRIES, + (UCHAR *) &device -> ux_slave_device_descriptor); + + /* Now we create a transfer request to accept the first SETUP packet + and get the ball running. First get the address of the endpoint + transfer request container. */ + transfer_request = &device -> ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request; + + /* Set the timeout to be for Control Endpoint. */ + transfer_request -> ux_slave_transfer_request_timeout = MS_TO_TICK(UX_CONTROL_TRANSFER_TIMEOUT); + + /* Adjust the current data pointer as well. */ + transfer_request -> ux_slave_transfer_request_current_data_pointer = + transfer_request -> ux_slave_transfer_request_data_pointer; + + /* Update the transfer request endpoint pointer with the default endpoint. */ + transfer_request -> ux_slave_transfer_request_endpoint = &device -> ux_slave_device_control_endpoint; + + /* The control endpoint max packet size needs to be filled manually in its descriptor. */ + transfer_request -> ux_slave_transfer_request_endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize = + device -> ux_slave_device_descriptor.bMaxPacketSize0; + + /* On the control endpoint, always expect the maximum. */ + transfer_request -> ux_slave_transfer_request_requested_length = + device -> ux_slave_device_descriptor.bMaxPacketSize0; + + /* Attach the control endpoint to the transfer request. */ + transfer_request -> ux_slave_transfer_request_endpoint = &device -> ux_slave_device_control_endpoint; + + /* Create the default control endpoint attached to the device. + Once this endpoint is enabled, the host can then send a setup packet + The device controller will receive it and will call the setup function + module. */ + dcd -> ux_slave_dcd_function(dcd, UX_DCD_CREATE_ENDPOINT, + (VOID *) &device -> ux_slave_device_control_endpoint); + + /* Ensure the control endpoint is properly reset. */ + device -> ux_slave_device_control_endpoint.ux_slave_endpoint_state = UX_ENDPOINT_RESET; + + /* A SETUP packet is a DATA IN operation. */ + transfer_request -> ux_slave_transfer_request_phase = UX_TRANSFER_PHASE_DATA_IN; + + /* We are now ready for the USB device to accept the first packet when connected. */ + return(UX_SUCCESS); +} + +static UINT last_function = 0; +static char *_func_name[] = { + "", + "DISABLE_CONTROLLER", + "GET_PORT_STATUS", + "ENABLE_PORT", + "DISABLE_PORT", + "POWER_ON_PORT", + "POWER_DOWN_PORT", + "SUSPEND_PORT", + "RESUME_PORT", + "RESET_PORT", + "GET_FRAME_NUMBER", + "SET_FRAME_NUMBER", + "TRANSFER_REQUEST", + "TRANSFER_ABORT", + "CREATE_ENDPOINT", + "DESTROY_ENDPOINT", + "RESET_ENDPOINT", + "SET_DEVICE_ADDRESS", + "ISR_PENDING", + "CHANGE_STATE", + "STALL_ENDPOINT", + "ENDPOINT_STATUS" +}; + + + +UINT _ux_test_dcd_sim_slave_function(UX_SLAVE_DCD *dcd, UINT function, VOID *parameter) +{ + +UINT status; +UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION_PARAMS params = { dcd, function, parameter }; +UX_TEST_ACTION action; + + + /* Perform hooked callbacks. */ + ux_test_do_hooks_before(UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, ¶ms); + + action = ux_test_action_handler(UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, ¶ms); + ux_test_do_action_before(&action, ¶ms); + + /* NOTE: This shouldn't be used anymore. */ + if (ux_test_is_expedient_on()) + { + if (action.matched && !action.do_after) + { + if (!action.no_return) + { + return action.status; + } + } + } + + status = _ux_dcd_sim_slave_function(dcd, function, parameter); + + ux_test_do_action_after(&action, ¶ms); + + /* NOTE: This shouldn't be used anymore. */ + if (ux_test_is_expedient_on()) + { + if (action.matched && action.do_after) + { + if (!action.no_return) + { + return action.status; + } + } + } + + /* Perform hooked callbacks. */ + ux_test_do_hooks_after(UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION, ¶ms); + + /* Return completion status. */ + return(status); +} + +UINT _ux_test_dcd_sim_slave_initialize(VOID) +{ +UINT status; +UX_SLAVE_DEVICE *device; +UX_SLAVE_DCD *dcd; + + status = _ux_dcd_sim_slave_initialize(); + + /* Redirect the entry function */ + device = &_ux_system_slave -> ux_system_slave_device; + dcd = &_ux_system_slave -> ux_system_slave_dcd; + dcd -> ux_slave_dcd_function = _ux_test_dcd_sim_slave_function; + + return status; +} + +VOID ux_test_dcd_sim_slave_transfer_done(UX_SLAVE_TRANSFER *transfer, UINT code) +{ +UX_SLAVE_ENDPOINT *endpoint = transfer -> ux_slave_transfer_request_endpoint; +UX_DCD_SIM_SLAVE_ED *slave_ed = (UX_DCD_SIM_SLAVE_ED *)endpoint -> ux_slave_endpoint_ed; + transfer -> ux_slave_transfer_request_completion_code = code; + transfer -> ux_slave_transfer_request_status = UX_TRANSFER_STATUS_COMPLETED; + slave_ed -> ux_sim_slave_ed_status |= UX_DCD_SIM_SLAVE_ED_STATUS_TRANSFER; + slave_ed -> ux_sim_slave_ed_status |= UX_DCD_SIM_SLAVE_ED_STATUS_DONE; + _ux_device_semaphore_put(&transfer -> ux_slave_transfer_request_semaphore); +} diff --git a/test/regression/ux_test_dcd_sim_slave.h b/test/regression/ux_test_dcd_sim_slave.h new file mode 100644 index 00000000..4aad6598 --- /dev/null +++ b/test/regression/ux_test_dcd_sim_slave.h @@ -0,0 +1,24 @@ +/* This test simulator is designed to simulate ux_hcd_ APIs for test. */ + +#ifndef _UX_TEST_DCD_SIM_SLAVE_H +#define _UX_TEST_DCD_SIM_SLAVE_H + +#include "ux_test.h" + +/* Uses general entry action simulator */ +#define _UX_TEST_DCD_SIM_ACTION_STRUCT _UX_TEST_SIM_ENTRY_ACTION_STRUCT +#define UX_TEST_DCD_SIM_ACTION UX_TEST_SIM_ENTRY_ACTION + +VOID ux_test_dcd_sim_slave_disconnect(VOID); +VOID ux_test_dcd_sim_slave_connect (ULONG speed); +VOID ux_test_dcd_sim_slave_connect_framework(UCHAR * framework, ULONG framework_length); + +UINT _ux_test_dcd_sim_slave_initialize(VOID); + +VOID ux_test_dcd_sim_slave_cleanup(VOID); + +UINT _ux_test_dcd_sim_slave_function(UX_SLAVE_DCD *dcd, UINT function, VOID *parameter); + +VOID ux_test_dcd_sim_slave_transfer_done(UX_SLAVE_TRANSFER *transfer, UINT code); + +#endif /* _UX_TEST_DCD_SIM_SLAVE_H */ diff --git a/test/regression/ux_test_hcd_sim_host.c b/test/regression/ux_test_hcd_sim_host.c new file mode 100644 index 00000000..147b8d7a --- /dev/null +++ b/test/regression/ux_test_hcd_sim_host.c @@ -0,0 +1,291 @@ +/* This test simulator is designed to simulate ux_hcd_ APIs for test. */ + +#include "tx_api.h" +#include "tx_thread.h" + +#include "ux_api.h" +#include "ux_hcd_sim_host.h" + +#include "ux_test_utility_sim.h" +#include "ux_test_hcd_sim_host.h" + +void test_control_return(UINT status); + +ULONG ux_test_port_status = UX_PS_CCS | UX_PS_DS_FS; + +/* We have a no wait version because in a real world scenario, there is no waiting. */ +VOID ux_test_hcd_sim_host_disconnect_no_wait(VOID) +{ + +UINT status; +UX_HCD *hcd = &_ux_system_host -> ux_system_host_hcd_array[0]; +UX_HCD_SIM_HOST *hcd_sim_host = hcd -> ux_hcd_controller_hardware; + + + /* Port is disconnected. */ + ux_test_port_status = 0; + if (hcd_sim_host != UX_NULL) + { +#if !defined(UX_HOST_STANDALONE) + /* Don't let the timer function run, or else the HCD thread will perform transfer requests. */ + status = tx_timer_deactivate(&hcd_sim_host -> ux_hcd_sim_host_timer); + if (status != TX_SUCCESS) + { + + printf("test_hcd_sim_host #%d, error: %d\n", __LINE__, status); + test_control_return(1); + } +#endif + } + /* Signal change on the port (HCD0.RH.PORT0). */ + hcd -> ux_hcd_root_hub_signal[0] = 1; + /* Signal detach to host enum thread. */ + _ux_host_semaphore_put(&_ux_system_host -> ux_system_host_enum_semaphore); +} + +VOID ux_test_hcd_sim_host_disconnect(VOID) +{ + + ux_test_hcd_sim_host_disconnect_no_wait(); + +#if defined(UX_HOST_STANDALONE) + { + UX_HCD *hcd = &_ux_system_host -> ux_system_host_hcd_array[0]; + ULONG n_device = hcd -> ux_hcd_nb_devices; + for (unsigned i = 0; i < 20000; i ++) + { + ux_system_tasks_run(); + if (hcd -> ux_hcd_nb_devices == 0 || + hcd -> ux_hcd_nb_devices < n_device) + break; + } + } +#else + + /* Sleep current thread for enum thread to run. */ + tx_thread_sleep(100); +#endif +} + +VOID ux_test_hcd_sim_host_connect_no_wait(ULONG speed) +{ + +UINT status; +UX_HCD *hcd = &_ux_system_host -> ux_system_host_hcd_array[0]; +UX_HCD_SIM_HOST *hcd_sim_host = hcd -> ux_hcd_controller_hardware; + + + /* Connect with specific speed. */ + switch(speed) + { + case UX_LOW_SPEED_DEVICE: + + ux_test_port_status = UX_PS_CCS | UX_PS_DS_LS; + break; + + case UX_FULL_SPEED_DEVICE: + + ux_test_port_status = UX_PS_CCS | UX_PS_DS_FS; + break; + + case UX_HIGH_SPEED_DEVICE: + + ux_test_port_status = UX_PS_CCS | UX_PS_DS_HS; + break; + + default: + break; + } + +#if !defined(UX_HOST_STANDALONE) + /* Allow the timer function to run, or else the HCD thread won't perform transfer requests. */ + status = tx_timer_activate(&hcd_sim_host -> ux_hcd_sim_host_timer); + if (status != TX_SUCCESS && + /* Was the timer already active? */ + status != TX_ACTIVATE_ERROR) + { + + printf("test_hcd_sim_host #%d, error code: %d\n", __LINE__, status); + test_control_return(1); + } +#endif + + /* Signal change on the port (HCD0.RH.PORT0). */ + _ux_system_host -> ux_system_host_hcd_array -> ux_hcd_root_hub_signal[0] = 1; + /* Signal detach to host enum thread. */ + _ux_host_semaphore_put(&_ux_system_host -> ux_system_host_enum_semaphore); +} + +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); +} + +/* Fork and modify _ux_hcd_sim_host_port_status_get. */ + +ULONG _ux_hcd_sim_host_port_status_get(UX_HCD_SIM_HOST *hcd_sim_host, ULONG port_index) +{ + + /* Check to see if this port is valid on this controller. */ + if (hcd_sim_host -> ux_hcd_sim_host_nb_root_hubs < port_index) + { + + /* Error trap. */ + _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HCD, UX_PORT_INDEX_UNKNOWN); + + /* If trace is enabled, insert this event into the trace buffer. */ + UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_PORT_INDEX_UNKNOWN, port_index, 0, 0, UX_TRACE_ERRORS, 0, 0) + + return(UX_PORT_INDEX_UNKNOWN); + } + + /* Return port status. */ + return(ux_test_port_status); +} + +static UINT last_function = 0; +static char *_func_name[] = { + "", + "DISABLE_CONTROLLER", + "GET_PORT_STATUS", + "ENABLE_PORT", + "DISABLE_PORT", + "POWER_ON_PORT", + "POWER_DOWN_PORT", + "SUSPEND_PORT", + "RESUME_PORT", + "RESET_PORT", + "GET_FRAME_NUMBER", + "SET_FRAME_NUMBER", + "TRANSFER_REQUEST", + "TRANSFER_ABORT", + "CREATE_ENDPOINT", + "DESTROY_ENDPOINT", + "RESET_ENDPOINT", + "PROCESS_DONE_QUEUE" +}; + +#if 0 /* Not sure what the purpose of this is. -Nick */ +UINT _ux_test_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; +UCHAR act = 0; +UX_TRANSFER *req; +UX_ENDPOINT *ep; +TX_THREAD *this_thread; +UINT i; +UCHAR action_matched; + + +#if 0 /* TODO: Enable/disable HCD entry call display */ +if (function != last_function) +{ + last_function = function; + printf("\n_H %2d(%s) ", function, _func_name[function]); +} +else + printf("."); +#endif + + status = ux_test_cd_handle_action(action, hcd, UX_TEST_CD_TYPE_HCD, function, parameter, &action_matched); + if (action_matched) + { + /* Proceed to next action */ + action++; + if (action->function == 0) + action = UX_NULL; + } + + return status; +} +#endif + +UINT _ux_test_hcd_sim_host_dummy_entry(UX_HCD *hcd, UINT function, VOID *parameter) +{ + if (function == UX_HCD_GET_PORT_STATUS) + /* Never connected. */ + return 0; + + return _ux_hcd_sim_host_entry(hcd, function, parameter); +} + +UINT _ux_test_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter) +{ + +UINT status; +UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS params = { hcd, function, parameter }; +UX_TEST_ACTION action; +ULONG action_taken; + + /* Perform hooked callbacks. */ + action_taken = ux_test_do_hooks_before(UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, ¶ms); + if (action_taken & 0x80000000u) /* The hook breaks normal process. */ + return(action.status); + + action = ux_test_action_handler(UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, ¶ms); + ux_test_do_action_before(&action, ¶ms); + + if (ux_test_is_expedient_on()) + { + if (action.matched && !action.do_after) + { + if (!action.no_return) + { + return action.status; + } + } + } + + status = _ux_hcd_sim_host_entry(hcd, function, parameter); + + ux_test_do_action_after(&action, ¶ms); + + if (ux_test_is_expedient_on()) + { + if (action.matched && action.do_after) + { + if (!action.no_return) + { + return action.status; + } + } + } + + /* Perform hooked callbacks. */ + ux_test_do_hooks_after(UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, ¶ms); + + /* Return completion status. */ + return(status); +} + +UINT _ux_test_hcd_sim_host_initialize(UX_HCD *hcd) +{ +UINT status; + + if (ux_utility_name_match((UCHAR*)"dummy", hcd->ux_hcd_name, 5)) + { + /* Use dummy halted */ + hcd -> ux_hcd_status = UX_HCD_STATUS_DEAD; /* Must not be UX_UNUSED == UX_HCD_STATUS_HALTED */ + hcd -> ux_hcd_entry_function = _ux_test_hcd_sim_host_dummy_entry; + return UX_SUCCESS; + } + + /* Use hcd sim host */ + status = _ux_hcd_sim_host_initialize(hcd); + + /* Redirect the entry function */ + hcd -> ux_hcd_entry_function = _ux_test_hcd_sim_host_entry; + + return status; +} + +VOID ux_test_hcd_sim_host_cleanup(VOID) +{ + + ux_test_port_status = UX_PS_CCS | UX_PS_DS_FS; +} diff --git a/test/regression/ux_test_hcd_sim_host.h b/test/regression/ux_test_hcd_sim_host.h new file mode 100644 index 00000000..cd398eb2 --- /dev/null +++ b/test/regression/ux_test_hcd_sim_host.h @@ -0,0 +1,23 @@ +/* This test simulator is designed to simulate ux_hcd_ APIs for test. */ + +#ifndef _UX_TEST_HCD_SIM_HOST_H +#define _UX_TEST_HCD_SIM_HOST_H + +#include "ux_test.h" + +/* Uses general entry action simulator */ +#define _UX_TEST_HCD_SIM_ACTION_STRUCT _UX_TEST_SIM_ENTRY_ACTION_STRUCT +#define UX_TEST_HCD_SIM_ACTION UX_TEST_SIM_ENTRY_ACTION + +VOID ux_test_hcd_sim_host_disconnect_no_wait(VOID); +VOID ux_test_hcd_sim_host_disconnect(VOID); +VOID ux_test_hcd_sim_host_connect_no_wait(ULONG speed); +VOID ux_test_hcd_sim_host_connect(ULONG speed); + +UINT _ux_test_hcd_sim_host_initialize(UX_HCD *hcd); + +VOID ux_test_hcd_sim_host_cleanup(VOID); + +UINT _ux_test_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter); + +#endif /* _UX_TEST_HCD_SIM_HOST_H */ diff --git a/test/regression/ux_test_jpeg_image.h b/test/regression/ux_test_jpeg_image.h new file mode 100644 index 00000000..4690288d --- /dev/null +++ b/test/regression/ux_test_jpeg_image.h @@ -0,0 +1,1652 @@ +#ifndef UX_TEST_JPEG_IMAGE_H +#define UX_TEST_JPEG_IMAGE_H + +static unsigned char ux_test_jpeg_image[] = +{ + 0xff,0xd8,0xff,0xe0,0x00,0x08,0x50,0x69,0x63,0x61,0x73,0x61,0xff, + 0xed,0x00,0xde,0x50,0x68,0x6f,0x74,0x6f,0x73,0x68,0x6f,0x70,0x20, + 0x33,0x2e,0x30,0x00,0x38,0x42,0x49,0x4d,0x04,0x04,0x00,0x00,0x00, + 0x00,0x00,0xc1,0x1c,0x02,0x50,0x00,0x0b,0x50,0x69,0x63,0x61,0x73, + 0x61,0x20,0x32,0x2e,0x30,0x00,0x1c,0x02,0x75,0x00,0x98,0x3c,0x68, + 0x65,0x6c,0x6c,0x6f,0x73,0x74,0x61,0x6d,0x70,0x3e,0x0a,0x20,0x3c, + 0x67,0x69,0x64,0x3e,0x30,0x2d,0x30,0x2d,0x37,0x66,0x66,0x66,0x66, + 0x66,0x66,0x66,0x2d,0x30,0x3c,0x2f,0x67,0x69,0x64,0x3e,0x0a,0x20, + 0x3c,0x6d,0x64,0x35,0x3e,0x30,0x2d,0x30,0x2d,0x30,0x2d,0x30,0x3c, + 0x2f,0x6d,0x64,0x35,0x3e,0x0a,0x20,0x3c,0x6f,0x72,0x69,0x67,0x57, + 0x69,0x64,0x74,0x68,0x3e,0x30,0x3c,0x2f,0x6f,0x72,0x69,0x67,0x57, + 0x69,0x64,0x74,0x68,0x3e,0x0a,0x20,0x3c,0x6f,0x72,0x69,0x67,0x48, + 0x65,0x69,0x67,0x68,0x74,0x3e,0x30,0x3c,0x2f,0x6f,0x72,0x69,0x67, + 0x48,0x65,0x69,0x67,0x68,0x74,0x3e,0x0a,0x20,0x3c,0x6f,0x72,0x69, + 0x67,0x53,0x69,0x7a,0x65,0x3e,0x30,0x3c,0x2f,0x6f,0x72,0x69,0x67, + 0x53,0x69,0x7a,0x65,0x3e,0x0a,0x3c,0x2f,0x68,0x65,0x6c,0x6c,0x6f, + 0x73,0x74,0x61,0x6d,0x70,0x3e,0x0a,0x1c,0x02,0x76,0x00,0x0f,0x3c, + 0x70,0x69,0x63,0x61,0x73,0x61,0x73,0x74,0x61,0x6d,0x70,0x2f,0x3e, + 0x0a,0x00,0xff,0xe0,0x00,0x10,0x4a,0x46,0x49,0x46,0x00,0x01,0x01, + 0x00,0x00,0x01,0x00,0x01,0x00,0x00,0xff,0xdb,0x00,0x43,0x00,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0xff,0xdb, + 0x00,0x43,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0xff,0xc4,0x01,0xa2,0x00,0x00,0x01,0x05,0x01,0x01,0x01, + 0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02, + 0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x10,0x00,0x02,0x01, + 0x03,0x03,0x02,0x04,0x03,0x05,0x05,0x04,0x04,0x00,0x00,0x01,0x7d, + 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13, + 0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,0x23,0x42, + 0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a, + 0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,0x29,0x2a,0x34,0x35, + 0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a, + 0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x63,0x64,0x65,0x66,0x67, + 0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84, + 0x85,0x86,0x87,0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98, + 0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3, + 0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7, + 0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1, + 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4, + 0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0x01,0x00,0x03,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02, + 0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x11,0x00,0x02,0x01, + 0x02,0x04,0x04,0x03,0x04,0x07,0x05,0x04,0x04,0x00,0x01,0x02,0x77, + 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51, + 0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,0xa1,0xb1, + 0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24, + 0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,0x27,0x28,0x29,0x2a, + 0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49, + 0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x63,0x64,0x65,0x66, + 0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82, + 0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96, + 0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa, + 0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5, + 0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9, + 0xda,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4, + 0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xff,0xc0,0x00,0x11,0x08,0x00,0xc8, + 0x01,0x40,0x03,0x01,0x22,0x00,0x02,0x11,0x01,0x03,0x11,0x01,0xff, + 0xda,0x00,0x0c,0x03,0x01,0x00,0x02,0x11,0x03,0x11,0x00,0x3f,0x00, + 0xfd,0xf7,0xbd,0xbd,0xb8,0xbe,0x9e,0x6b,0xbb,0xfb,0x99,0xee,0x6e, + 0xa7,0x63,0x2c,0xf7,0x57,0x97,0x0d,0x73,0x71,0x34,0x8a,0x30,0x25, + 0x96,0x79,0x1d,0xe4,0x95,0x94,0x00,0x84,0xbb,0xb3,0x1e,0x31,0x9e, + 0xf5,0x52,0x61,0xc0,0x45,0x50,0x85,0xb6,0xe1,0x72,0x80,0x7f,0x79, + 0x55,0x70,0x00,0xc1,0x19,0xef,0xc9,0x27,0xe9,0xcf,0x1d,0x41,0x11, + 0x19,0xe5,0x2a,0x53,0x81,0xb5,0xf8,0x52,0x72,0x5b,0x96,0xe0,0x2e, + 0x00,0x3d,0x48,0xc8,0xe8,0x0e,0x45,0x61,0xdc,0x78,0xdb,0x42,0xb2, + 0x56,0x1f,0x6d,0x49,0x4e,0xe2,0xcb,0x1c,0x4a,0xd3,0x49,0xe6,0x1d, + 0xc5,0x86,0x50,0x98,0xa3,0xc8,0x27,0x68,0x79,0x17,0x8c,0xf7,0xc0, + 0x3f,0xe9,0x4d,0x2c,0x0e,0x22,0x69,0x42,0x85,0x09,0x49,0x45,0x28, + 0xc6,0x14,0xe0,0xda,0x8a,0x49,0x28,0xa4,0xa3,0x1f,0x75,0x25,0x64, + 0xb4,0x49,0x2d,0xb6,0x3f,0xc4,0x7a,0xd8,0xb4,0x9d,0x4a,0x95,0x6a, + 0xc6,0x55,0x1f,0x3c,0xe6,0xea,0x54,0xbc,0xe5,0x37,0x79,0x39,0x49, + 0xc9,0xb9,0x37,0x27,0x76,0xdb,0xbc,0x9b,0xbb,0xb9,0xe8,0x1e,0x61, + 0x39,0x25,0xb0,0xa7,0x6a,0xed,0xc8,0xc1,0xdc,0x3e,0x6c,0x71,0x9c, + 0xf0,0x32,0x3a,0x0e,0xf8,0xee,0x34,0xc9,0xce,0xe6,0x1b,0x77,0x3e, + 0xd2,0xa5,0x59,0x40,0x21,0x7a,0x9e,0x84,0x06,0x24,0x8c,0x74,0x38, + 0x24,0x62,0xbc,0x03,0x54,0xf8,0xa3,0xa8,0xcd,0xe6,0x43,0xa7,0xc6, + 0x96,0x70,0x87,0x60,0x93,0xb2,0x09,0xe7,0x20,0x9f,0x94,0xe1,0xcf, + 0x97,0x1e,0x71,0x9c,0xaa,0xb0,0xce,0x54,0xf7,0x35,0xc7,0xde,0xf8, + 0xb7,0x58,0xd4,0x55,0x52,0xf7,0x52,0xb8,0x9d,0x54,0x97,0x54,0x46, + 0x58,0x94,0xb1,0x00,0x00,0x12,0x1d,0x8c,0x4e,0xe0,0x79,0x6d,0xdf, + 0xdd,0xdc,0x14,0x57,0xb5,0x87,0xe1,0x6c,0xd2,0xb7,0x24,0xa6,0xa9, + 0x51,0x8b,0xbd,0xd4,0xa4,0xe5,0x38,0xe9,0x75,0x75,0x15,0xca,0x9b, + 0xda,0xd7,0xba,0xeb,0x6e,0xbe,0x64,0xb3,0xcc,0x3a,0xf7,0x61,0x09, + 0x54,0x96,0x9e,0xf7,0xc1,0x0b,0xf5,0x57,0x9d,0x9d,0x92,0xeb,0x6b, + 0x5f,0x43,0xeb,0x15,0xb8,0x55,0xeb,0x22,0xa8,0x27,0xaf,0xca,0xdd, + 0x38,0x3c,0x10,0xdc,0x8c,0xe3,0x69,0x23,0x9e,0xbc,0xe4,0xd3,0x3f, + 0xb4,0x23,0x8d,0x99,0x59,0xe3,0x27,0x24,0xe3,0xcc,0x08,0xdc,0xe4, + 0xa9,0x28,0x18,0x10,0xab,0x86,0x62,0xd9,0x03,0xa0,0x24,0x77,0xf8, + 0xec,0xea,0xd7,0x23,0x1e,0x5f,0x9b,0x13,0x11,0xe6,0x28,0x49,0xa7, + 0x1e,0x66,0xee,0x32,0x58,0x4b,0xb0,0x64,0x82,0xa4,0x30,0x24,0x75, + 0x38,0x1c,0x55,0x36,0xd4,0x1b,0x25,0xe5,0x66,0x67,0x09,0x92,0x01, + 0x67,0x11,0x7e,0xf3,0x67,0xcc,0xce,0xc4,0x82,0xcb,0xca,0xae,0xed, + 0xa7,0x9c,0x11,0xc8,0xae,0xe7,0xc1,0x18,0x89,0xbb,0xcf,0x17,0x18, + 0xa7,0xfc,0x94,0x9d,0x47,0x7d,0x96,0x8e,0x70,0xd1,0xf7,0xbe,0x8e, + 0xcb,0xa9,0xcf,0x53,0x88,0x61,0x05,0x65,0x85,0x9b,0x9d,0xd5,0xfd, + 0xf8,0xf2,0xed,0xd2,0x49,0xea,0xf6,0x5f,0x79,0xf6,0x3c,0x1a,0xcd, + 0xab,0xcd,0xe5,0xc7,0xa8,0x59,0x4b,0x70,0x18,0x90,0x90,0xdc,0x43, + 0xbd,0x41,0x52,0xa4,0x08,0x8c,0x8c,0x77,0x63,0x90,0x0b,0x10,0x4f, + 0xa1,0xc6,0xdd,0x45,0xba,0x5d,0xb8,0x2e,0xcd,0x86,0x60,0xa0,0x96, + 0x53,0x80,0xa3,0x27,0x24,0x60,0x8c,0x92,0x09,0xec,0x7e,0xf1,0xc6, + 0x71,0xf1,0x12,0x5f,0x95,0x74,0x91,0x25,0x68,0x80,0x62,0xe8,0x40, + 0x58,0xc0,0x2a,0x70,0x46,0xfc,0x91,0x98,0xf2,0x1d,0xb6,0xe1,0xd8, + 0x31,0x1b,0x89,0x18,0x5e,0xb2,0xdf,0xc7,0x1e,0x20,0x86,0x34,0x86, + 0x2d,0x5e,0xf5,0x52,0x25,0xf3,0x56,0x36,0x2a,0xf1,0xaa,0xf5,0x1b, + 0x64,0x75,0x90,0x94,0x07,0x1b,0x62,0x25,0x93,0x92,0x57,0x18,0x00, + 0xe1,0x5f,0x82,0x31,0x4b,0x97,0xd8,0x57,0xa7,0x27,0xb4,0x9c,0xe1, + 0x38,0xb6,0xb6,0x4d,0xdb,0x9a,0xcf,0xbe,0xe9,0x3d,0x39,0x99,0xb5, + 0x2e,0x21,0xa7,0x15,0xcd,0x3a,0x35,0x3d,0xe5,0x1d,0x29,0x4a,0x0d, + 0xae,0xb6,0x97,0x3d,0x96,0x9e,0x57,0xd7,0x73,0xeb,0x21,0x72,0x18, + 0x02,0xc3,0x69,0xdc,0x78,0x2a,0xc7,0xd3,0x6e,0x3d,0xcf,0x50,0x30, + 0x33,0xb4,0xe3,0x82,0x71,0x2f,0x9b,0x9d,0xd2,0x64,0x13,0xb8,0x01, + 0x8c,0xe7,0x04,0x1f,0x5e,0x7e,0x51,0xce,0x00,0xe4,0x93,0xed,0x9f, + 0x9b,0x2c,0xfe,0x2e,0xea,0x71,0xaa,0xfd,0xaa,0xda,0xd6,0xf4,0x13, + 0x9d,0xc4,0x3d,0xab,0x1f,0xe0,0x60,0x7c,0xbd,0xe9,0x23,0x1e,0x48, + 0x6e,0x07,0x38,0x21,0x7b,0xf6,0x76,0xdf,0x15,0xb4,0x09,0x63,0x22, + 0x7b,0x5b,0xeb,0x67,0x2c,0x33,0x1a,0x40,0x93,0xa9,0xc0,0xfb,0xcb, + 0x22,0xcc,0xa4,0x06,0x6c,0xe3,0x72,0x0c,0x81,0xd4,0x02,0x33,0xe2, + 0x62,0x38,0x63,0x3a,0xc3,0x6b,0x2c,0x15,0x4a,0x91,0xbd,0x94,0xe8, + 0xb8,0xd4,0xb2,0xba,0x4d,0xca,0x29,0xa7,0x6e,0xaf,0x54,0x92,0xdd, + 0x9e,0x9d,0x2c,0xf7,0x03,0x56,0xfe,0xfb,0xa7,0x66,0x97,0xef,0x63, + 0x25,0x7b,0xf5,0x5a,0x6c,0x7b,0x00,0xb9,0x0d,0x95,0x2d,0x82,0x3a, + 0x92,0x09,0x60,0x00,0xf9,0x94,0x13,0x85,0x5c,0x8f,0xee,0xe7,0xa7, + 0x1d,0x09,0xa9,0x85,0xc9,0x8d,0x5b,0x0c,0x0f,0xc8,0x47,0x07,0x27, + 0x8e,0x46,0x4f,0x07,0xa0,0x03,0x27,0xab,0x13,0xd3,0xa5,0x79,0x0c, + 0x1f,0x13,0x3c,0x35,0x23,0x2c,0x73,0x7d,0xaa,0xd8,0x16,0x54,0x12, + 0xcd,0x6e,0xc6,0x06,0x39,0xc9,0x19,0x8e,0x47,0x78,0xf6,0xae,0x4e, + 0x59,0x08,0xeb,0xce,0x70,0x2b,0xb5,0xb0,0xd6,0x74,0xcd,0x4f,0x9d, + 0x3e,0xfa,0xde,0xe7,0x11,0xfc,0xc2,0x19,0x55,0xdc,0x13,0x92,0xa1, + 0x23,0xc0,0x97,0x0a,0x41,0x0d,0x94,0x18,0x23,0x0d,0x81,0xcd,0x70, + 0x55,0xca,0xf1,0x54,0x21,0x7c,0x56,0x1a,0xbd,0x28,0x77,0xa9,0x45, + 0xc6,0x9b,0xdb,0x4e,0x74,0xe5,0x0d,0x3c,0xa7,0x74,0xfb,0x1d,0x70, + 0xc7,0xd1,0xab,0x7f,0x65,0x56,0x95,0x45,0x1d,0xf9,0x66,0xae,0xbd, + 0x55,0xee,0xbe,0x67,0x45,0xf6,0xbd,0xc1,0x55,0xb6,0x2b,0x14,0xce, + 0x32,0x4f,0xde,0x38,0xef,0xc9,0x03,0xef,0x70,0x3b,0x7e,0x34,0x19, + 0x95,0x43,0x2e,0x0e,0x39,0xe4,0x1c,0x9c,0x1f,0x41,0xdf,0x91,0xc0, + 0x38,0x3c,0x9c,0x81,0x85,0x35,0x9b,0x1c,0xc8,0x5c,0x14,0x2c,0x08, + 0x0a,0x01,0x07,0x8c,0x0c,0xa8,0x27,0x20,0x06,0xdb,0xf4,0x23,0x39, + 0x53,0xc2,0x72,0x1f,0x2e,0x2d,0xc7,0x24,0x9f,0x98,0x13,0xf3,0x36, + 0x31,0xf3,0x30,0x0c,0xb9,0x0a,0x32,0x72,0x00,0xf9,0x79,0xc0,0x39, + 0x38,0x38,0x7d,0x5e,0x31,0xb2,0xbf,0x2a,0xe8,0xad,0x6f,0xc1,0xff, + 0x00,0x57,0x3b,0x61,0x2e,0x68,0xa9,0x77,0xbf,0xe6,0xd1,0xa2,0x26, + 0x50,0x03,0x82,0xd8,0xda,0x00,0x53,0xf2,0x81,0xcb,0x03,0x91,0xd7, + 0x70,0x39,0x1b,0x8f,0x4e,0xbd,0x6a,0x63,0x3e,0x70,0x78,0xca,0xb8, + 0x55,0x2a,0x79,0x50,0xf1,0xe0,0x8c,0x75,0x27,0x03,0x19,0x3c,0x7a, + 0x66,0xb0,0x3c,0xc6,0x7d,0xe5,0xcf,0xcb,0xb8,0xb2,0x9c,0x9c,0xa8, + 0x66,0xcb,0x71,0x8f,0x94,0x70,0x4f,0x7f,0xc8,0xe6,0x98,0x64,0x91, + 0x71,0xf3,0x64,0x29,0x04,0x05,0xc8,0x3c,0x92,0x46,0x49,0xce,0x78, + 0x6d,0xa3,0x23,0xb0,0xcd,0x1f,0x56,0x6f,0x67,0xf7,0xab,0x7d,0xdf, + 0xd7,0xdc,0x6b,0x4e,0xaf,0x23,0x97,0x2b,0x4d,0xec,0xd5,0xf6,0xb3, + 0xf2,0xfb,0xb5,0x3a,0x26,0xb8,0xda,0x84,0xb1,0x00,0xb2,0x8d,0x80, + 0x6e,0x3b,0xb7,0xaf,0x41,0x8e,0xac,0x00,0xe4,0x75,0xe7,0x27,0x19, + 0xa0,0xce,0xad,0xb5,0x46,0xc7,0x5c,0x03,0xc6,0x55,0x9b,0xb1,0x07, + 0x2d,0xd0,0x10,0x39,0x23,0x1c,0x56,0x34,0x97,0x08,0x02,0x21,0x5c, + 0x9c,0x02,0x19,0x37,0xa9,0x42,0x70,0xa7,0xbe,0x77,0x1c,0xe4,0xf3, + 0x82,0x38,0x3c,0x60,0xd3,0x5a,0x75,0x57,0x28,0xac,0x43,0x67,0xe5, + 0x63,0x9c,0xf1,0xdb,0x39,0x23,0x6e,0x71,0xc7,0xae,0x31,0xc0,0xa3, + 0xea,0xd2,0x7d,0x5d,0xd3,0xd3,0x4f,0x5f,0x3d,0x34,0xb7,0xe2,0x69, + 0xf5,0x97,0x24,0xd2,0x49,0xdf,0x47,0x69,0x37,0xbf,0xce,0xdf,0x81, + 0xb5,0xe6,0xfc,0xa7,0x79,0xc7,0x29,0x80,0xdc,0x92,0x49,0xe7,0x81, + 0xd7,0x03,0x9f,0x97,0x23,0x1f,0x7b,0x03,0x9a,0x4f,0x34,0x92,0x02, + 0x20,0x23,0x76,0x33,0xbf,0x69,0x00,0x7d,0xd6,0xc1,0xe3,0x39,0xed, + 0xeb,0xd7,0x8c,0xd6,0x21,0xbb,0xdb,0xc3,0x17,0xe0,0x32,0x65,0x46, + 0xee,0x59,0x76,0x91,0xc1,0xdd,0xc8,0x3b,0x73,0xc6,0x0e,0x0b,0x60, + 0x60,0x99,0x04,0xa1,0x04,0x60,0x49,0xb4,0x10,0x43,0xef,0x12,0x1c, + 0x63,0x23,0x82,0x07,0x27,0x04,0x10,0x07,0x04,0xf1,0x9e,0xf4,0x7d, + 0x56,0x6b,0x76,0xfc,0xad,0x1b,0x89,0x62,0x1c,0x3d,0xcb,0x24,0xde, + 0xa9,0x39,0x35,0x2f,0x92,0xba,0xfc,0x8d,0x87,0x9f,0xc9,0x60,0x98, + 0x03,0x23,0x95,0xcb,0x60,0x13,0x85,0x6d,0xa4,0x7a,0x93,0xbb,0xe6, + 0xee,0x07,0x63,0x93,0x19,0xb8,0x4e,0xc5,0x99,0xb0,0xdb,0x46,0xff, + 0x00,0x93,0xe5,0xe8,0x08,0x07,0xd3,0x96,0xe7,0x27,0x82,0x38,0x06, + 0xb2,0x56,0x62,0x46,0xd7,0x95,0x5d,0xf7,0x00,0xa4,0x04,0xf9,0x80, + 0x6c,0x9d,0xc0,0x91,0x8c,0x28,0x53,0x81,0xc0,0xe8,0x39,0x38,0xa3, + 0xce,0x27,0x1c,0x16,0xc8,0x2d,0xf2,0x85,0x39,0x0d,0xd3,0xe5,0xce, + 0xe2,0x76,0x82,0x70,0x07,0x5c,0x71,0xd6,0x8f,0x60,0x96,0x8e,0x4e, + 0xeb,0xa5,0xb5,0xfb,0xb5,0x66,0x8f,0x11,0x34,0xae,0xe1,0x65,0xb5, + 0xdb,0x92,0xfd,0x6c,0x6d,0xab,0xab,0x96,0xe3,0x2b,0x85,0x0a,0x41, + 0xe7,0xe6,0x19,0x93,0x8c,0x72,0x33,0xc8,0x38,0xe4,0xe0,0x1e,0xb9, + 0xa0,0x15,0x3f,0x28,0xdb,0x82,0xac,0x09,0x2e,0x03,0x03,0xb4,0x0c, + 0xed,0xcf,0x03,0x8e,0x09,0xea,0x72,0x3b,0x56,0x47,0xda,0xe3,0x89, + 0x9c,0xee,0x2a,0x89,0xd4,0xb9,0x1b,0x54,0xaf,0x04,0xb1,0xe8,0x17, + 0xeb,0x80,0x0e,0x4e,0x6b,0x12,0x6f,0x15,0xf8,0x6a,0xd4,0x8f,0xb4, + 0x6b,0xfa,0x54,0x21,0xd6,0x46,0x63,0x26,0xa3,0x66,0xac,0xbe,0x5b, + 0x1c,0xa9,0x57,0x98,0x3e,0x7f,0xb9,0xb5,0x08,0x5c,0x64,0xf1,0x4e, + 0x18,0x4a,0x95,0x2f,0xc8,0xa7,0x34,0xbf,0x92,0x0e,0x76,0x7d,0x9f, + 0x2d,0xf5,0x56,0x64,0x3c,0x62,0x8a,0xf7,0x9c,0x17,0x4b,0xb9,0xb5, + 0x77,0xff,0x00,0x81,0x2d,0x4e,0xb0,0xce,0x84,0x85,0xe7,0x01,0x49, + 0x3b,0xb2,0x30,0xd9,0xda,0xa7,0x8c,0xf4,0x1e,0xdf,0x30,0x03,0x19, + 0xe7,0x2f,0x13,0x18,0xf2,0xd1,0xed,0x3d,0x50,0x13,0xfb,0xb0,0xc4, + 0xe0,0x70,0x23,0xda,0x14,0x64,0xe7,0x04,0x13,0x9c,0x67,0xae,0x07, + 0x9e,0xc5,0xf1,0x07,0xc1,0x97,0x33,0x35,0xba,0x78,0x8b,0x4c,0x96, + 0x66,0x63,0x12,0x46,0x26,0x68,0xda,0x5f,0x98,0xe0,0x23,0x4e,0xb1, + 0xab,0xef,0x6e,0x11,0xf7,0x2a,0xb0,0x3d,0x94,0xe6,0xba,0x88,0x2f, + 0x61,0xb9,0x51,0xf6,0x69,0xd2,0x68,0x78,0x64,0x68,0x26,0x85,0xd0, + 0xa9,0x18,0x0c,0x4c,0x6c,0xe3,0x00,0xfd,0xec,0x36,0x71,0xc1,0x3c, + 0x8a,0xba,0xb8,0x1a,0xd4,0x52,0xf6,0xf4,0xea,0xd2,0x4d,0x5d,0xfb, + 0x5a,0x53,0xa6,0x9c,0x7e,0xd7,0xc4,0x97,0xcd,0xe9,0xf2,0x37,0xa7, + 0x89,0xa3,0x37,0xfb,0xba,0xf4,0xea,0x5a,0xd7,0x54,0xab,0x46,0x6d, + 0x7c,0xe3,0x37,0xca,0xed,0xd5,0xde,0xdb,0xd8,0xdd,0x87,0x51,0xba, + 0x57,0xdc,0x93,0x15,0xc0,0x0a,0x17,0x8e,0x48,0xc6,0x19,0xc6,0x49, + 0x24,0x64,0xfb,0x74,0xab,0x8d,0x7d,0x30,0xc0,0x72,0xad,0xf3,0xa9, + 0xf9,0x3e,0x56,0x08,0xb9,0xc9,0xf9,0x49,0xf9,0xf2,0x07,0xc8,0x30, + 0x00,0xc7,0x5e,0x95,0xcf,0x71,0xf2,0x8d,0xbc,0x38,0x3d,0x58,0x9c, + 0x10,0x73,0x86,0x4e,0x00,0xc9,0xcf,0x39,0xf5,0x2b,0xc3,0x0c,0x0d, + 0x26,0xde,0xac,0x54,0x3f,0x23,0x2a,0x40,0xc6,0x4e,0x41,0xcf,0x24, + 0x0c,0xe4,0x0c,0xe4,0x64,0x9e,0xdc,0xf2,0xbc,0x25,0x07,0xad,0xe3, + 0x6d,0x3d,0x2d,0xde,0xfc,0xdd,0xbf,0xe1,0xec,0x6f,0xf5,0x96,0xb6, + 0x9e,0x8b,0xf9,0xa7,0xcd,0xaf,0x5d,0x5b,0x5f,0xd7,0xae,0x9b,0xcd, + 0xae,0x09,0x37,0x28,0x88,0x82,0x15,0x14,0xe1,0xbc,0xc5,0x3b,0x09, + 0xc6,0x01,0x18,0x24,0xe7,0x77,0x39,0x23,0x00,0x74,0x26,0x9a,0x75, + 0x28,0x8c,0x72,0x36,0x3e,0x70,0x93,0x61,0x01,0x8c,0x0c,0x79,0x6d, + 0xb4,0x8f,0xe1,0x2a,0x47,0xcf,0x9d,0xd9,0x6f,0x7c,0x0a,0xc1,0x67, + 0xc0,0x20,0x0e,0x83,0x08,0x51,0xb2,0x48,0xcf,0x56,0xce,0x30,0x47, + 0x6f,0x6c,0x9e,0x09,0xa8,0x67,0x7c,0xac,0x8c,0xb9,0x08,0x16,0x50, + 0x71,0x8d,0xca,0x36,0x3e,0x36,0xe4,0x8c,0x03,0x80,0x00,0x00,0xf4, + 0x38,0xe4,0x56,0x73,0xc1,0xd1,0x74,0xe4,0xe2,0x93,0x49,0x34,0xda, + 0x77,0x5b,0x3d,0xdd,0xf7,0xfb,0xb5,0xfc,0x6a,0x38,0xfa,0x91,0x94, + 0x63,0x09,0xc6,0x72,0x8f,0x33,0xe5,0x52,0x4d,0xda,0x2a,0x55,0x3e, + 0x15,0x77,0x6b,0xc5,0x27,0xd2,0xcd,0xb3,0xf7,0x5f,0xe1,0x83,0x6e, + 0xf8,0x6d,0xf0,0xfd,0xb1,0x8d,0xde,0x09,0xf0,0xa3,0x7f,0xdf,0x5a, + 0x0e,0x9e,0x7f,0xad,0x77,0x55,0xc1,0x7c,0x2b,0x20,0xfc,0x31,0xf8, + 0x76,0x46,0x48,0xff,0x00,0x84,0x17,0xc2,0x38,0xcf,0x5c,0x7f,0xc2, + 0x3d,0xa7,0x63,0x3e,0xf8,0xae,0xf6,0xbf,0xcf,0xfc,0xd1,0x28,0xe6, + 0x79,0x8c,0x56,0xcb,0x1f,0x8b,0x4b,0xd1,0x62,0x2a,0x24,0x7f,0xae, + 0x3c,0x3c,0xef,0x90,0x64,0x6f,0x7f,0xf8,0x47,0xcb,0x3f,0xf5,0x0a, + 0x88,0x51,0x45,0x15,0xc0,0x7b,0x01,0x45,0x14,0x50,0x01,0x45,0x14, + 0x50,0x01,0x45,0x14,0x50,0x07,0xf2,0x67,0xa9,0x78,0x8f,0x57,0xd5, + 0x86,0x6e,0xaf,0x58,0xc3,0xbc,0xb0,0x85,0x48,0x58,0xf0,0xbf,0x29, + 0x01,0x00,0x20,0x17,0x6d,0x8c,0x59,0xcb,0x63,0x25,0x54,0xa8,0x35, + 0xcf,0xb3,0x3b,0x39,0x72,0x71,0xbc,0x03,0x22,0xaf,0xe0,0x0a,0xe0, + 0x10,0x1b,0x18,0x01,0x59,0x81,0x20,0xf2,0x3e,0xee,0x0e,0x13,0x5c, + 0xcf,0x95,0x7f,0x35,0xf0,0x8c,0xe0,0xa3,0x6d,0x6c,0x23,0x9c,0x8d, + 0xdb,0x42,0x86,0x24,0x92,0x41,0xc7,0x03,0x00,0x66,0xac,0x47,0x7a, + 0xa1,0xd3,0x78,0x43,0xf3,0x16,0x1b,0x70,0xad,0x9d,0xbb,0x53,0x9d, + 0xa4,0xe0,0x64,0x96,0x5c,0xe7,0x9c,0x9c,0x1e,0xbf,0xec,0xd5,0x1c, + 0x04,0x70,0xcb,0x96,0x95,0x18,0x46,0x16,0x97,0xbb,0x08,0xc5,0x24, + 0xb5,0xef,0x79,0x36,0xf5,0x77,0xbd,0xbb,0x74,0x3f,0xc0,0x2a,0xd8, + 0x87,0x56,0xa4,0x67,0x29,0xb9,0x6a,0xae,0xdf,0x36,0x8a,0xfd,0x17, + 0xe3,0xd4,0xd9,0x63,0xbc,0x92,0x59,0x80,0xf9,0x4e,0x3a,0xf2,0x09, + 0xc8,0x39,0x23,0x07,0x18,0xc9,0x5e,0x0f,0x50,0x05,0x32,0x59,0xda, + 0x2d,0xb8,0x42,0x40,0x5e,0x88,0x53,0x39,0x1c,0xae,0x09,0x1c,0x00, + 0x71,0xf3,0x73,0x93,0xc6,0x39,0xaa,0x63,0x50,0x85,0x71,0x90,0xc4, + 0x8f,0x2c,0x36,0xdf,0xde,0x71,0xc2,0x1d,0x8d,0xc6,0xf2,0x18,0xee, + 0xdb,0x81,0xc7,0x72,0x41,0x14,0x8f,0x77,0x6f,0x21,0x45,0x57,0xc9, + 0x8d,0x8a,0x36,0xf5,0x28,0xcf,0xbf,0x20,0x9c,0x31,0xe4,0x60,0x8c, + 0xbf,0xdd,0x43,0xc7,0xa5,0x5f,0xb2,0xb3,0x5e,0xec,0x92,0xeb,0xa5, + 0xba,0x79,0x2f,0x93,0xfc,0x34,0x22,0x55,0x9a,0x7e,0xe5,0x9a,0xf3, + 0x4f,0xee,0xe8,0x5c,0x67,0x0a,0x36,0x0f,0x95,0xd7,0x68,0x39,0xea, + 0x37,0x21,0x66,0x4e,0x32,0x3e,0xf9,0x27,0xea,0x7a,0xe3,0x8a,0x7b, + 0x6f,0x21,0xd7,0x05,0x8b,0x44,0x84,0x30,0x24,0x11,0xc9,0x01,0x4f, + 0xf0,0xb7,0xcc,0x54,0xe0,0x8c,0xaf,0xae,0x32,0x0d,0x45,0x98,0xc4, + 0x9b,0x44,0x87,0x05,0x88,0x07,0x38,0x67,0x24,0x64,0xf2,0xca,0xcc, + 0xc4,0xa8,0x1c,0x82,0x09,0xc7,0x5c,0xe0,0xd3,0x0c,0xa0,0xb9,0xc1, + 0x70,0xec,0x46,0x3e,0x66,0x4d,0xa8,0x40,0x3c,0xe5,0x80,0xc9,0x61, + 0xf2,0x10,0xad,0xb7,0x24,0x90,0x3b,0x57,0x24,0xb4,0xba,0xd1,0x6c, + 0xf7,0x7a,0x3f,0xbd,0x2e,0x96,0xb7,0xcf,0x6b,0xa5,0x57,0x9b,0x49, + 0xd9,0x2e,0xe9,0x3b,0xdf,0xf1,0xfc,0x8b,0x08,0xee,0x4b,0x20,0xda, + 0xa5,0x3e,0xe6,0xe5,0xfb,0xa1,0x5f,0x2e,0x31,0xcf,0xe0,0x4e,0x47, + 0x1d,0xb3,0xc3,0xc4,0x85,0x1c,0x17,0x29,0xb7,0x3f,0x33,0x67,0x0a, + 0xa4,0xb8,0x0a,0x0e,0x32,0x53,0x39,0x04,0x02,0x06,0x33,0xb4,0xa9, + 0x1c,0x9a,0x06,0x68,0xc6,0x7f,0x78,0x49,0x1d,0x79,0x39,0x3b,0x4f, + 0xcd,0xf3,0x67,0x07,0x19,0x00,0x90,0x39,0xe3,0xae,0x6a,0x14,0xbd, + 0x65,0x3f,0x24,0x5b,0xd1,0xf7,0x07,0x6d,0xea,0x02,0xe3,0x05,0x48, + 0xc6,0x3e,0x6d,0xc0,0x6e,0x93,0x39,0xfb,0xe9,0x9e,0x95,0x4a,0x9c, + 0xdd,0xec,0x9e,0xda,0xf4,0xfb,0xaf,0x6e,0xba,0xaf,0x9f,0x7d,0x1c, + 0x2a,0xab,0xc9,0x49,0xa5,0x15,0xf0,0xbb,0x3d,0x57,0x4b,0xe9,0xdb, + 0xc8,0xd1,0x98,0x6d,0x2c,0xc9,0x90,0xc8,0xca,0xdb,0x41,0xda,0xcf, + 0xb4,0xe4,0xaa,0x9f,0x99,0x32,0x73,0xf7,0x76,0x8d,0xdc,0x9c,0xe4, + 0x0c,0xaa,0xcd,0x97,0x00,0x9d,0xc0,0xe3,0x04,0xb6,0xd4,0x0c,0xec, + 0xcc,0xc4,0x29,0x25,0xbe,0x51,0xb7,0xa6,0x01,0x39,0x3d,0x07,0x38, + 0xe6,0xe6,0x5c,0xc8,0x02,0x20,0x62,0xca,0x41,0x0e,0x5d,0x89,0x43, + 0x9e,0x09,0x50,0x01,0xc1,0xdc,0x03,0x1c,0x02,0xa7,0x3d,0x28,0x6b, + 0xb9,0x13,0x76,0x42,0x26,0x19,0xb6,0x86,0x19,0x05,0x8e,0x39,0xea, + 0x47,0x39,0xcb,0x1e,0x31,0x86,0x18,0xc6,0x01,0x6e,0x84,0xe7,0xbc, + 0x5d,0xbb,0x5e,0x3b,0x34,0xaf,0xbf,0x43,0x65,0x38,0xc9,0x36,0x9e, + 0x8b,0x77,0x66,0xad,0xf7,0x9b,0xaa,0xe3,0x2a,0x18,0x2a,0x29,0x76, + 0xea,0xc4,0x8c,0x0c,0x1c,0xed,0xea,0x01,0x3f,0x36,0x58,0xe0,0x13, + 0x92,0xbb,0x5b,0x14,0xe5,0xbc,0x6b,0x67,0x49,0xe1,0x79,0x20,0x91, + 0x10,0x15,0xb9,0x85,0x9a,0x36,0x8f,0x18,0x40,0xa5,0xd1,0x91,0xc9, + 0x25,0xcb,0x36,0xcd,0xa0,0x05,0x0a,0xdb,0x85,0x62,0x25,0xff,0x00, + 0x96,0x9e,0x69,0x63,0x96,0xc9,0x05,0xb9,0x01,0x46,0x10,0x29,0x04, + 0x64,0x9c,0x28,0x04,0x71,0xce,0x32,0x4d,0x45,0x2e,0xad,0x17,0x00, + 0x2e,0xf2,0x46,0x58,0x26,0x08,0x00,0x8d,0xc9,0x96,0x7e,0x1c,0x9f, + 0xbd,0x85,0x5c,0xab,0x64,0x37,0x00,0x1a,0xc9,0xe0,0xe2,0xd5,0xa5, + 0x49,0x49,0x6b,0xf1,0x28,0xcb,0x7b,0xdd,0x59,0xa6,0xb6,0xfb,0xfc, + 0xae,0xae,0x95,0x68,0x45,0xf3,0x42,0x6e,0x12,0xfe,0x78,0xf3,0xa9, + 0x5b,0xb3,0xe8,0xd6,0xeb,0x55,0xb3,0xf4,0x3b,0xeb,0x6f,0x1a,0x78, + 0x96,0xd2,0x5f,0xdd,0xeb,0x77,0x44,0xed,0x51,0x0c,0x73,0x4a,0x6e, + 0xa0,0x24,0x46,0xc0,0x33,0x09,0x40,0xf9,0x73,0xb4,0x05,0xc9,0xca, + 0xaf,0xcc,0x7c,0xc6,0x72,0x7b,0x9d,0x2f,0xe2,0xd5,0xcc,0x46,0x08, + 0x75,0x6b,0x34,0x98,0x17,0x55,0x37,0x36,0x65,0xa3,0x92,0x34,0x38, + 0xcc,0x9e,0x43,0x02,0xb7,0x12,0x29,0x2c,0xdb,0x01,0x55,0x6e,0x06, + 0x46,0xda,0xf0,0x0f,0xed,0xd8,0x4e,0x36,0xab,0xee,0x60,0x76,0xab, + 0x47,0x1a,0x90,0x49,0xe4,0x82,0x57,0x80,0x78,0x0c,0x54,0x8c,0xf5, + 0xea,0x33,0x50,0x9d,0x7a,0x71,0xf3,0x08,0x60,0x0c,0x8d,0x95,0x6c, + 0x49,0x94,0x20,0x8d,0xcc,0xa1,0x5c,0x21,0x66,0xc8,0x04,0x91,0xc0, + 0x05,0x47,0x5c,0x8f,0x3b,0x13,0xc3,0x18,0x2c,0x6c,0x1c,0x3e,0xa3, + 0x4d,0x3d,0x5a,0x71,0x6a,0x9b,0xd7,0xb4,0x92,0x76,0xd5,0xde,0xd6, + 0x6a,0xd7,0xd2,0xce,0xc7,0x5d,0x1c,0xd2,0xb5,0x2a,0x9c,0xff,0x00, + 0x58,0xab,0x25,0xb3,0x8b,0x72,0xe5,0x49,0xda,0xed,0x2b,0x79,0x79, + 0xb3,0xee,0x4d,0x33,0xc4,0x7a,0x76,0xa6,0x9b,0xb4,0xeb,0xa8,0x6e, + 0x57,0x85,0x64,0x57,0xf9,0xe2,0xc8,0x05,0x94,0x8d,0x85,0x86,0x46, + 0xd0,0x37,0x60,0x6e,0xca,0x86,0x38,0xc9,0xb5,0x25,0xce,0xc5,0x66, + 0xda,0xca,0x85,0xcb,0x16,0x61,0xfe,0xad,0x76,0xe5,0x49,0xce,0xe1, + 0x95,0x21,0x88,0xce,0x07,0x3c,0xe4,0x1c,0x0f,0x82,0x4f,0x88,0x2f, + 0xe3,0xe6,0xd6,0x51,0x0c,0xcc,0x1c,0x0f,0x20,0x3c,0x5e,0x5e,0x59, + 0x48,0x60,0x62,0x75,0x2c,0xbf,0x29,0xf9,0x64,0xc8,0x19,0xef,0x81, + 0x53,0xc9,0xe2,0xaf,0x10,0xdd,0xa1,0x86,0x7d,0x6e,0xf9,0xe3,0x2a, + 0xc4,0xa8,0x9a,0x4d,0xa3,0xf8,0x5d,0x33,0xb8,0xf9,0x9d,0xf7,0x09, + 0xb7,0x70,0x72,0x41,0xcd,0x78,0x0f,0xc3,0xdc,0x47,0x35,0xa9,0xe3, + 0x68,0xc2,0x9a,0x49,0x5a,0xa4,0x2a,0x4a,0x51,0xb6,0x96,0x5c,0x96, + 0xbc,0x53,0xd9,0xb7,0x7b,0x6b,0x63,0xdc,0xa3,0xc4,0xf4,0xa9,0x47, + 0x96,0x54,0x27,0x39,0xad,0x39,0xd4,0x97,0x2c,0xa2,0xb6,0x7a,0xfb, + 0xdc,0xed,0x6b,0x25,0xb2,0x7b,0x36,0x7d,0xd7,0xfd,0xa5,0x6a,0x5a, + 0x56,0x92,0xee,0xd4,0x9d,0x8a,0x4a,0xbd,0xcd,0xba,0x32,0x24,0x6c, + 0x37,0x30,0x5f,0x37,0x70,0x0c,0xfb,0xd7,0x38,0xc9,0xc1,0xe3,0x6e, + 0x33,0xc9,0xea,0xbf,0x11,0x7c,0x29,0xa4,0x99,0x4d,0xc6,0xa7,0x0c, + 0xad,0x1c,0xbb,0x1e,0x1b,0x4c,0xde,0x4b,0xb8,0x80,0xc5,0x4b,0x5b, + 0xee,0x51,0x8d,0xb8,0x6f,0x9f,0x0b,0x90,0x0f,0x2d,0x5f,0x0f,0x4f, + 0x71,0x70,0xdd,0x6f,0x6e,0x5d,0x46,0x32,0x3c,0xd1,0xce,0x17,0x03, + 0x24,0x01,0xc7,0x27,0xae,0x49,0xcf,0x07,0x3c,0xd5,0x59,0x27,0x92, + 0x3d,0xc5,0x59,0xb2,0xe5,0x81,0xcb,0x31,0x3f,0x31,0xea,0xc7,0x1c, + 0x1e,0x98,0x3e,0xc3,0x18,0xeb,0x5d,0xf8,0x5f,0x0e,0x21,0xcf,0xfb, + 0xfc,0xc2,0x55,0x29,0xae,0x90,0xa5,0x1a,0x4f,0x4d,0x95,0xdc,0xa7, + 0xa3,0xeb,0x65,0xe8,0xcc,0x67,0xc5,0x33,0x8c,0x1a,0xa1,0x86,0x8c, + 0x5b,0xd2,0xf2,0x9b,0x76,0xbe,0x9c,0xcb,0x48,0xdf,0x97,0x7b,0x5d, + 0x6d,0xbe,0xa7,0xd5,0x7a,0xbf,0xc7,0x1d,0x2a,0x38,0x80,0xd0,0xf4, + 0xbb,0x9b,0xb9,0xe5,0x12,0x13,0x2d,0xe9,0x4b,0x58,0x50,0x31,0x18, + 0x60,0x63,0x32,0x4c,0xec,0x76,0xe5,0xa1,0xe0,0xac,0x48,0x00,0x2a, + 0xce,0x0d,0x71,0x53,0x7c,0x6c,0xf1,0x39,0xf3,0xd8,0x2e,0x93,0x6a, + 0x8e,0x98,0x8d,0x7e,0xcd,0x25,0xc3,0x46,0xdc,0x90,0xc8,0xf2,0x4c, + 0x3f,0x78,0x06,0x0e,0x0a,0x98,0xf8,0xc7,0x4e,0x07,0xcf,0xcd,0x2b, + 0x08,0xd0,0x07,0x0c,0x58,0x92,0x57,0x71,0xf3,0x15,0x40,0xe0,0x93, + 0xdb,0x24,0x70,0x73,0x83,0xd3,0xaf,0x35,0x13,0x5c,0x49,0x91,0x80, + 0xa0,0x9e,0x08,0x61,0x91,0x9d,0xb9,0x38,0xfc,0x7d,0x7b,0x7b,0x75, + 0xfa,0x7c,0x2f,0x01,0xe4,0x54,0xa3,0x79,0x61,0x61,0x5e,0x5f,0x6a, + 0xad,0x79,0xca,0x72,0x4d,0x7f,0x2e,0xa9,0x46,0x3d,0xaf,0x1b,0xef, + 0xd3,0x53,0xcd,0x9e,0x7d,0x99,0xd6,0xa9,0xee,0xe2,0xaa,0x50,0x83, + 0x56,0x71,0xa5,0x65,0xae,0xae,0xeb,0x99,0x4d,0xdd,0xe8,0xb7,0x7a, + 0x76,0x67,0xb6,0x37,0xc6,0x5f,0x15,0x99,0x43,0x8d,0x5a,0xd8,0xa4, + 0x45,0x89,0x55,0xd3,0xed,0xd0,0x15,0x23,0x0a,0x1c,0xe4,0x92,0x9c, + 0xe0,0x85,0x2a,0xdb,0xba,0x30,0xe6,0xa2,0x93,0xe3,0x37,0x8c,0xe7, + 0xfd,0xe4,0x7a,0xa9,0x45,0x20,0x0f,0xdc,0x59,0x59,0x2e,0xd2,0x84, + 0x70,0x86,0x44,0x6d,0xa4,0x28,0xc6,0x58,0xb1,0x07,0xa8,0xf5,0xf1, + 0x32,0x0a,0x82,0xed,0xf2,0x95,0xdc,0x46,0x57,0x6f,0xdd,0x1c,0xb7, + 0x5e,0x99,0xc0,0xcf,0x6e,0xf5,0x8d,0x7f,0xe3,0x0f,0x0e,0x69,0x59, + 0xb7,0xd4,0x75,0x9d,0x3e,0xc6,0xe2,0x14,0x32,0x49,0x14,0xd2,0x15, + 0xb8,0x20,0xdb,0x35,0xe0,0x11,0x42,0x83,0x6c,0x98,0x81,0x1a,0x47, + 0x61,0x19,0x5d,0x8b,0xb4,0xbb,0x48,0xe5,0x2b,0xd2,0xa7,0xc2,0x39, + 0x24,0x9c,0x7d,0x9e,0x57,0x42,0xbc,0x9d,0xfd,0xd8,0x61,0xe7,0x39, + 0x68,0xd5,0xdd,0xa2,0x9b,0xb5,0xed,0x7d,0x3a,0xab,0x6e,0x72,0xcf, + 0x31,0xcc,0x6a,0x4d,0xaf,0xad,0xe2,0x27,0xb4,0xaf,0x29,0xb5,0x7b, + 0x45,0x2b,0xde,0xd1,0x8e,0x9b,0x69,0xf9,0x9e,0xa5,0x7f,0xe2,0x9d, + 0x67,0x55,0x91,0xe5,0xbf,0xd4,0x6f,0xee,0x83,0x23,0x21,0x59,0xef, + 0x27,0x60,0x61,0x79,0x0c,0x86,0x3f,0x2e,0x39,0x16,0x00,0x0b,0x15, + 0x39,0x0a,0x73,0xd0,0x77,0x03,0x14,0x5e,0x48,0x1d,0x9c,0x88,0xcb, + 0x24,0x80,0x83,0xe5,0x85,0x61,0xc6,0x5d,0x7e,0x62,0x08,0x01,0x4e, + 0x41,0x04,0xe4,0x01,0x93,0x9e,0xbf,0x33,0xf8,0xa3,0xf6,0x8e,0xf0, + 0xa6,0x84,0xd6,0x23,0x4a,0x41,0xad,0x91,0xaa,0xc9,0x65,0xaa,0xa4, + 0x6d,0x34,0x1e,0x4d,0x85,0xbc,0xa9,0x14,0xf7,0x56,0x44,0x2c,0xa9, + 0x33,0x1f,0x31,0xe5,0xb4,0x0c,0x0c,0x72,0xc6,0xac,0x7e,0x46,0xc0, + 0x1e,0x4f,0xa8,0xfe,0xd4,0xda,0xb4,0xf6,0x91,0xc3,0xa7,0x69,0xd6, + 0xf0,0xde,0x79,0x3a,0xd4,0x0d,0x77,0x34,0x99,0x52,0xcd,0x24,0xa9, + 0xa6,0xdc,0xc2,0x8e,0x19,0xe2,0x6b,0x4b,0x63,0x6e,0x5c,0x16,0x22, + 0x5b,0x85,0x60,0xc3,0x00,0x1a,0xfa,0x3c,0x27,0x08,0x63,0x65,0x4a, + 0x32,0xc1,0x60,0x21,0x42,0x95,0x94,0x62,0xaa,0x5b,0x0f,0x15,0x14, + 0x9d,0x92,0x4b,0x96,0xa3,0x6a,0xc9,0x3e,0x7b,0xbd,0x53,0xd3,0xde, + 0x6b,0x37,0x0c,0x5e,0x22,0x4e,0x7e,0xd2,0x72,0xa9,0x65,0xcd,0x29, + 0xd5,0x7f,0x24,0xac,0xed,0xa6,0xbe,0x7d,0xdb,0x3e,0xf4,0x37,0xaf, + 0xb7,0x05,0x43,0x02,0x54,0xab,0x3f,0xcc,0x15,0xc3,0x31,0x52,0x32, + 0x4f,0x4c,0xe7,0x3c,0x02,0x41,0xc9,0xe0,0x11,0xa1,0xa7,0xf8,0x9a, + 0xff,0x00,0x45,0x91,0x6e,0xac,0x35,0x0b,0x8d,0x3a,0xe0,0x21,0x40, + 0xf6,0xf2,0xe0,0x10,0xee,0xca,0xc5,0xa2,0x04,0xc4,0xc1,0x94,0x04, + 0x50,0xca,0xe8,0x46,0x4a,0x1e,0x32,0x7f,0x2b,0x75,0x1f,0x8f,0xff, + 0x00,0x10,0x6f,0xe6,0x7b,0x9b,0x7d,0x66,0x5b,0x67,0x68,0x19,0x6e, + 0x21,0xb6,0x28,0x63,0x21,0xee,0x27,0xb8,0x84,0x44,0xbe,0x5e,0x2d, + 0xc2,0x2c,0xa6,0x25,0x58,0xf1,0x2f,0x95,0x0c,0x4a,0xf2,0x33,0x8d, + 0xd5,0xcc,0xdc,0x7c,0x4a,0xf1,0xe5,0xf8,0x68,0xa7,0xd7,0xb5,0x08, + 0xff,0x00,0x7a,0x93,0x39,0x49,0xdb,0xcc,0x59,0x97,0xfb,0x4d,0xc1, + 0x46,0x24,0xb4,0x31,0x88,0xf5,0x39,0xe2,0x44,0x19,0x45,0x8b,0x62, + 0xaa,0x83,0x12,0x30,0xf6,0xbf,0xd4,0x1a,0xd5,0xa9,0xa8,0x62,0xe7, + 0x85,0xb4,0xb4,0x9a,0x71,0x95,0x6b,0xc5,0xe9,0x25,0xef,0xf3,0x2b, + 0x59,0xda,0xc9,0xab,0xf5,0xb1,0xd3,0x4b,0x0d,0x88,0xa6,0xf9,0xe9, + 0xd5,0x95,0x0a,0x8b,0x69,0xd1,0xab,0x2e,0x6b,0x6f,0x6f,0x79,0x5b, + 0x75,0xd9,0xfc,0xba,0xfe,0xe0,0xd8,0xfe,0xd3,0xb6,0xfa,0x54,0x19, + 0xf1,0x0d,0xde,0x87,0x77,0x6d,0x66,0xc1,0x67,0x9d,0x75,0x28,0xf4, + 0xfb,0x94,0x41,0x17,0x9d,0xf3,0xa0,0xf3,0xe3,0x9a,0x7d,0x85,0x25, + 0x1e,0x6c,0x71,0xb1,0x59,0xe3,0x2a,0x80,0x3a,0x8a,0x9f,0x4d,0xfd, + 0xb5,0xfe,0x0f,0xea,0x70,0xc7,0x34,0x32,0xde,0x46,0xae,0x96,0x45, + 0x05,0xc4,0x96,0xb1,0x44,0xcd,0x7d,0x71,0x2c,0x36,0xcb,0x13,0xcb, + 0xf3,0xb0,0x94,0xdb,0x4e,0xe5,0x99,0x22,0x08,0x91,0x96,0x97,0x62, + 0x8d,0xc7,0xf0,0x3e,0xfb,0x56,0xbf,0xbb,0x41,0x3d,0xee,0xa3,0x2d, + 0xd4,0x92,0x4b,0x09,0x58,0x1e,0x69,0xbc,0xa1,0x22,0xc3,0x15,0xa3, + 0x5c,0x18,0x92,0x45,0xc4,0xde,0x45,0xad,0xbc,0x51,0xb3,0x02,0x0a, + 0x44,0x1d,0x00,0x62,0x6b,0x2d,0xc9,0x92,0x1f,0x39,0x1d,0xdd,0xbc, + 0xa8,0x84,0x6b,0x24,0xcd,0xb1,0x8b,0xc8,0xf1,0xed,0x41,0xb8,0x93, + 0xb5,0x43,0x91,0x8c,0x61,0xf2,0x7a,0xf5,0xf2,0x27,0xe0,0xa7,0x0c, + 0x57,0x94,0xa7,0x52,0x58,0xaa,0x73,0x9b,0xbb,0x58,0x5c,0x43,0xc3, + 0x52,0x4f,0x7d,0x29,0x7b,0xda,0xbd,0x9b,0x56,0xba,0x3d,0x88,0x66, + 0x59,0xac,0x20,0xa0,0xb1,0x2d,0xa5,0xd6,0x5a,0xc9,0xfa,0xbb,0xea, + 0xf4,0xec,0x7e,0xf5,0xc5,0xfb,0x64,0x78,0x5b,0x54,0x69,0x4e,0x8b, + 0x73,0xe1,0xf3,0x01,0x8a,0x07,0x8d,0x2f,0x75,0x16,0xf3,0x00,0xbf, + 0xbc,0x7d,0x3f,0x4f,0x32,0xba,0x6d,0x58,0xe6,0x9a,0x70,0x63,0x7b, + 0x70,0x0b,0x82,0x15,0xdb,0xcb,0x49,0x11,0xda,0x96,0xa7,0xfb,0x45, + 0xf8,0x84,0xa2,0xc2,0x9a,0xb6,0x89,0x64,0xf3,0xba,0xc2,0x89,0x0d, + 0xad,0xbb,0xdc,0x0b,0x8b,0xcb,0x69,0xda,0xd2,0xdd,0x0c,0xb3,0xcb, + 0xf3,0x4a,0x23,0x94,0xc6,0x85,0x32,0xc6,0x02,0xc8,0xc4,0xef,0xc7, + 0xe0,0xcc,0xe5,0x92,0x55,0x75,0xf3,0x10,0x15,0x8d,0x97,0x6b,0x10, + 0x59,0x90,0x99,0x5e,0x42,0xa3,0x96,0x7d,0xc0,0x04,0x39,0xca,0x86, + 0x61,0x91,0xb8,0xd4,0xd2,0x6b,0xda,0x92,0xf9,0x92,0x25,0xdd,0xe2, + 0x93,0x86,0xc8,0xb9,0xb8,0x2d,0xe7,0x47,0x0c,0xa6,0x2b,0x93,0xbd, + 0xd8,0x99,0x61,0x49,0x1a,0x34,0x7d,0xc3,0x64,0x5b,0xd1,0x4f,0x2d, + 0x5d,0x54,0xfc,0x19,0xe1,0x98,0x49,0x7b,0x3a,0x70,0xa8,0xfd,0xdb, + 0xac,0x45,0x3f,0x6c,0xdb,0x94,0xa3,0x49,0x27,0x39,0x54,0xb4,0xa4, + 0xf9,0xec,0x9f,0x25,0x95,0xd7,0x35,0x94,0x4c,0x6a,0xe3,0x73,0x5a, + 0x8e,0xef,0x1d,0x56,0x09,0x5d,0xfb,0x8d,0x46,0xde,0xe3,0x8e,0x8f, + 0x95,0xb4,0x9a,0xdd,0x37,0xdf,0x64,0xec,0x7f,0xa4,0x07,0xc0,0x2b, + 0xc9,0xf5,0x1f,0x81,0xbf,0x06,0xf5,0x0b,0x99,0x3c,0xeb,0x8b,0xef, + 0x85,0x5f,0x0e,0x6f,0x67,0x94,0x00,0x04,0xb3,0x5d,0x78,0x33,0x44, + 0x9e,0x59,0x00,0x50,0x14,0x6f,0x92,0x46,0x6c,0x28,0x0a,0x33,0x80, + 0x00,0xc0,0x1e,0xb7,0x5f,0x37,0xfe,0xc7,0x52,0x4b,0x37,0xec,0x93, + 0xfb,0x2f,0x4d,0x33,0x34,0x93,0x4b,0xfb,0x3b,0x7c,0x10,0x96,0x57, + 0x66,0x2e,0xcf,0x23,0xfc,0x2f,0xf0,0xa3,0x48,0xcc,0xc4,0x92,0xcc, + 0xce,0x4b,0x16,0xfe,0x22,0x73,0xd4,0xe6,0xbe,0x90,0xaf,0xf0,0xd7, + 0x89,0xa9,0x46,0x87,0x11,0xe7,0xf4,0x21,0xf0,0x51,0xce,0xb3,0x4a, + 0x71,0xff,0x00,0x0c,0x31,0xd5,0xe2,0xb6,0xf2,0x47,0xfb,0x87,0xc3, + 0x0d,0xbe,0x1b,0xe1,0xf6,0xdb,0x6f,0xfb,0x17,0x2b,0xbb,0x7b,0xb7, + 0xf5,0x1a,0x1a,0xbf,0x30,0xa2,0x8a,0x2b,0xc4,0x3d,0xc0,0xa2,0x8a, + 0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x03,0xf8,0xcf,0xfb, + 0x78,0x2c,0x41,0x62,0x43,0x61,0x0a,0xf4,0xc1,0x50,0x48,0x39,0xc9, + 0xe4,0x1f,0x5f,0x4f,0x7a,0x41,0xa8,0x32,0xc6,0x50,0x32,0xee,0x21, + 0x58,0x64,0xe3,0x9d,0x81,0x48,0xf9,0x8e,0x7f,0x01,0xcf,0x5c,0x03, + 0x8e,0x39,0x27,0xd5,0x23,0x50,0xcc,0x5c,0x1c,0x02,0x5a,0x42,0x09, + 0x0a,0x07,0x3b,0xdd,0xbe,0x54,0x01,0x81,0x05,0x55,0x4b,0x71,0x82, + 0x32,0x31,0x9e,0x13,0x5d,0xf8,0xc1,0xe0,0x0f,0x0d,0x24,0x6d,0xac, + 0xf8,0xbb,0x44,0xb4,0x32,0x98,0xda,0x28,0x85,0xda,0x4f,0x3c,0x8b, + 0x2c,0xa2,0x2f,0x30,0x41,0x07,0x9b,0x20,0x44,0xdc,0x64,0x79,0x08, + 0x0a,0x91,0xa3,0xb9,0xc0,0x5c,0x1f,0xf7,0x3e,0x9e,0x5d,0x5a,0xae, + 0x90,0xa1,0x51,0xdb,0x5b,0x46,0x0e,0x49,0xfa,0xb4,0x9d,0x9e,0xdf, + 0x27,0xe4,0x7f,0xcf,0x84,0x65,0x56,0x53,0x50,0x54,0xeb,0x49,0xbe, + 0x8a,0x9a,0x7b,0x3d,0xb4,0x49,0xdd,0xed,0xf3,0xf9,0x9e,0xd9,0xf6, + 0xd6,0xda,0xff,0x00,0x3a,0xb8,0xdc,0x87,0xf8,0x31,0xb9,0xd4,0xff, + 0x00,0x12,0x9c,0x90,0xa7,0xa7,0x6c,0xe7,0x23,0xad,0x3f,0xed,0x89, + 0x3f,0xc8,0x18,0xab,0x90,0x38,0x0b,0x8c,0xe3,0x83,0xcb,0x12,0xb8, + 0x03,0x91,0xb8,0x10,0x47,0xbd,0x7c,0x4b,0xe2,0x0f,0xdb,0x13,0xc0, + 0xda,0x5d,0xf4,0xf6,0xba,0x35,0x8e,0xad,0xe2,0x58,0x16,0xd9,0x1d, + 0x6f,0x6c,0x1e,0x08,0x6d,0x45,0xe6,0xe9,0x97,0xec,0x85,0x2f,0x16, + 0x27,0xcc,0x48,0x91,0x5c,0x3b,0x8c,0xee,0x8e,0x70,0xc0,0x07,0x0a, + 0x1b,0xca,0xf5,0x3f,0xdb,0x73,0x56,0x91,0xa2,0x5d,0x1f,0xc1,0x36, + 0xb1,0x44,0x65,0xf3,0xe6,0x5b,0xfd,0x46,0x4b,0x87,0x96,0xdb,0x8f, + 0xdc,0x46,0x6d,0xa3,0x43,0x14,0xec,0xde,0x63,0xa3,0x8d,0xe1,0x62, + 0x50,0x8d,0x97,0x3c,0x77,0xd2,0xe1,0x5c,0xdb,0x11,0x69,0x2c,0x23, + 0xa5,0x16,0xaf,0x7a,0xd2,0xa7,0x4e,0x16,0xb6,0x92,0x72,0x94,0xac, + 0xb9,0xad,0x65,0x7b,0x6b,0x65,0xb9,0xea,0x47,0x2c,0xcc,0x27,0xcb, + 0x25,0x87,0x94,0x61,0x28,0xa6,0xb9,0xb9,0x54,0xb5,0xbe,0xea,0xee, + 0xcb,0xa7,0x73,0xf4,0xd6,0x3b,0xc7,0x80,0x4c,0x03,0x17,0x8b,0x6c, + 0x78,0x12,0x84,0x73,0x98,0xf9,0xf9,0x40,0x66,0x03,0x01,0x83,0x31, + 0x6c,0x60,0x60,0x0e,0x48,0x05,0x4e,0xa2,0x8e,0x59,0x9e,0x40,0xc1, + 0x4e,0xd3,0xc8,0xc8,0xc8,0xda,0x9c,0x02,0x30,0xa4,0xb1,0xe7,0x3c, + 0x74,0x04,0xd7,0xe6,0x2d,0x87,0xed,0xb3,0xaf,0xa3,0xca,0xda,0xb7, + 0x85,0x34,0xf9,0xad,0x59,0xa5,0x30,0x49,0x63,0x75,0x73,0x67,0x71, + 0x1e,0xfb,0x82,0x6d,0xbc,0xf8,0xae,0x12,0x45,0x2b,0x1c,0x26,0x18, + 0xe7,0xc7,0xcc,0xed,0x1b,0xca,0xa5,0x78,0x51,0xe9,0x9a,0x57,0xed, + 0x87,0xe0,0xcb,0xf5,0x54,0xbf,0xd3,0x75,0x6d,0x3e,0x72,0xf1,0x44, + 0x48,0xf2,0xee,0x22,0xdf,0x3d,0xd2,0x2d,0xc4,0xc5,0x95,0x42,0xa5, + 0xbc,0x10,0x17,0xb8,0x4c,0xab,0xb9,0x44,0x31,0xbf,0xce,0x03,0x17, + 0x53,0x83,0xf3,0x6a,0x2d,0xd4,0xfa,0xab,0xa8,0x9d,0xaf,0x3a,0x33, + 0xa7,0x56,0x36,0xb2,0xf7,0x97,0x2c,0xac,0xd2,0xb5,0x9b,0x8d,0xda, + 0x6a,0xc3,0xa9,0x96,0xe3,0x69,0xc5,0xcd,0xe1,0xe7,0x2b,0x74,0x85, + 0x9c,0xbe,0x4a,0xeb,0xf3,0x3e,0xee,0x5b,0xa8,0x31,0x83,0x32,0x02, + 0x07,0x3f,0x31,0x58,0xc6,0x06,0x70,0x03,0x1c,0xe7,0xfb,0xa1,0xb7, + 0x02,0x73,0x9c,0x82,0x0d,0x57,0x3a,0xbc,0x11,0x83,0xfb,0xd5,0x60, + 0xaa,0xe0,0xa9,0x52,0xc4,0x87,0x3b,0xf0,0x8f,0xb7,0x82,0xad,0x9c, + 0x8c,0x60,0x0c,0x60,0x0a,0xf9,0xf7,0xc3,0xdf,0x18,0x7c,0x05,0xe2, + 0xa9,0xde,0x3d,0x0b,0xc5,0xb6,0x57,0x13,0x03,0x33,0xbc,0x73,0x3b, + 0x5a,0x4a,0xc9,0x1d,0xc2,0x5b,0x46,0xe0,0xcf,0x1c,0x2a,0xa9,0x3b, + 0x4b,0x08,0x85,0x49,0x06,0x44,0x75,0x60,0x32,0x5b,0x6f,0x5f,0x16, + 0xb5,0x63,0x3a,0xca,0xd1,0xea,0x76,0x97,0x0b,0x1c,0xa2,0xda,0xe0, + 0xc7,0x77,0x6f,0x3c,0x69,0x70,0x58,0x8f,0xb3,0x4a,0x52,0x46,0x09, + 0x70,0x24,0x05,0x1a,0x19,0x36,0xc8,0x1f,0x23,0x1f,0x74,0x57,0x04, + 0xb2,0x69,0xc5,0xf2,0xd5,0x8c,0xe1,0x35,0xba,0x9c,0x26,0x9a,0x6a, + 0xe9,0xda,0xca,0xfe,0x47,0x9d,0x39,0xba,0x72,0xe5,0x9d,0x3a,0xca, + 0x4b,0x75,0xec,0xe4,0xec,0xfa,0xa7,0x6e,0xa9,0xe9,0xdb,0xb3,0x68, + 0xf4,0xdf,0xed,0xa8,0x76,0x65,0x65,0x32,0x6c,0x2d,0xf2,0x90,0x43, + 0x30,0x90,0x0f,0x97,0x73,0x1f,0x9b,0x6e,0x09,0xe0,0x13,0xb7,0x2d, + 0x8c,0x73,0x55,0x9f,0x56,0x91,0xf8,0xc7,0x96,0xbc,0x1c,0x31,0xdc, + 0x76,0xae,0x30,0x08,0x1d,0x40,0xcf,0x6c,0xe4,0x11,0x9e,0xf5,0xc4, + 0x35,0xc3,0x60,0x0d,0xe5,0xd8,0xe4,0x27,0xca,0x3e,0x56,0x0a,0x55, + 0xd7,0x23,0x05,0x19,0x49,0x21,0xb0,0x55,0xb9,0x2b,0x9d,0xa7,0x14, + 0x1b,0x89,0x06,0x09,0x39,0x00,0x63,0x39,0x00,0x9c,0x67,0x70,0x0c, + 0x0f,0x27,0x80,0x01,0x50,0x71,0x9e,0xe0,0xd3,0xa7,0x96,0x41,0x5e, + 0xfc,0xc9,0xdf,0x44,0xef,0x77,0xf8,0xb5,0xd2,0xde,0xa5,0x2a,0xae, + 0x29,0xc6,0xd2,0x8a,0x7b,0xa7,0x15,0xad,0xd7,0x46,0xff,0x00,0x4f, + 0xf2,0x3a,0xf7,0xbb,0x32,0x80,0xac,0xcc,0x57,0x05,0xc1,0x91,0x89, + 0x58,0xdc,0x0c,0x7c,0x99,0xe4,0x67,0xd0,0xf4,0xea,0x29,0xff,0x00, + 0x69,0xf2,0xd5,0x43,0x10,0xc0,0xb0,0xc1,0x63,0xdb,0x00,0x9e,0x87, + 0xa0,0xe3,0x9f,0xe9,0x91,0x5c,0x8a,0xdd,0xa9,0x01,0x0b,0x06,0x24, + 0x63,0x0c,0x41,0x04,0x82,0x73,0xf3,0x6e,0xe4,0xae,0x72,0x3d,0x73, + 0x83,0xef,0x20,0xbf,0x56,0x1c,0x60,0xed,0xe9,0xf3,0xf4,0xe3,0x6f, + 0xa7,0x4c,0x0c,0x77,0x38,0xc0,0xeb,0xcd,0x6a,0xf2,0xf7,0x1f,0x86, + 0x9d,0xd7,0x4b,0xe8,0xfb,0x74,0xf9,0xfe,0xbb,0x93,0xce,0xbc,0xff, + 0x00,0xaf,0x99,0xd3,0x2d,0xc1,0x75,0x56,0x07,0x20,0x96,0xda,0x0f, + 0xca,0x78,0x76,0x27,0xaf,0x4c,0x00,0x0e,0x4e,0x7b,0x7a,0xe2,0xac, + 0xa0,0x69,0x01,0xcf,0x11,0x92,0x54,0x9e,0x30,0x00,0x01,0x8a,0x8c, + 0x60,0xe4,0x0e,0x41,0x55,0xe8,0x73,0x8c,0x0a,0xe3,0x85,0xf3,0x1c, + 0xc8,0xcc,0x0b,0xc6,0x37,0x46,0x0e,0x48,0xe4,0xee,0x3b,0x80,0xce, + 0x78,0x19,0x23,0xb0,0xf7,0xa7,0xc9,0xab,0x6d,0x50,0x24,0x43,0xe6, + 0x21,0x05,0x84,0x60,0xf9,0x79,0x0a,0x06,0x54,0x93,0x92,0xa5,0x48, + 0x0c,0x76,0xf2,0x72,0x31,0xc7,0x13,0x3c,0x25,0x4b,0x72,0xc6,0x09, + 0x3b,0xec,0xbb,0x3f,0xbf,0x5e,0xb6,0xef,0xdf,0x60,0xf6,0x8b,0xb3, + 0xfb,0x8e,0xb5,0x25,0x81,0x5a,0x45,0x43,0x91,0xe5,0x91,0xbb,0xfb, + 0xe5,0x8a,0xf2,0xc3,0x18,0x19,0xc1,0x07,0x18,0xf5,0xeb,0x55,0x9e, + 0x45,0x5e,0x5b,0x82,0xe0,0xb1,0x00,0xb0,0xe0,0x65,0x79,0xe8,0x78, + 0x5e,0xf8,0xfe,0x1c,0xe6,0xb9,0x5f,0xed,0xe5,0x41,0xe7,0x5c,0x08, + 0xe3,0x4d,0xa4,0x1f,0x36,0x48,0xc2,0xa8,0xce,0xd0,0x49,0x2c,0xaa, + 0x99,0x3c,0x96,0x2c,0x0b,0x77,0x63,0xb4,0xed,0xf2,0xcf,0x15,0x7c, + 0x6f,0xf0,0x7f,0x87,0xac,0x2e,0x67,0x87,0x53,0x87,0x56,0xbf,0xb7, + 0x7b,0xbb,0x7b,0x7b,0x2b,0x23,0x1c,0xe7,0xed,0x96,0x88,0xb2,0xf9, + 0x33,0xc8,0x25,0x53,0x0a,0x1f,0x31,0x3c,0xb9,0xd5,0x64,0x89,0xa4, + 0x56,0x1c,0x80,0xc2,0xae,0x86,0x55,0x89,0xad,0x35,0x1a,0x74,0x2a, + 0xe2,0x25,0x2d,0xa3,0x08,0xbe,0xbe,0x7e,0xe2,0xdf,0xcd,0x22,0xb5, + 0xb2,0x7c,0xb2,0xd6,0xcd,0x7b,0xad,0xde,0xfa,0xfd,0x9b,0xfe,0x27, + 0xb9,0xbd,0xd2,0x95,0x54,0x0c,0xae,0xc3,0x70,0xca,0x91,0x81,0xb5, + 0x77,0x60,0x92,0x03,0x31,0xda,0x0b,0x70,0x77,0x6d,0x07,0x00,0x90, + 0xc4,0x61,0xde,0xf8,0x8b,0x49,0xd3,0x99,0xde,0xfb,0x52,0xb3,0xb4, + 0x11,0x46,0xd7,0x12,0x45,0x34,0xca,0x93,0x24,0x7e,0x6c,0x50,0x97, + 0x6c,0x9f,0x91,0x52,0x6b,0x88,0x91,0x99,0x86,0xc5,0x6f,0xdd,0xb7, + 0xcd,0x85,0x1f,0x08,0x78,0xc3,0xe3,0xff,0x00,0x89,0x35,0xa9,0xee, + 0x74,0xbd,0x29,0xa2,0x82,0xc1,0x6f,0xf5,0x2b,0x68,0xa7,0x89,0x5e, + 0x39,0x6e,0x34,0xab,0xcd,0x3a,0x6b,0x5b,0x58,0xae,0x5d,0x18,0x24, + 0x93,0x5a,0xbc,0xf3,0xce,0xb3,0xc4,0x50,0x33,0xac,0x44,0xae,0x55, + 0x94,0xf8,0x8d,0xdf,0x88,0xb5,0xed,0x50,0xa2,0xcf,0xa9,0xdd,0xdd, + 0xcb,0xe4,0x84,0xdd,0x71,0x72,0xdb,0xd7,0x74,0xc9,0x21,0x88,0xb0, + 0x24,0xca,0xb2,0xbc,0x11,0xbc,0x91,0xc8,0x59,0x59,0x82,0xbe,0x15, + 0xf0,0x47,0xd5,0x60,0xb8,0x3f,0x13,0x51,0x7b,0x4c,0x45,0x5f,0xab, + 0x46,0x49,0x2f,0x67,0x67,0x29,0xae,0xfa,0xe9,0x67,0xe4,0xee,0x8e, + 0xd8,0x61,0x27,0x78,0x73,0xa5,0x69,0xb5,0xd5,0xa7,0x6b,0xab,0xf6, + 0xe8,0xcf,0xd0,0x0f,0x10,0xfc,0x75,0xf0,0xce,0x91,0x64,0x2e,0x51, + 0xc5,0xd5,0xfc,0xd0,0xeb,0x3f,0x63,0xb3,0x49,0x50,0xa7,0x9b,0xa7, + 0x1b,0xf4,0xb3,0x6b,0x96,0x8b,0xe6,0x58,0x35,0x19,0x6c,0x73,0x00, + 0x51,0xbf,0xca,0x60,0xd2,0x27,0xcc,0x31,0xe3,0x9e,0x28,0xfd,0xa5, + 0xef,0x1a,0x4d,0x52,0xd3,0x44,0xb4,0xb4,0x84,0xc7,0x2e,0xa1,0x15, + 0x86,0xa4,0xa0,0x5d,0xe1,0xa1,0x96,0x01,0x69,0x2b,0x24,0xa4,0x24, + 0xaa,0xd1,0xc7,0x76,0x84,0x48,0xaa,0xc1,0xa5,0x80,0xe4,0x88,0xd9, + 0x4f,0xc7,0x73,0xbc,0x88,0xed,0x2c,0xb3,0x4a,0xc7,0xa7,0xcc,0xe7, + 0x82,0xa0,0xe1,0x95,0x08,0x20,0xe3,0x73,0xfc,0xc0,0x00,0x77,0x31, + 0xe7,0x27,0x28,0x3c,0xb5,0x8d,0x9e,0x34,0xf2,0xfc,0xa2,0x8a,0x78, + 0xe3,0xcc,0xe7,0xf8,0xbd,0x76,0x9e,0x43,0x1e,0x4f,0xcd,0xdf,0x23, + 0xe8,0xf0,0xdc,0x2f,0x96,0xe1,0xd7,0xbf,0xed,0x31,0x12,0xd3,0xe3, + 0x6d,0x45,0x7f,0xdb,0xa9,0xfb,0xdd,0x77,0xd3,0x5f,0x2d,0x7b,0x56, + 0x06,0x0b,0x54,0xff,0x00,0x33,0xd6,0x35,0xdf,0x8c,0x1e,0x30,0xd6, + 0x8e,0xa9,0x1a,0xde,0xb5,0x8d,0x96,0xad,0x79,0x75,0x76,0xf1,0x5b, + 0x99,0x11,0xd0,0x4d,0x25,0xbc,0xa6,0xda,0x39,0x95,0x96,0x4f,0x20, + 0x0b,0x74,0x81,0x95,0x56,0x30,0x50,0xcb,0x80,0x0c,0x87,0x1c,0x16, + 0xa3,0xe2,0x0d,0x4f,0x50,0x94,0x3d,0xe5,0xed,0xc5,0xcc,0x91,0xc3, + 0x6f,0x68,0x92,0x4f,0x3c,0xb2,0xc8,0xb0,0x44,0xa4,0x1f,0x98,0x9d, + 0xbe,0x5a,0xee,0x25,0xdd,0x83,0x33,0x0c,0x83,0xb8,0x66,0xb0,0x7c, + 0xf0,0x53,0x24,0x02,0x18,0x4f,0x22,0xba,0x9e,0x1f,0x66,0x51,0xd5, + 0xcf,0x65,0xe4,0xe3,0xa0,0x2c,0x3e,0xb5,0x42,0x4b,0x9b,0x75,0x7b, + 0x85,0xe8,0x8c,0x41,0x65,0xda,0xc4,0x14,0x40,0xae,0xb9,0x27,0xef, + 0x94,0x42,0x77,0x32,0x60,0x75,0x24,0x76,0xaf,0x6b,0x0f,0x82,0xc3, + 0x61,0x55,0xa8,0x51,0x85,0x36,0xf4,0x72,0x8c,0x6d,0x26,0xbb,0x39, + 0x2d,0x6d,0xa2,0xd2,0xf6,0x76,0xbb,0xd4,0xea,0xa3,0x86,0x84,0x6c, + 0x92,0x5c,0xc9,0x34,0xdb,0xbb,0x56,0x6f,0x5d,0x35,0xfc,0x8d,0xa8, + 0x66,0x93,0xcc,0x8d,0x64,0x20,0x6c,0x37,0x00,0x05,0x23,0x6c,0x9c, + 0xb3,0xac,0x99,0xe8,0xab,0xed,0xc6,0x49,0xec,0x78,0xa6,0xbb,0x27, + 0xcf,0x92,0x17,0x23,0x70,0x50,0xb9,0x73,0xb4,0x97,0x00,0x0c,0xe4, + 0x6e,0xe0,0x02,0x00,0xce,0x08,0x1f,0x77,0x8c,0x56,0xba,0x92,0x77, + 0x3f,0x30,0x88,0xca,0x5c,0x22,0x21,0x00,0x08,0x4c,0x71,0xb7,0xcb, + 0x80,0x40,0xc8,0x3b,0xb2,0x48,0x3f,0x36,0x38,0x20,0xe6,0xa4,0x97, + 0xd2,0xab,0x6d,0x84,0x93,0x93,0x3a,0x6c,0x58,0x8b,0x91,0xb4,0x9d, + 0xaa,0xec,0x49,0x60,0x0a,0x3e,0x54,0x60,0x16,0x73,0x80,0x36,0xae, + 0x6b,0xa5,0xa4,0xf7,0xbe,0x9e,0x6f,0xfc,0xf7,0xf3,0x3a,0xa3,0x42, + 0x52,0xbf,0x2f,0x2d,0xfa,0xee,0xbd,0x3a,0x1d,0x3a,0x97,0x01,0x11, + 0x18,0x46,0x1b,0x63,0xaf,0x07,0x73,0xfc,0xaa,0xdf,0x7b,0xef,0x0d, + 0xa0,0xe1,0xc3,0x00,0x47,0x53,0x81,0x9a,0x93,0xcc,0x76,0x6d,0xb1, + 0xc8,0x30,0x3c,0xc6,0x91,0x82,0x0e,0xac,0xf8,0x20,0xb0,0x24,0xfd, + 0xdf,0xe2,0xe7,0x24,0xff,0x00,0x74,0xe6,0xb9,0x06,0xba,0xd4,0x03, + 0x3c,0x8c,0xcb,0x12,0x22,0xc9,0xf3,0x6f,0x24,0x39,0x2a,0x80,0xbe, + 0x4e,0x3e,0x66,0x4e,0xaa,0x06,0x76,0x92,0x71,0xe8,0xb2,0x6a,0x12, + 0x45,0x13,0x11,0x71,0x11,0x0c,0xeb,0xf2,0xa1,0x65,0x21,0x57,0x2c, + 0x32,0x30,0x4c,0x9e,0x62,0x90,0x4f,0x2a,0x43,0x21,0x62,0x0e,0x4e, + 0x21,0xc6,0x4f,0x76,0xbf,0xaf,0x91,0x7f,0x55,0xa9,0xfd,0xdf,0xbf, + 0xfe,0x01,0xd4,0x09,0x7c,0xe1,0x03,0x63,0x63,0x44,0xc2,0x4d,0x92, + 0x28,0x39,0x72,0xad,0xc2,0xe4,0x1d,0xa1,0x82,0x85,0x3d,0xce,0x71, + 0x81,0x9c,0x52,0xcd,0x74,0x1c,0x41,0x26,0xf0,0x36,0xa4,0x32,0x88, + 0x82,0x0c,0x47,0x86,0xf3,0xb1,0xce,0x30,0x49,0x62,0xaa,0x13,0xe5, + 0x00,0x84,0x1c,0x81,0x5c,0x7f,0xf6,0xf9,0x52,0xed,0x28,0x32,0x61, + 0xd4,0x12,0xb1,0xb6,0xe3,0x84,0x77,0x43,0x9d,0xea,0x0e,0x51,0x0e, + 0x4e,0x7a,0xe0,0x9e,0x71,0x99,0x8e,0xbf,0x67,0x22,0x24,0x5b,0x65, + 0x85,0x63,0x51,0x0e,0xf3,0x1a,0xc8,0x92,0x00,0x03,0xa2,0x9c,0xb8, + 0x6d,0xf8,0x0d,0x8c,0x1c,0xa9,0x1c,0xf5,0x02,0xa7,0x95,0xdd,0x2d, + 0x2e,0xff,0x00,0xaf,0xd0,0x97,0x42,0xa2,0x97,0x2d,0xb5,0xee,0xb5, + 0x5b,0x5f,0xb7,0xe8,0x6f,0xca,0x64,0x49,0x25,0x32,0x12,0xd0,0x3c, + 0x91,0x98,0xca,0xb0,0xd8,0xa9,0x29,0x90,0xc8,0x8e,0xf9,0x5d,0x8a, + 0x1c,0x95,0xf5,0x8f,0x01,0x72,0x59,0xb1,0x55,0x6e,0x27,0x50,0x85, + 0x43,0x28,0x12,0xa5,0xd4,0x8a,0xab,0x9f,0xba,0xb6,0xee,0xae,0x87, + 0x05,0xb0,0xac,0x40,0x00,0x37,0xdd,0x6c,0xbe,0x32,0x4d,0x54,0x86, + 0xfe,0x16,0x47,0x57,0x90,0xb1,0x90,0xfc,0xc8,0x43,0x23,0x8d,0xcc, + 0xd2,0x02,0xfe,0x62,0x2e,0x43,0x09,0x06,0xcd,0xb8,0x01,0x94,0xb7, + 0x24,0xd4,0xac,0x22,0x91,0x5e,0x40,0xe0,0x6d,0xb6,0xb8,0x58,0x8e, + 0x0a,0xe4,0x3c,0x4c,0x59,0x76,0x0c,0x96,0x24,0xa0,0xe4,0x00,0x37, + 0x1c,0xf1,0x9c,0x1b,0x83,0xe4,0x9a,0xbf,0xfc,0xfc,0xc3,0xae,0xfb, + 0xe2,0x68,0x7a,0x11,0x3a,0x53,0x57,0x87,0xbb,0x7b,0x35,0xbb,0xfe, + 0x56,0xfb,0x1f,0xe8,0xdf,0xfb,0x1a,0x9c,0xfe,0xc8,0x9f,0xb2,0xd1, + 0x18,0xc1,0xfd,0x9c,0xbe,0x06,0x9e,0x37,0x63,0x9f,0x85,0xbe,0x14, + 0xe9,0xbb,0x0d,0x8f,0xf7,0x80,0x3e,0xbc,0xd7,0xd2,0x75,0xf3,0x5f, + 0xec,0x68,0x73,0xfb,0x21,0xfe,0xcb,0x27,0x9e,0x7f,0x67,0x1f,0x81, + 0x87,0x9c,0xe7,0x9f,0x85,0xbe,0x13,0xeb,0x9e,0x73,0xf5,0xe7,0xd6, + 0xbe,0x94,0xaf,0xf9,0xda,0xe2,0xcf,0xf9,0x2a,0x78,0x93,0xfe,0xc7, + 0xd9,0xbf,0xfe,0xa7,0xe2,0x0f,0xf7,0x07,0x86,0x3f,0xe4,0x9b,0xe1, + 0xff,0x00,0xfb,0x12,0xe5,0x7f,0xfa,0x85,0x40,0x28,0xa2,0x8a,0xf9, + 0xf3,0xdc,0x0a,0x28,0xa2,0x80,0x0a,0x28,0xa2,0x80,0x0a,0x28,0xa2, + 0x80,0x3f,0xcb,0xd7,0x5f,0xf8,0xe3,0xf1,0x33,0xc5,0x90,0xde,0x69, + 0x3a,0x9f,0x89,0xef,0xda,0xc6,0x79,0x96,0xe5,0xed,0xe2,0x51,0x63, + 0x17,0x9d,0x1c,0xf3,0x4c,0x8c,0xa6,0x2f,0xdf,0x22,0xa9,0xba,0x96, + 0x32,0xa9,0x2f,0x96,0x12,0x18,0x51,0x57,0x64,0x6b,0x5e,0x5f,0x32, + 0x48,0x9e,0x44,0xad,0x30,0x94,0x87,0x90,0x29,0x91,0x9d,0x81,0x50, + 0x14,0xe5,0x77,0x33,0x8c,0x32,0xe5,0x40,0x38,0xe8,0x7e,0x50,0x49, + 0xac,0x87,0x9d,0xcc,0xb3,0x12,0xa6,0x2c,0x44,0x37,0x18,0xf1,0xfb, + 0xcd,0xfe,0x59,0x08,0x4b,0x72,0x30,0xca,0x08,0x3d,0x7d,0x38,0x18, + 0xa6,0x93,0x29,0xfb,0x2d,0xb1,0x07,0xef,0xb3,0xee,0x46,0x29,0x95, + 0x7c,0x3e,0xd6,0x2d,0x93,0xf2,0x83,0xd8,0xe5,0x88,0xc7,0x19,0x18, + 0xff,0x00,0xa4,0x0a,0x78,0x7a,0x74,0x54,0xbd,0x8d,0x3a,0x74,0x53, + 0xd5,0xaa,0x51,0xe5,0x52,0xb2,0xeb,0xf2,0xd3,0xd0,0xff,0x00,0x10, + 0x29,0x61,0xe8,0xd1,0x4d,0x52,0xa5,0x4e,0x9d,0xfa,0xc1,0x2d,0xfb, + 0xec,0xb6,0x35,0xe3,0xbb,0x08,0xb0,0xbc,0xa7,0x12,0x3d,0xc8,0x9a, + 0x5f,0x2d,0x8a,0x32,0xec,0x3f,0x2a,0x86,0xe7,0x89,0x4e,0xdd,0xf9, + 0x1c,0x63,0x39,0x20,0x00,0x2e,0xa4,0xb0,0xfc,0xcb,0x6a,0xd2,0x85, + 0x38,0x79,0x95,0xc9,0x90,0x6e,0x9a,0x42,0x22,0x0a,0x70,0x80,0x6d, + 0xe4,0xae,0x64,0xd8,0x48,0x66,0x64,0xc1,0x22,0xb9,0x72,0x1a,0x59, + 0x02,0xb7,0xdc,0x8f,0x73,0x34,0xa1,0x8e,0xe6,0x55,0x21,0xd5,0x97, + 0xb3,0x1e,0xcf,0xc0,0x00,0x15,0x07,0x81,0xcd,0xb5,0x31,0xc2,0xaa, + 0xde,0x7b,0xef,0xf2,0xf7,0x3c,0x6b,0x81,0x11,0x2c,0xcc,0x43,0xb0, + 0x19,0x5d,0xe0,0xb6,0xc2,0x07,0x00,0x30,0xc0,0x1f,0x35,0x2b,0x2b, + 0xde,0xca,0xef,0x4b,0xdb,0x5f,0xbc,0x7e,0xc6,0x3a,0xe9,0x1d,0x5d, + 0xdf,0xb8,0xb5,0x7d,0xdf,0x76,0x74,0xb7,0x17,0xab,0x09,0xf2,0x50, + 0x3a,0xaa,0x22,0x32,0xb9,0x20,0xac,0xc1,0xd5,0x3c,0xf7,0x76,0x05, + 0xe4,0xdc,0x65,0x91,0xb0,0xcd,0xf3,0x01,0xb7,0x1b,0x8a,0xd4,0x69, + 0x79,0x74,0x04,0x2e,0xe4,0xb0,0x12,0x01,0xbd,0x88,0x92,0x41,0x93, + 0x88,0xcb,0x05,0x65,0x6c,0x74,0x0b,0x95,0x1c,0x29,0x24,0x9e,0xf8, + 0x91,0xcd,0xf3,0x48,0x43,0x96,0x8c,0xe7,0xae,0xc2,0xc4,0x46,0x72, + 0x30,0x10,0x95,0xde,0x83,0x3c,0x8c,0xfc,0xb9,0xc1,0x19,0xa7,0x09, + 0x31,0x21,0x7c,0xef,0x28,0x63,0x0c,0x81,0x41,0x94,0x37,0x2c,0x48, + 0x12,0x0c,0x10,0x40,0x18,0x1c,0x71,0x93,0x9e,0x33,0x4f,0xad,0xfa, + 0xad,0x53,0xeb,0xf7,0x90,0xa9,0x25,0x37,0x65,0x14,0xda,0xb6,0x8b, + 0xa6,0x9d,0x52,0x3a,0x48,0x75,0x57,0xb5,0x50,0xa3,0x76,0xe6,0x51, + 0x12,0xe1,0x9a,0x19,0x19,0xa0,0x92,0x56,0x2c,0xee,0xbf,0x36,0xe0, + 0x1d,0x56,0x29,0x3a,0xab,0xa1,0x75,0xc6,0x54,0x0d,0x5d,0x3f,0xc5, + 0x5a,0xdd,0x9c,0x12,0xc7,0x67,0xa9,0xde,0xdb,0x41,0x77,0x75,0x1d, + 0xf4,0x91,0xc3,0x7d,0x22,0xab,0x5d,0x5b,0x97,0x7b,0x79,0x25,0x58, + 0xd9,0x4c,0x93,0x79,0x41,0xdd,0x67,0xc8,0x91,0xa5,0x66,0x6c,0x87, + 0x39,0x1c,0x6e,0xe4,0x93,0x04,0x30,0x47,0x40,0x55,0x4b,0x6d,0x0c, + 0x19,0xb2,0x50,0xed,0xfd,0xe1,0x50,0x43,0xb9,0x66,0x24,0x86,0xc6, + 0x72,0x30,0x31,0x20,0x94,0x84,0x8e,0x02,0xb1,0x3b,0xa3,0xb3,0x0f, + 0x40,0x46,0x32,0x41,0x85,0xd4,0x29,0x60,0xd9,0x8d,0x0e,0x41,0x56, + 0x54,0x03,0x0c,0x28,0x7a,0xbe,0x67,0xac,0x9d,0x93,0x93,0xd5,0xd9, + 0x6c,0xae,0xf5,0xd3,0xa1,0x12,0xa1,0x4d,0xb7,0xee,0xeb,0xaa,0xf7, + 0x92,0x92,0xb7,0x64,0xac,0xac,0xbc,0xbe,0x47,0xb4,0x68,0xdf,0x1b, + 0x3e,0x24,0x68,0xb3,0xa5,0xdd,0xb7,0x89,0xf5,0x19,0x66,0x59,0x2e, + 0xa5,0xf2,0xef,0x67,0x37,0xd0,0x34,0xba,0x84,0x71,0xa4,0xf2,0x1b, + 0x7b,0x82,0xe0,0x4b,0x2a,0x45,0x1e,0x64,0x59,0x95,0xa3,0x2a,0x5d, + 0x06,0xfe,0x6b,0xe8,0x5f,0x09,0xfe,0xd6,0xe5,0xe0,0xb7,0xb6,0xf1, + 0x8e,0x91,0x71,0x33,0xc9,0x2c,0x9e,0x65,0xf6,0x92,0x23,0x8c,0x2c, + 0x6f,0x14,0x0f,0x0a,0x8b,0x29,0x65,0x2a,0x67,0xf3,0x8c,0xca,0xea, + 0x92,0x66,0x60,0x62,0x65,0x65,0x69,0x14,0x0f,0x85,0x21,0xc4,0x41, + 0x43,0x14,0x7e,0x66,0x02,0x26,0x27,0xcb,0x3f,0x2a,0x87,0x7d,0xaa, + 0x32,0x84,0x96,0x50,0xab,0xf3,0x30,0x50,0x4a,0x9d,0xed,0x9a,0xb6, + 0x66,0x10,0xae,0xd0,0x55,0x8f,0x94,0x92,0xc5,0x30,0x2a,0x36,0xb1, + 0xf2,0xf8,0x56,0x53,0x9d,0xa8,0x23,0x0a,0x38,0x07,0xb1,0xc1,0xe6, + 0xb8,0x2a,0xe5,0x98,0x1a,0xb1,0xb4,0xb0,0xf0,0xbd,0xfe,0x38,0xa5, + 0x19,0x45,0x6b,0xf0,0xb8,0xa5,0xaa,0x6d,0xb5,0xd9,0x9e,0x7d,0x4c, + 0xaf,0x05,0x28,0xda,0x54,0x23,0xcc,0xde,0x92,0x8c,0xa4,0x9a,0x5d, + 0x7a,0xfa,0x79,0x77,0x5b,0x1f,0xa9,0xe7,0xf6,0x82,0xf8,0x6c,0x34, + 0xe5,0xba,0x6d,0x68,0x41,0x3f,0xd8,0x96,0xf2,0xde,0xca,0xe6,0x19, + 0x52,0xe6,0x63,0x2c,0x13,0xdc,0x25,0xbb,0x6d,0x0e,0x91,0xce,0xcf, + 0x0a,0xc0,0xfb,0xc8,0x09,0x34,0xc8,0xad,0x8d,0xb9,0x37,0x74,0x3f, + 0x8d,0xfe,0x02,0xd5,0x96,0x50,0x6f,0xc5,0xab,0xc5,0x36,0x9a,0x1a, + 0x29,0x64,0x3b,0xbc,0xbd,0x4e,0xde,0x37,0x89,0x93,0xca,0xf3,0x3c, + 0xc7,0x86,0x46,0x9a,0x2b,0xb8,0x53,0x73,0xdb,0xb4,0x25,0xb7,0x30, + 0x25,0x87,0xe5,0x44,0x37,0x2e,0x63,0x69,0x3c,0xc6,0xb8,0x71,0x70, + 0xe8,0xb1,0x3e,0xd0,0xab,0x13,0x95,0x92,0x47,0x0e,0xb8,0x66,0x00, + 0x92,0xdb,0x57,0x80,0xcb,0xdd,0x9b,0x87,0x8d,0x40,0xac,0x73,0x32, + 0x5c,0xa4,0x31,0x24,0x8a,0xa6,0x03,0x2e,0xc7,0x21,0xf8,0xce,0xed, + 0xad,0xc6,0x1b,0x74,0x64,0x61,0x1d,0xf7,0x8e,0x70,0x45,0x71,0xcb, + 0x22,0xc2,0x34,0xd4,0x27,0x5a,0x37,0xd9,0xb9,0x5e,0x4b,0xba,0xf4, + 0x6b,0xbf,0x76,0x79,0xef,0x21,0xc2,0xb5,0x24,0xa7,0x52,0x2d,0xbb, + 0xa6,0x9d,0xdc,0x76,0xef,0xd6,0xca,0xda,0xe9,0xa9,0xfa,0xd7,0xac, + 0x7c,0x56,0xf0,0x9e,0x97,0x61,0x7f,0x7b,0x25,0xf0,0xdf,0x61,0xa8, + 0x6a,0x9a,0x48,0xb5,0xf9,0x1d,0xae,0xef,0x34,0x99,0x23,0x86,0x63, + 0x07,0x95,0x2b,0x16,0xb6,0x79,0x26,0x8d,0x4c,0xe3,0xee,0x02,0xe1, + 0x94,0xba,0x15,0x3e,0x3d,0x79,0xfb,0x47,0xc9,0x2a,0xc5,0xf6,0x3d, + 0x39,0x2d,0xa4,0x90,0xce,0x5a,0x1b,0x86,0x12,0x14,0x21,0x8a,0xc6, + 0xb3,0xca,0x3e,0x47,0x32,0x46,0xeb,0x20,0x58,0x4a,0x91,0x2c,0x62, + 0x36,0x21,0x5c,0x91,0xf0,0x13,0x5d,0x5c,0xcb,0x27,0x9d,0x0c,0xe6, + 0x78,0xc6,0xd9,0x55,0x5a,0x56,0x2c,0xfe,0x6b,0x89,0x6e,0x0b,0xe6, + 0x53,0x1e,0x65,0xb8,0x8c,0x90,0xea,0x37,0x6e,0xce,0xcd,0xca,0xa3, + 0x12,0x26,0xb3,0x73,0xb5,0x55,0xae,0x25,0x89,0x4d,0xcb,0x9d,0xd9, + 0xde,0xcc,0x64,0xce,0xe0,0xe1,0x06,0x70,0x4e,0x01,0x6c,0x96,0x38, + 0x03,0xa5,0x5e,0x1f,0x25,0xc1,0xd2,0x7f,0xbd,0x8f,0xd6,0x35,0xde, + 0xa5,0xa2,0xf6,0xb5,0xbd,0xd5,0x67,0xea,0xf5,0xfb,0x8a,0xa7,0x91, + 0xd1,0x8c,0x5c,0x62,0xdd,0x49,0x5e,0xea,0x53,0x49,0xbb,0x75,0x5d, + 0xbd,0x2c,0x7d,0x11,0xe2,0x2f,0x88,0xfe,0x29,0xf1,0x3c,0x0b,0x6f, + 0xa9,0x6a,0x33,0xb4,0x2a,0x5d,0xa6,0x58,0x24,0xfb,0x2c,0x0f,0x6f, + 0x18,0xdf,0x12,0xbc,0x31,0x04,0x57,0xd9,0x2b,0x5c,0x64,0xb6,0x08, + 0x47,0x68,0xf2,0xea,0x71,0x5c,0x24,0x93,0xc7,0x20,0x53,0xb5,0x54, + 0xa8,0x32,0x37,0x96,0xcc,0xdb,0x94,0x87,0x5e,0x13,0x3b,0xc0,0x18, + 0x18,0x24,0x91,0xc7,0xca,0x7d,0x7c,0xce,0x5d,0x73,0x52,0xd8,0x91, + 0xac,0x89,0x3a,0x65,0x3c,0xcf,0x97,0x24,0xa7,0x2b,0xb0,0x3f,0x04, + 0xed,0x56,0x27,0x69,0x38,0x52,0x41,0x3d,0x8d,0x3e,0x3d,0x68,0xae, + 0xcf,0x35,0x21,0x63,0x2a,0x45,0x1b,0x93,0xbd,0x37,0x92,0xf2,0x2a, + 0x30,0x2a,0x77,0x29,0x11,0x81,0x90,0x41,0x04,0xe7,0x8c,0x74,0xf5, + 0x61,0x4e,0x9d,0x35,0xcb,0x4a,0x9c,0x69,0xc2,0xdc,0xaa,0x31,0x8a, + 0x5e,0xea,0xd9,0x3b,0x2d,0x6c,0x8b,0xa7,0x82,0xa9,0x49,0xc9,0x24, + 0xac,0x92,0x8a,0xb6,0x9a,0x46,0xe9,0x6d,0xa6,0x8b,0xb6,0x87,0xa2, + 0xc9,0x75,0x0e,0xe0,0xb1,0x5d,0xac,0xb2,0x89,0xa6,0x67,0x74,0x56, + 0x00,0x5b,0x8b,0x60,0x8a,0xc3,0x7f,0x2a,0x11,0x83,0x31,0x0a,0x78, + 0x65,0xc0,0x23,0x38,0x35,0x7e,0xd9,0x1c,0x26,0x29,0x0c,0xdb,0xdc, + 0x18,0xcf,0x11,0xb0,0x8c,0x12,0x85,0x36,0x93,0xc0,0x66,0x67,0x1b, + 0x9b,0x93,0xc3,0x02,0x71,0x8e,0x78,0x1f,0xed,0x31,0x09,0x01,0x10, + 0x37,0x9a,0xc5,0x4b,0x16,0x90,0xb0,0x8a,0x43,0x90,0xa3,0xa0,0x20, + 0x8c,0x91,0x91,0xc8,0x3c,0xf2,0x72,0x1c,0x6f,0x4a,0xb3,0x6e,0x11, + 0xc8,0xd9,0x20,0x10,0xed,0x8d,0xa1,0x5d,0x42,0xef,0xdd,0x91,0xd5, + 0x8b,0x11,0xe9,0x80,0x41,0x39,0x1b,0x39,0x6a,0x9a,0xba,0xef,0xe6, + 0x74,0xbc,0x23,0x76,0xbc,0xa2,0xed,0xf0,0xde,0x3b,0x7a,0x76,0xd7, + 0xb1,0xd5,0xcd,0xaa,0xc7,0x3b,0x9c,0xa2,0xbc,0xbe,0x5c,0x61,0x70, + 0x19,0x54,0x2b,0x6e,0x0c,0x06,0x7d,0x32,0x06,0x46,0x32,0x39,0x39, + 0xe1,0x85,0x79,0x2f,0xe3,0xdc,0xab,0x0e,0xfe,0x0e,0x18,0x33,0x10, + 0x99,0x07,0x00,0xb0,0xc9,0xc1,0xdd,0xc9,0x38,0x73,0xb4,0x15,0x19, + 0x07,0x23,0x98,0x17,0x71,0x33,0x98,0xe6,0x4f,0x2e,0x20,0x10,0x45, + 0x32,0x4a,0xcc,0xec,0x23,0x57,0x3b,0x79,0x39,0xc6,0xe5,0x6d,0x84, + 0xf2,0x14,0x6d,0x2c,0xd8,0xe2,0x0f,0xed,0x00,0x02,0xa8,0x09,0xb5, + 0xca,0x12,0x46,0x49,0xf9,0x55,0xd8,0xc9,0x86,0xce,0x48,0x03,0x2c, + 0x5b,0x2a,0xa0,0x72,0xa4,0x1c,0x0d,0x13,0xba,0xb9,0x50,0xc3,0x38, + 0xca,0x2d,0xb8,0xc9,0x2d,0xd3,0x5b,0xe8,0xfb,0xe9,0xf7,0x9b,0xa6, + 0xfd,0xe3,0x8b,0x00,0xbc,0xd7,0x0e,0x3c,0xcc,0x99,0x1f,0x64,0x60, + 0xcd,0xc9,0x64,0x60,0xaa,0x44,0x91,0xb1,0x19,0x51,0xb4,0x31,0xce, + 0xc0,0x45,0x43,0x7b,0x70,0x03,0x38,0x91,0x82,0x17,0x48,0xf7,0xc8, + 0x87,0x20,0x14,0x56,0x66,0x00,0x8f,0x98,0xc6,0xdf,0xbb,0xc0,0x04, + 0x6d,0x28,0x7d,0x79,0xc3,0x37,0xf2,0x4e,0xa1,0x64,0x9d,0x43,0xa1, + 0x99,0xa5,0x0c,0x01,0x2c,0x8c,0x1b,0x6c,0x78,0xc0,0x18,0x71,0x20, + 0x70,0x7a,0xe0,0x05,0xed,0xc6,0x73,0x4d,0x23,0x8f,0x32,0x37,0x18, + 0x59,0x59,0x02,0x64,0x2a,0x80,0xd1,0xe5,0x09,0x4f,0xb8,0x46,0xc6, + 0x05,0xb8,0x19,0x05,0x78,0x07,0x14,0xce,0xb8,0xd2,0x83,0x7a,0x42, + 0x0b,0xfe,0xdd,0x5f,0xe4,0x74,0xe7,0x50,0x83,0x2a,0xc6,0x50,0xf2, + 0x7c,0xa8,0xe2,0x30,0x56,0x35,0x50,0x12,0x32,0xac,0x46,0x0e,0x59, + 0xb0,0xc5,0x97,0x92,0x49,0x27,0x8c,0x81,0x56,0x4d,0x52,0x67,0xca, + 0x21,0x48,0xd5,0x2e,0x26,0x86,0x55,0x05,0xb7,0x11,0x9c,0x2b,0xa4, + 0x9b,0xb3,0x84,0xd8,0x39,0xc9,0x65,0x39,0x3b,0xb1,0xc5,0x73,0x4b, + 0x3e,0xc1,0x19,0x78,0xc3,0x30,0xc3,0x48,0x43,0x28,0x0c,0xed,0x97, + 0x18,0xc3,0x6d,0x0a,0xa3,0x04,0x60,0x06,0x2d,0xc9,0x38,0x26,0x9c, + 0x8c,0x03,0xab,0x13,0xc1,0x49,0xa3,0x3c,0x01,0x92,0x0b,0xa9,0x3b, + 0x3b,0xb3,0x1e,0x43,0x83,0x99,0x36,0xb0,0x5c,0x11,0x41,0x6a,0x92, + 0x5b,0x72,0xaf,0x45,0xff,0x00,0x0d,0xd4,0xd8,0x6d,0x45,0xa3,0x23, + 0x92,0xcb,0xe5,0xb2,0xb8,0x91,0x8b,0xef,0x12,0x3b,0x10,0x40,0xc8, + 0x1e,0x62,0xab,0xaa,0xaf,0x00,0xfc,0xa7,0x92,0x2a,0xb9,0xbc,0x50, + 0xcd,0x08,0x11,0xae,0xc4,0x20,0xcb,0x96,0xe0,0x46,0x81,0xb7,0x1c, + 0x75,0xf9,0x77,0x28,0xc7,0x2d,0xf3,0x0e,0x3a,0x56,0x18,0x62,0x51, + 0x83,0x32,0x00,0xaf,0x18,0x62,0xcd,0xb4,0x9d,0xa0,0x36,0x00,0x20, + 0x92,0xc4,0x1c,0x28,0x04,0x73,0xc6,0x73,0xd2,0x4d,0xa8,0x5f,0xfb, + 0xfb,0xa7,0x09,0xc7,0x40,0xd3,0xa0,0x5c,0xa9,0xe9,0x84,0x52,0x09, + 0x2b,0x80,0xac,0x0e,0x3a,0xd0,0x37,0x06,0xae,0xef,0xb1,0xb5,0xe7, + 0x23,0xd9,0xac,0xca,0xcc,0xd1,0x42,0x1a,0x40,0x5f,0x99,0x19,0x64, + 0xea,0xc7,0xd0,0x2f,0xc8,0x31,0xb5,0x8e,0xd0,0xc3,0xe5,0xdc,0x30, + 0xc5,0x9c,0x81,0xb1,0x38,0x55,0x96,0x37,0x5d,0xdc,0xc6,0xfc,0xec, + 0xdd,0x87,0xdc,0x77,0x34,0x4c,0x5c,0x05,0xc7,0xdd,0x5f,0x7a,0xc4, + 0x3f,0xbb,0x8c,0x28,0x70,0xc8,0xa8,0xf1,0x4a,0x48,0xc2,0xc8,0xa1, + 0x90,0x2a,0x9e,0xe0,0xb1,0x07,0xe6,0xe1,0x80,0x18,0xe7,0x26,0x9e, + 0xd3,0x33,0x14,0xce,0x30,0x8e,0xa9,0x9e,0x99,0x55,0x8d,0xc9,0xc6, + 0x78,0x05,0x8b,0xfb,0x10,0x17,0x04,0x13,0x8a,0x3c,0xed,0xa8,0xa3, + 0x1e,0x6d,0x6f,0x6f,0x97,0xa1,0xb3,0xf6,0x81,0x3c,0xa1,0xdb,0x03, + 0xcb,0x88,0xbb,0x12,0x40,0x67,0x2e,0xa5,0x15,0x79,0xe0,0xaa,0x60, + 0x05,0xc7,0x1f,0xc4,0x30,0x73,0x89,0xe4,0xb9,0x60,0x25,0x40,0xd8, + 0x97,0xc8,0x9e,0x45,0x8b,0x05,0x3c,0xb1,0xf6,0x47,0x04,0x89,0x10, + 0xe1,0x8a,0x08,0xdd,0xd8,0xe3,0x03,0x2b,0xc1,0x6e,0x9c,0xf8,0x96, + 0x45,0x69,0x15,0x88,0x1e,0x64,0x25,0x39,0xe0,0xf5,0xda,0x02,0x8f, + 0xef,0x7e,0xf0,0x71,0x9e,0x30,0x4e,0x7a,0x02,0x19,0xce,0xc9,0xc9, + 0x8f,0x76,0x6d,0xee,0xa2,0x2c,0x1f,0x0c,0x01,0xb3,0x06,0x42,0x01, + 0x39,0x01,0xb0,0x31,0x8c,0x80,0x4b,0x30,0x3c,0x83,0x4d,0x25,0x78, + 0xdd,0x2f,0xe2,0xe1,0xfa,0x2f,0xfa,0x09,0xa3,0xdc,0x4a,0x11,0xf6, + 0x8a,0xf1,0x4f,0x59,0x5f,0x45,0xaf,0xee,0xe7,0xdf,0xd7,0xa9,0xfe, + 0x98,0xbf,0xb1,0x53,0xf9,0x9f,0xb1,0xd7,0xec,0xa1,0x20,0x25,0x83, + 0xfe,0xcd,0x5f,0x01,0xdc,0x31,0xc9,0x2c,0x1b,0xe1,0x4f,0x84,0x9b, + 0x24,0x9e,0x72,0x73,0x9e,0x6b,0xe9,0xba,0xf9,0x83,0xf6,0x25,0x6d, + 0xdf,0xb1,0xaf,0xec,0x98,0xd8,0xc6,0xef,0xd9,0x9b,0xe0,0x23,0x60, + 0x74,0x19,0xf8,0x4f,0xe1,0x13,0x81,0xf4,0xaf,0xa7,0xeb,0xfe,0x75, + 0xb8,0xb3,0xfe,0x4a,0x9e,0x24,0xff,0x00,0xb1,0xf6,0x6f,0xff,0x00, + 0xab,0x0c,0x41,0xfe,0xd6,0x70,0xd7,0xfc,0x93,0x99,0x0f,0xfd,0x89, + 0xb2,0xcf,0xfd,0x42,0xa2,0x14,0x51,0x45,0x7c,0xf9,0xed,0x85,0x14, + 0x51,0x40,0x05,0x14,0x51,0x40,0x05,0x14,0x51,0x40,0x1f,0xe4,0xf5, + 0x14,0xe8,0x59,0x77,0x8f,0xde,0xef,0xc2,0x9e,0x76,0xe0,0xe1,0x50, + 0x9e,0xa7,0x0a,0x39,0x27,0x8c,0x63,0x18,0x15,0x64,0xbf,0x98,0x9b, + 0xcb,0xf9,0x81,0x65,0x97,0x95,0xc0,0xc0,0x2a,0x0a,0xf2,0x7e,0x51, + 0xb7,0x61,0x62,0x71,0xc0,0x23,0xb7,0x5c,0x8c,0x9c,0xc6,0xc8,0x09, + 0x62,0x65,0x38,0xec,0x84,0x12,0x18,0x36,0x78,0x3b,0x7e,0x5c,0x2f, + 0x40,0x09,0xce,0x73,0x9a,0x9c,0x33,0x24,0x41,0x58,0x72,0xec,0xe1, + 0x48,0x03,0x62,0x48,0xe1,0x10,0xbe,0xde,0x46,0xd5,0xe0,0x9c,0xf0, + 0xa7,0x1f,0xde,0xaf,0xfa,0x40,0x3f,0xc4,0xc7,0x49,0xad,0xee,0xbd, + 0x55,0xbf,0xaf,0xd0,0xbe,0xd2,0x6f,0x76,0x45,0x94,0x38,0x76,0x95, + 0x55,0x06,0xdc,0xa6,0xf8,0xd0,0xc8,0xc4,0x8e,0x1b,0xcc,0x09,0x8e, + 0x32,0xab,0xd0,0xf2,0x46,0x6b,0x99,0x65,0x3e,0x6a,0x64,0x15,0x93, + 0x0c,0x58,0x02,0xcc,0x55,0xdc,0x0e,0xbd,0x57,0x0a,0x9b,0x7d,0x30, + 0xa4,0xe7,0x8a,0xab,0xe6,0x37,0x98,0xa0,0xe0,0x09,0x19,0x95,0x08, + 0x1b,0x71,0x26,0x00,0x6d,0xcd,0xb8,0x8e,0x39,0x66,0xe7,0xa9,0x18, + 0x04,0x71,0x4a,0xb7,0x1e,0x5c,0xea,0x51,0xcb,0xaa,0x61,0x15,0xf9, + 0x2b,0x18,0x45,0x08,0x47,0x2a,0xa5,0xc1,0x3b,0xf0,0x39,0x3c,0xf3, + 0xd0,0xe4,0x0f,0x63,0x2b,0x5f,0xf1,0x5f,0x0f,0xce,0x5b,0x2e,0xc6, + 0x80,0x92,0x78,0xd8,0x24,0x6c,0x89,0x1c,0x86,0x5c,0xe4,0x65,0x17, + 0xf7,0x60,0x70,0x47,0xcc,0x0b,0x72,0xa4,0xae,0x08,0xdc,0x41,0x22, + 0x9e,0x67,0x1e,0x5a,0x99,0x80,0x1e,0x4a,0x44,0xa7,0x76,0x79,0xb8, + 0x85,0xa4,0x2d,0xb8,0xa8,0xc9,0xc2,0x15,0xe0,0xf0,0x77,0x75,0xac, + 0xbb,0x79,0xa5,0x6d,0xaa,0x50,0x02,0xbe,0x63,0x36,0xfe,0x09,0x04, + 0x74,0xc1,0x3c,0xe5,0x55,0x40,0xe9,0xc9,0x3e,0xa6,0xa5,0x7d,0xed, + 0x23,0xa1,0x18,0x28,0x92,0x48,0x03,0x1c,0xee,0x76,0x5c,0xbe,0xee, + 0xdf,0x2a,0xe7,0x67,0x3d,0x70,0xb9,0xe7,0x34,0x0b,0xd9,0xb5,0xbb, + 0x5f,0x2d,0x57,0xde,0x9e,0xa6,0xac,0x53,0x96,0x8d,0x06,0x63,0x04, + 0xe7,0xb4,0x92,0x70,0xc0,0xe0,0x63,0x28,0x40,0x0a,0x53,0x6c,0x84, + 0xf2,0x4b,0x29,0x03,0x00,0x97,0xa4,0xd1,0xc9,0x84,0x95,0xdd,0x3e, + 0x48,0x83,0x95,0x01,0x4e,0x54,0x98,0xf2,0x9c,0xfa,0x36,0xd3,0x82, + 0x70,0x06,0x09,0x3c,0x9a,0xca,0x69,0x91,0x01,0x5d,0xe7,0x6b,0x3a, + 0xac,0x6c,0xa8,0x0f,0x48,0xd7,0x6e,0xe5,0x24,0x70,0x70,0x37,0x1e, + 0xaa,0xb9,0x65,0x24,0x8c,0x53,0x7e,0xd0,0x0a,0xe4,0x8c,0xbc,0x6a, + 0x8a,0xca,0x01,0x6d,0xe4,0x12,0x5c,0xa6,0x4f,0x0a,0x08,0xed,0xd3, + 0x39,0xfa,0x01,0xec,0xfc,0xff,0x00,0x0f,0xf8,0x26,0xc2,0xce,0xc8, + 0xec,0xca,0x3e,0x66,0xd8,0xdb,0xc1,0xc8,0x62,0x88,0x0b,0x64,0x16, + 0x39,0x55,0x4c,0x6f,0x29,0xc0,0x6d,0xca,0x0f,0x15,0x2c,0x17,0xc8, + 0x18,0x79,0xd1,0x48,0xdc,0x4d,0x1a,0xb8,0x03,0x7f,0x96,0xab,0xf3, + 0xab,0xba,0xae,0xe2,0x77,0x10,0x17,0x04,0x2f,0x23,0xb0,0x22,0xb1, + 0xc3,0x23,0xb2,0x18,0x76,0x65,0x08,0x94,0xa1,0xdd,0xbb,0xca,0x23, + 0xe6,0x09,0x9e,0x09,0xc1,0x2c,0x06,0x31,0xd8,0x9e,0x69,0x3e,0xd2, + 0xa0,0x82,0x85,0xdb,0x2a,0x37,0x1c,0x80,0x59,0x9d,0xf2,0xce,0x17, + 0xfb,0xc5,0x76,0x73,0x80,0x30,0x38,0x03,0x9a,0x08,0x94,0x3c,0xaf, + 0xa6,0x8e,0xcf,0x4d,0xfb,0x3f,0x9e,0xa7,0x4f,0x6c,0xd1,0x46,0x37, + 0xaa,0xb2,0xa4,0x61,0x59,0x03,0x86,0xdf,0xb1,0xb2,0x0a,0xb0,0xc0, + 0x3c,0xc8,0x70,0x08,0xe3,0xb9,0xf9,0x73,0x4f,0x9a,0x35,0x8e,0x2d, + 0xdb,0x5e,0x45,0x63,0xfb,0xc5,0x01,0xb9,0x55,0x6d,0xdb,0xb0,0x01, + 0x3b,0x55,0xb9,0x24,0x92,0x46,0x4e,0x06,0x6b,0x22,0x2b,0xc8,0xd9, + 0x12,0x24,0x94,0xbb,0x45,0x1d,0xc9,0x91,0x0a,0x15,0x91,0xd4,0xb2, + 0x13,0x86,0xc9,0x0c,0xea,0x4f,0x3b,0x78,0xf2,0xf0,0x40,0xde,0x08, + 0xad,0x2b,0x5d,0x49,0x91,0x58,0x11,0xe6,0xe1,0x55,0x0a,0xb0,0x0e, + 0xa1,0x42,0xc6,0xe5,0xca,0x92,0x53,0x78,0x3c,0x97,0xc7,0x4e,0xa0, + 0xd0,0x63,0x2a,0x4e,0xcf,0xe2,0xfb,0xbc,0xd7,0x51,0x63,0x79,0x04, + 0x11,0x26,0xd6,0x1b,0x03,0x8c,0x8e,0x0e,0xd4,0x62,0xd1,0x46,0x41, + 0x03,0x0c,0x10,0x91,0xb7,0xa8,0xc8,0xeb,0x9a,0x9d,0x9c,0xe0,0xb0, + 0x70,0xb2,0xe0,0xac,0x71,0xe3,0x21,0xf7,0xf9,0x65,0xdc,0x39,0xc0, + 0x2e,0x4b,0x60,0x33,0x8c,0x11,0x91,0xc1,0xa5,0x47,0x8b,0x04,0xf9, + 0x88,0x8e,0xb2,0xb9,0x8c,0xf9,0x92,0x0c,0x80,0xdc,0x31,0x80,0x65, + 0x1d,0xfc,0xb6,0x1b,0xdc,0xca,0x31,0xc6,0x0c,0x98,0xc5,0x13,0x44, + 0xcb,0x1c,0x6c,0x8c,0xa7,0xcb,0x67,0x60,0xea,0xdb,0xe3,0x08,0x8b, + 0xe6,0x36,0x41,0xe5,0x70,0xe4,0x2f,0xcd,0xd4,0x1c,0x0c,0xe4,0x95, + 0x9e,0x78,0xff,0x00,0x34,0x7e,0xf4,0x73,0x4a,0x2e,0x3b,0xa7,0x6d, + 0xae,0xd3,0x4b,0x52,0x48,0xee,0xb6,0xab,0x1f,0xbd,0xb5,0x97,0x2d, + 0xb4,0xa8,0x2d,0xe6,0xfc,0xfb,0x46,0xdd,0xae,0x4a,0x90,0xab,0xc8, + 0x8d,0xb6,0x96,0xdd,0xd0,0x16,0x24,0xc0,0x90,0x3f,0x79,0x84,0xb9, + 0x0c,0x36,0x96,0xc0,0x55,0x2d,0x1a,0x9c,0x90,0x09,0xdf,0x95,0x18, + 0x20,0x1e,0x73,0x8d,0xd9,0x15,0x9e,0x5a,0x44,0x56,0x66,0xce,0xe0, + 0x10,0x64,0x70,0x7e,0x67,0x0b,0x9f,0x2c,0x00,0x32,0x8a,0xcc,0xcf, + 0xce,0x02,0x02,0xc3,0x71,0xe2,0xa5,0x6b,0xc4,0x42,0x58,0x27,0xca, + 0xaf,0xe4,0x90,0xab,0xb9,0xb7,0x22,0x65,0x03,0x3b,0x36,0xd6,0x01, + 0xd8,0x64,0x2a,0x87,0x7e,0x30,0x47,0x5a,0xab,0x94,0xa9,0xdd,0x26, + 0x9b,0x7b,0x3d,0x17,0x72,0xcb,0xbc,0x9c,0x64,0x3a,0x12,0x77,0xbc, + 0x64,0xee,0x30,0xb0,0x20,0x84,0x75,0x42,0x55,0xa3,0xce,0x30,0x5b, + 0xe4,0x55,0x6c,0x67,0x76,0x45,0x0b,0x30,0x66,0x49,0x5f,0xe6,0x76, + 0x91,0x24,0x93,0x07,0x08,0xe4,0x1f,0x2e,0x40,0x54,0x1e,0x40,0x25, + 0x9c,0x74,0x20,0x85,0xc9,0xc5,0x57,0x92,0xe6,0x27,0x57,0x9b,0x77, + 0x9a,0x44,0x42,0x39,0x53,0x96,0xf2,0xbe,0x45,0xdc,0xdb,0x70,0xad, + 0xb8,0xba,0xef,0x18,0x66,0xec,0x08,0xce,0x6a,0xbc,0xb2,0xee,0x8d, + 0x4f,0x0a,0x4c,0x6e,0x49,0x54,0x62,0xbf,0xea,0x95,0x48,0x00,0xb7, + 0xde,0xdc,0xa0,0x96,0xf9,0x79,0xdd,0xc6,0x28,0x29,0x53,0x69,0xad, + 0xf7,0xbe,0xdd,0x9f,0xfc,0x37,0xf4,0xcd,0x06,0x97,0xf7,0x9b,0xd5, + 0xd5,0x73,0xb3,0xca,0x1c,0xef,0xca,0xef,0xc7,0xef,0x49,0x3b,0x63, + 0xe8,0x70,0x46,0x54,0xe4,0xaf,0x7a,0x47,0x9d,0x19,0x4a,0x06,0x67, + 0xe1,0x92,0x26,0xdc,0x33,0xb5,0x56,0x42,0x9b,0xb2,0x01,0xf3,0x24, + 0xff,0x00,0x57,0x93,0xb8,0x32,0x33,0xab,0x71,0xb4,0xd6,0x31,0x9f, + 0x7b,0x6d,0x40,0x9e,0x64,0x6f,0x24,0xaa,0xa7,0x2b,0xe6,0x2b,0x28, + 0x0a,0xa7,0x96,0x23,0xe6,0x24,0x81,0xc1,0xc6,0x01,0x5c,0x73,0x4e, + 0x49,0xf8,0xf3,0x1b,0x9f,0x9c,0x94,0x0a,0x88,0x13,0xcb,0x78,0x98, + 0xa1,0xdc,0x09,0x25,0x83,0x7c,0xd8,0x23,0x38,0x3c,0xfc,0xd9,0x23, + 0x48,0xca,0xd1,0x7d,0xef,0xb7,0xdc,0x6d,0xec,0xfc,0xff,0x00,0x02, + 0xc7,0xda,0x65,0x6d,0xe5,0x01,0x31,0x6e,0x80,0x97,0x21,0x77,0x12, + 0xbb,0xb7,0x7c,0xc7,0x0c,0x07,0x50,0x07,0x53,0x82,0x31,0x9e,0x29, + 0x1a,0x6f,0x34,0xef,0x03,0xef,0xb7,0xdf,0x49,0x1f,0x08,0xb1,0xa6, + 0xc2,0xa1,0x03,0x85,0x66,0x65,0xc1,0x42,0xc3,0xa0,0x20,0xf6,0xc5, + 0x44,0x2d,0x12,0x6d,0x20,0xb2,0xab,0x48,0xa2,0x45,0x51,0xb8,0x93, + 0x20,0x12,0xb3,0xe5,0xbe,0x42,0xeb,0x96,0x3c,0x1c,0xed,0x05,0x76, + 0xe0,0x93,0x0c,0x92,0xb6,0x73,0x10,0xd8,0x16,0x32,0x58,0x0e,0x81, + 0xbc,0xcc,0x80,0x01,0x19,0xfb,0xa3,0xd3,0x3f,0x78,0x11,0x8c,0x51, + 0x7e,0x7d,0x36,0xeb,0xdf,0xd3,0xb7,0x71,0xa8,0x59,0xde,0xf7,0xf9, + 0x17,0x1a,0x70,0xad,0x98,0xd4,0x2c,0x4b,0x1b,0x86,0x2c,0x54,0xbc, + 0x68,0x22,0x60,0xa3,0x70,0x23,0x77,0x07,0x8d,0xab,0x91,0x9e,0x7a, + 0x66,0x87,0x91,0x9f,0xc8,0x6d,0xf9,0xc8,0x89,0x48,0xcf,0x28,0x54, + 0x88,0xd8,0x39,0x62,0x06,0x7a,0xbe,0x47,0x03,0xbf,0x4a,0xa5,0x3b, + 0xe2,0x29,0xdb,0x76,0x5b,0xc9,0x84,0x02,0x46,0xee,0x64,0x6c,0x12, + 0x70,0x39,0xc2,0x81,0x8c,0x8f,0x97,0xa1,0xc8,0x60,0x69,0x81,0xd9, + 0x5a,0x10,0x42,0x95,0x32,0xe3,0x24,0x60,0x37,0xca,0x49,0x03,0x00, + 0x92,0x09,0x1e,0x84,0x7a,0x12,0x49,0x15,0xa2,0xd3,0x4e,0xc5,0xea, + 0xf6,0x45,0xb1,0x2b,0x20,0x29,0x20,0x56,0x8d,0xae,0x03,0x83,0xb5, + 0x76,0x95,0x45,0x58,0xe3,0x6c,0xe4,0x83,0xcc,0x4a,0xdb,0xba,0x48, + 0xc5,0x89,0x3c,0xe6,0xad,0x42,0xf2,0x79,0xaa,0xd1,0x7d,0xcf,0x31, + 0x64,0xcb,0x92,0x78,0x55,0x55,0xc7,0x23,0xa1,0x24,0x82,0xb9,0xc7, + 0x03,0xb8,0xe7,0x32,0x19,0xd4,0x46,0xe8,0xe0,0x86,0x78,0xc7,0x96, + 0x30,0x78,0x43,0x28,0x72,0xa8,0x0f,0x40,0x0e,0x43,0x0e,0x72,0x3e, + 0x50,0x45,0x3c,0xb1,0x2e,0x89,0xbd,0xf0,0x82,0x56,0x60,0x30,0x42, + 0x3f,0x99,0xc0,0x07,0xf8,0x55,0x80,0xc8,0x3f,0x39,0x1b,0x95,0x06, + 0x4b,0x66,0x80,0x69,0xec,0xd3,0xd7,0x4d,0x8d,0x26,0x93,0x7a,0xe0, + 0xb8,0x57,0x45,0x2c,0xec,0x39,0x5c,0xef,0x2a,0x99,0xc1,0xc6,0xfc, + 0x0c,0x0d,0xd8,0xe0,0x93,0xe9,0x55,0xe5,0xb8,0xf3,0x10,0xed,0x00, + 0x8d,0xac,0x48,0xe7,0x3b,0xfe,0x60,0xcd,0xf2,0xe7,0xae,0x39,0xc1, + 0xc0,0xfc,0x79,0xa7,0x15,0xc8,0xd8,0x93,0x92,0xc8,0x4a,0x10,0x54, + 0x7d,0xc6,0x22,0x45,0xc4,0x8c,0xa0,0x1d,0xbf,0x33,0x1c,0xa8,0xdd, + 0xf7,0x47,0x72,0x40,0x24,0x3e,0x53,0xaa,0x02,0x58,0x45,0x23,0x29, + 0xc9,0x00,0xc9,0x8c,0xee,0xf9,0x47,0x00,0x1f,0xbd,0x82,0x7a,0x1d, + 0xbc,0x62,0x81,0x28,0xdb,0x44,0x9f,0xea,0x59,0x8a,0x56,0x68,0xa4, + 0x66,0x60,0x5c,0x4b,0x1a,0xa0,0x24,0x28,0xdb,0xb4,0x3e,0x77,0x1e, + 0x38,0x1b,0x78,0x18,0x24,0xb6,0x30,0x46,0x05,0x24,0x97,0x00,0xa5, + 0xc8,0x93,0x01,0xcc,0x77,0x45,0xc0,0x61,0xb9,0x49,0x8f,0x24,0x13, + 0x83,0xf2,0xe0,0xed,0xc1,0xc7,0xca,0x76,0x9e,0x30,0x6b,0x38,0x5c, + 0x2a,0x31,0x0d,0xca,0x84,0x04,0x60,0x67,0x3b,0x01,0x4e,0x87,0x82, + 0x43,0x00,0x8a,0x73,0xc7,0x4e,0x47,0xcd,0x50,0xcb,0x29,0x63,0x2e, + 0xe7,0x0a,0x4c,0x73,0x24,0x89,0xd9,0x89,0x8b,0x2c,0xc3,0x03,0x9f, + 0x97,0x04,0xb1,0xe7,0x3c,0x0c,0xf6,0xa5,0xbc,0x7f,0xeb,0xee,0x1f, + 0xbf,0xfd,0x04,0xd1,0xbf,0xf9,0xff,0x00,0xc0,0xb8,0xe3,0x49,0xce, + 0x77,0x6a,0x5f,0x0c,0xde,0x8b,0xb5,0x39,0x7f,0x95,0xcf,0xf4,0xeb, + 0xfd,0x89,0x0e,0x7f,0x63,0x5f,0xd9,0x30,0x80,0x00,0x3f,0xb3,0x37, + 0xc0,0x42,0x00,0xe8,0x33,0xf0,0x9f,0xc2,0x1d,0x3d,0xab,0xe9,0xfa, + 0xf9,0x77,0xf6,0x20,0x39,0xfd,0x8c,0x7f,0x64,0x83,0xeb,0xfb,0x31, + 0xfc,0x01,0x3f,0x9f,0xc2,0x5f,0x08,0x57,0xd4,0x55,0xff,0x00,0x3a, + 0xbc,0x59,0xff,0x00,0x25,0x4f,0x12,0x7f,0xd8,0xfb,0x37,0xff,0x00, + 0xd5,0x86,0x20,0xff,0x00,0x67,0x78,0x6b,0xfe,0x49,0xdc,0x87,0xfe, + 0xc4,0xd9,0x67,0xfe,0xa1,0x51,0x0a,0x28,0xa2,0xbe,0x7c,0xf6,0xc2, + 0x8a,0x28,0xa0,0x02,0x8a,0x28,0xa0,0x02,0x8a,0x28,0xa0,0x0f,0xf2, + 0x5d,0x12,0x72,0xc5,0x50,0xfe,0xe8,0x22,0xec,0xce,0x41,0x01,0xfe, + 0x62,0x0e,0x41,0x0c,0xec,0x41,0x2d,0xfc,0x43,0x2a,0x48,0xa9,0x04, + 0x9e,0x6b,0x05,0x66,0x6d,0x81,0xdf,0xb1,0x2a,0x39,0x00,0x80,0x41, + 0xc7,0x2c,0x3b,0xf2,0xdb,0x49,0x19,0x0b,0xc5,0x1f,0x34,0x3c,0x8c, + 0xcf,0xc6,0x20,0x46,0x5e,0x00,0x6c,0xa3,0x60,0x64,0x75,0xc6,0x5d, + 0x1d,0xb9,0xe1,0x4e,0xe3,0xd3,0x35,0x34,0x12,0xa3,0x1f,0x94,0x80, + 0x16,0x49,0x90,0x7c,0xc3,0x71,0x3b,0x53,0x9e,0x07,0xf7,0x98,0x95, + 0x3f,0x88,0xea,0x6b,0xfe,0x90,0x0f,0xf1,0x7e,0xa6,0x1e,0x4d,0x36, + 0xe3,0xac,0x62,0xda,0xf7,0x97,0x6b,0xf7,0x34,0x25,0x78,0xd9,0x56, + 0x38,0xd5,0x03,0x6f,0xdd,0x1e,0xe7,0xca,0xef,0xc6,0xf5,0xfb,0xc0, + 0x95,0x2c,0x33,0x96,0x6f,0x5e,0xa7,0x00,0x54,0x5e,0x68,0x90,0xcc, + 0x10,0x61,0x46,0xf7,0x8b,0x9f,0x94,0xa2,0xca,0xdb,0x90,0x1c,0x02, + 0x08,0xdc,0xcc,0x09,0xc9,0x60,0xc3,0xe6,0xf9,0x45,0x54,0xb8,0x95, + 0x1c,0x13,0x96,0x27,0x01,0xb6,0x8c,0x73,0x14,0x83,0x87,0xc8,0x00, + 0x91,0x9e,0x31,0xc9,0xfa,0x0a,0x44,0x73,0x1a,0xaa,0xb3,0x88,0xda, + 0x23,0xb3,0x0d,0xcb,0x3c,0x46,0x2f,0x31,0x80,0x54,0xee,0x58,0x6d, + 0x55,0xe0,0xe4,0x0e,0x79,0x6a,0x0c,0xe9,0xd2,0x6e,0x1e,0xcd,0xad, + 0x5b,0xbd,0xae,0xbc,0x9e,0xf7,0xb6,0xcb,0xee,0x2d,0xa4,0x99,0x52, + 0xc4,0x9c,0x2e,0xc5,0xcb,0x0f,0x98,0xe5,0x18,0x82,0x46,0x4e,0x40, + 0x1d,0x7d,0x79,0xfe,0xf0,0xc2,0xbd,0xc2,0x09,0x67,0xde,0x8d,0xb9, + 0x77,0xee,0x21,0xf1,0xfb,0xb5,0x8d,0x49,0xc0,0xe4,0x10,0xdb,0xd5, + 0xf1,0xd4,0x95,0xc0,0xe2,0xb3,0x85,0xd9,0xf2,0xb6,0x95,0x50,0xcb, + 0x76,0xa6,0x20,0x72,0x37,0x00,0xcc,0x8a,0x24,0x6c,0x60,0xa0,0x0e, + 0xaf,0x83,0x9c,0xec,0x20,0xfc,0xa7,0x15,0x2d,0xbb,0x34,0x85,0xe0, + 0x90,0xa8,0x2c,0xaf,0x6a,0x5c,0x36,0xe0,0x92,0x6e,0x40,0x59,0x5c, + 0x63,0x77,0x1f,0x36,0x7b,0x28,0xe9,0xc5,0x05,0x3c,0x2f,0x2e,0xb2, + 0x4e,0xda,0x2f,0x8a,0x3f,0xa6,0xbf,0xa7,0xe0,0x5c,0x49,0x9d,0xe4, + 0x08,0xd9,0x52,0x81,0x48,0x38,0x00,0x2b,0x6c,0x19,0xc7,0x51,0x93, + 0x18,0x07,0xb8,0xf9,0x8f,0x1e,0x8c,0x13,0xf9,0x61,0x64,0x61,0x98, + 0xf6,0xb3,0xab,0xa9,0x00,0x3a,0xa9,0x1f,0x27,0x3f,0x36,0x47,0x72, + 0x39,0xea,0x01,0x22,0xa2,0x25,0x62,0x8a,0x39,0x08,0x2c,0x92,0x4f, + 0x70,0xa0,0x67,0x0a,0xd8,0x0a,0x98,0x2c,0x3e,0x61,0x80,0xbb,0x94, + 0x1e,0x0e,0x78,0xe0,0xe2,0xb2,0xa7,0xbf,0xb1,0x8b,0xcb,0x49,0xee, + 0x90,0x2c,0x08,0xe9,0x14,0x67,0x39,0x64,0x2e,0xaa,0xd1,0x92,0x07, + 0xde,0x62,0x72,0x1b,0xa0,0x03,0x69,0xac,0xe5,0x56,0x9c,0x7e,0x29, + 0xc5,0x6b,0x6d,0xfa,0xf6,0xd0,0x74,0xf0,0x6e,0xa3,0x7c,0x90,0x9c, + 0xac,0xae,0xf9,0x75,0xb2,0xd6,0xd7,0xb6,0xd7,0x6a,0xc7,0x4c,0xd7, + 0x0a,0xf1,0xc6,0xc9,0x98,0xe4,0x75,0x04,0x01,0xb9,0x48,0x42,0x4f, + 0x95,0x09,0x1b,0xbe,0xe0,0x5d,0xa1,0x89,0xc8,0x3b,0x8e,0x46,0x05, + 0x42,0x92,0x21,0x90,0x6e,0xcb,0xec,0x78,0x63,0x6c,0x02,0x71,0xb2, + 0x3c,0xb7,0x46,0x00,0x92,0xc0,0x9e,0x33,0xd8,0xf0,0x48,0x15,0xe7, + 0xd7,0xde,0x36,0xb4,0x54,0x7f,0xb1,0xc5,0x23,0xc9,0x20,0xf2,0xd1, + 0xa4,0x55,0x58,0xd0,0x1d,0x80,0x10,0xc0,0xb6,0x1b,0xe5,0x20,0x1e, + 0x8a,0x80,0x90,0x32,0x2b,0x95,0xd4,0xfc,0x65,0x7d,0x34,0xac,0xa1, + 0xfe,0xcf,0x04,0x61,0xbc,0xb1,0x1b,0x08,0xdb,0x78,0x8c,0x3c,0x88, + 0x64,0xc0,0x3e,0x62,0xe0,0x17,0x01,0x48,0x65,0x75,0x07,0xa6,0x47, + 0x9f,0x57,0x35,0xc3,0x41,0xc7,0x92,0x4e,0xac,0x6d,0x79,0x7b,0x38, + 0xdf,0x67,0xf0,0xfb,0xce,0x3a,0xb5,0xb6,0x96,0xee,0x7b,0x38,0x5e, + 0x17,0xc7,0x62,0xaf,0x78,0xc7,0x0e,0xac,0xda,0x95,0x49,0x49,0xdd, + 0x25,0x77,0x68,0xa8,0xdf,0xfa,0xf2,0x3d,0x81,0xb5,0xbb,0x0b,0x39, + 0x1a,0x49,0x2f,0x22,0x1b,0x09,0x1b,0x77,0x16,0x6d,0xce,0x58,0x84, + 0xda,0xbb,0x8a,0x93,0xc6,0x06,0x00,0xce,0x47,0xbd,0x73,0xf2,0x78, + 0xf2,0xda,0x23,0xb2,0xd1,0x1d,0x99,0x92,0x55,0x73,0xfe,0xaf,0x84, + 0x0a,0x0e,0x7e,0x63,0xc1,0x3b,0x86,0x08,0xe8,0x07,0x4c,0xe0,0x78, + 0xd4,0xf7,0x72,0x1f,0x36,0x43,0x22,0xbc,0xa6,0x65,0x81,0x00,0x6d, + 0xbf,0x33,0x8c,0x96,0xda,0xa7,0xe6,0x27,0x91,0xbc,0x1c,0xa9,0x3c, + 0x9e,0x71,0x54,0x1e,0xe9,0x94,0xdc,0x88,0x98,0x0d,0xcf,0x0f,0x92, + 0x37,0x6d,0x0a,0xb3,0x95,0x12,0x10,0x4e,0x48,0x5d,0xae,0x8c,0x48, + 0xc6,0x39,0x2c,0x09,0x61,0x8f,0x36,0xae,0x6d,0x89,0x9b,0x94,0x69, + 0xfb,0x3a,0x70,0x97,0xc2,0xfd,0xef,0x6a,0x95,0xef,0xfe,0x1b,0xe9, + 0x67,0xba,0x49,0xbd,0xd9,0xf4,0x58,0x4e,0x10,0xc2,0xc5,0x2f,0x6b, + 0x29,0xd6,0x7a,0x26,0xa4,0xa3,0x18,0x4a,0x6e,0xca,0xd6,0xbb,0x97, + 0x2a,0x6d,0x49,0x37,0x6d,0x9d,0xd2,0x3d,0x9a,0x2f,0x88,0x97,0xf1, + 0x9f,0xf8,0xf2,0x59,0x13,0xcd,0xe7,0x05,0xbe,0xe1,0x3f,0x21,0xc8, + 0x73,0xc2,0x39,0x27,0x1d,0x36,0x92,0x33,0x8e,0x96,0xa3,0xf8,0x9f, + 0x3c,0x68,0xcb,0x2e,0x9f,0xe5,0x9f,0x35,0x64,0x91,0x54,0xbf,0x93, + 0xb1,0x58,0x82,0xac,0xa4,0xb1,0xcb,0x29,0x3b,0x8b,0x31,0x51,0x95, + 0x60,0xbc,0x01,0x5e,0x13,0xf6,0x99,0x61,0x31,0xa2,0xa9,0x6d,0xc3, + 0x7b,0x85,0xdc,0x5b,0x2d,0x23,0xc7,0x1a,0x3a,0xa9,0x2b,0xcb,0x27, + 0x25,0x49,0x52,0x08,0xcf,0x43,0x56,0xde,0xed,0xde,0x37,0x62,0xe8, + 0xa1,0x93,0x28,0x09,0x0c,0x46,0xd6,0xf9,0x97,0x03,0xa8,0x20,0x30, + 0x19,0x1c,0xae,0x3a,0xe4,0x0a,0xe6,0x78,0xbc,0x4b,0x6f,0x9a,0xb4, + 0xe5,0x7e,0x8e,0xd6,0xfc,0x12,0x3a,0xa7,0xc2,0x39,0x6b,0x76,0x9e, + 0x0e,0x92,0xbd,0xfd,0xe4,0xdd,0xdf,0x2e,0x96,0xf8,0x9a,0xdd,0x3d, + 0xd2,0xec,0xaf,0xa1,0xf4,0x95,0xbf,0xc4,0x7d,0x19,0xae,0x63,0x5b, + 0xb8,0xae,0x2c,0xe2,0xde,0xe1,0xdc,0xac,0x93,0x42,0xc4,0xc0,0x7c, + 0xa5,0x31,0x9d,0xb2,0x79,0x52,0xcc,0xcc,0x85,0xb7,0x10,0x13,0x6e, + 0x17,0x6a,0xd6,0xcd,0xb6,0xa9,0xa5,0x6a,0x31,0xef,0xd2,0xae,0x95, + 0x9a,0x1b,0x88,0xd7,0xc8,0x2e,0x8b,0x2b,0xcf,0xe6,0x31,0x0b,0x1a, + 0xb9,0x02,0x46,0x75,0xc2,0xc6,0xcd,0xf3,0x61,0x55,0x0a,0x92,0x73, + 0x5f,0x32,0x43,0x79,0x11,0x88,0x3e,0x4c,0x8c,0x63,0x4d,0xae,0xe4, + 0x92,0x15,0x00,0x6e,0x78,0xdb,0x9c,0x65,0xa4,0xc9,0x25,0x02,0x83, + 0xd4,0x1a,0xb5,0x69,0xab,0x7d,0x92,0xed,0x27,0xb4,0x77,0x82,0x6b, + 0x69,0xa2,0x74,0x98,0x1d,0xa1,0x7c,0xb9,0x7c,0xd5,0x71,0x19,0x05, + 0x4f,0x7c,0x02,0x38,0xdd,0x91,0xc6,0x49,0xea,0x86,0x6d,0x52,0x97, + 0x22,0x94,0x5c,0xd5,0x92,0x97,0xca,0xd7,0x6b,0x5e,0xba,0xe9,0xf8, + 0x9e,0x5e,0x27,0x84,0x70,0x95,0x1c,0xa3,0x87,0xf6,0xb4,0x65,0x1b, + 0xf2,0x3b,0xc5,0xd3,0x6e,0xf6,0xb4,0x93,0x4a,0x71,0x8a,0xfb,0x36, + 0x6f,0xb6,0x9b,0x9f,0x4f,0xb4,0x8f,0x6a,0x25,0x12,0xc7,0x21,0xf2, + 0xa3,0x0b,0x21,0x2e,0x0e,0x19,0x99,0x70,0x92,0x60,0x63,0x71,0xc3, + 0x2e,0xdc,0xe4,0x67,0xae,0x79,0x0f,0x2d,0x1b,0xbb,0x2c,0x60,0x9c, + 0xc4,0xac,0xb9,0x62,0xa9,0xc8,0x2a,0xee,0x81,0x89,0xe5,0xba,0x95, + 0xc9,0x03,0xcb,0x18,0xc7,0x43,0xe1,0x76,0x1f,0x10,0x75,0x08,0xa5, + 0x5f,0x3a,0x66,0x90,0x92,0x93,0x5c,0x2c,0xe8,0x9b,0xe4,0x21,0xdd, + 0x9e,0x02,0xcc,0x4f,0x0e,0xd8,0x2c,0x5c,0x06,0x56,0x39,0x1b,0x7f, + 0x87,0xaf,0x87,0xc7,0x30,0xcd,0x1b,0x24,0xf6,0xea,0xd3,0x94,0x50, + 0x08,0x28,0xa9,0xcb,0x06,0x27,0x29,0x96,0x18,0x05,0x88,0x08,0x47, + 0x45,0x03,0x19,0xcd,0x7a,0x74,0xb3,0x3a,0x15,0x39,0xb9,0xb9,0xa0, + 0xd5,0xac,0xad,0x7b,0xdf,0xbb,0xbf,0x7e,0xb6,0xdb,0xa1,0xf2,0xd8, + 0xae,0x1c,0xcc,0xb0,0xce,0x29,0xc2,0x13,0x52,0x57,0xe6,0x8c,0x9d, + 0x96,0xb6,0xb3,0x56,0xbb,0xef,0xe6,0x8f,0x49,0x10,0x24,0x8a,0x4f, + 0xcc,0x33,0x22,0x88,0x4e,0xcc,0x13,0xb0,0xa2,0x39,0x38,0x3b,0xb2, + 0xca,0xc3,0x1f,0x32,0xe4,0x9d,0xbd,0xaa,0xb1,0x86,0x5f,0x9d,0x15, + 0xc2,0xb2,0xe4,0x79,0x60,0x8d,0xc9,0xb4,0x31,0x52,0xe3,0x69,0x19, + 0x73,0x90,0xac,0x0f,0xcd,0x9c,0x01,0x8c,0x1a,0xf3,0x29,0x3c,0x65, + 0x7a,0xd1,0xf9,0x30,0x37,0x96,0xa3,0x78,0x56,0x0f,0xe6,0x33,0x07, + 0x3f,0x20,0x65,0x38,0x0a,0x51,0x80,0x75,0x2d,0x96,0x52,0xc4,0x02, + 0x37,0x64,0x62,0xdc,0x6b,0x5a,0xc4,0xcf,0x34,0xef,0x79,0x2a,0x38, + 0x91,0x10,0xe1,0xbe,0xfe,0x57,0x05,0x95,0x54,0x0c,0xac,0x40,0x0c, + 0x28,0x5f,0x94,0xfc,0xca,0x70,0x06,0x15,0x4c,0xc6,0x31,0x95,0xa0, + 0xb9,0xb4,0xdb,0xbe,0xf7,0xd7,0x4d,0x88,0xa5,0xc3,0xd8,0xd9,0xeb, + 0x56,0xa5,0x3a,0x49,0xeb,0x15,0xf1,0x3b,0x77,0x76,0xd7,0x5b,0x6d, + 0x6f,0x53,0xd7,0x25,0xb9,0x89,0x30,0x92,0x4c,0xb1,0x07,0x62,0xe3, + 0x73,0xa8,0x75,0x44,0x50,0x72,0xd9,0x61,0xb8,0x16,0xf5,0xdd,0xf2, + 0xe4,0x75,0xe0,0x42,0xda,0x8d,0xa9,0x85,0xd1,0x6e,0xa3,0x67,0x42, + 0xcd,0x26,0xe9,0x23,0x18,0x43,0x90,0x77,0x36,0xe5,0xce,0x54,0x81, + 0xd4,0x1e,0x83,0x39,0x00,0x1f,0x15,0xbc,0xbc,0xbc,0xb9,0x75,0xfd, + 0xf3,0x92,0xab,0x2e,0x37,0xe1,0x80,0x58,0x97,0x27,0x24,0xf2,0x37, + 0x02,0xc1,0x41,0xe4,0xee,0xda,0x78,0x6e,0x6b,0xf9,0xaf,0xe6,0xb7, + 0xcb,0xb7,0xe5,0x8b,0x7e,0xe2,0x0a,0xc6,0xce,0x04,0xc3,0x24,0x72, + 0xc7,0x6f,0x1f,0x36,0x40,0xc0,0xc6,0x00,0x15,0x70,0xcc,0x36,0x7c, + 0xa9,0x79,0x36,0xba,0xf7,0xb3,0x76,0xdb,0xa3,0x7a,0x79,0xe8,0x7a, + 0x14,0xf8,0x65,0x38,0x27,0x3c,0x54,0xb9,0xb5,0xbf,0x2d,0x35,0xca, + 0xb5,0xd2,0xd7,0x77,0xda,0xdf,0x33,0xdc,0xa0,0xbf,0xb3,0x89,0xe4, + 0xdb,0x2a,0x4c,0x04,0x60,0x98,0x83,0xae,0xe5,0x0f,0x85,0x72,0xcc, + 0xd8,0xdf,0xe4,0xb1,0x50,0x76,0x7d,0xd2,0xc0,0x64,0xed,0x26,0x92, + 0x29,0x49,0x49,0x01,0x72,0xf8,0x0f,0x3a,0xed,0xcf,0xee,0x91,0x3a, + 0x65,0x83,0x60,0x03,0xbb,0x77,0xcb,0x9c,0x0c,0x8c,0x13,0xcd,0x78, + 0x8a,0x4a,0xe6,0x49,0x53,0x7a,0x90,0x72,0xc1,0xb1,0x22,0x96,0x48, + 0x94,0x31,0x0a,0xc7,0x28,0x72,0x19,0x41,0x50,0xbf,0x77,0xe6,0x1f, + 0x3a,0x0a,0x9e,0xd7,0x5d,0xbb,0x80,0x67,0xcc,0x31,0xc6,0xa5,0x86, + 0x15,0xce,0xd7,0x12,0x00,0x84,0x71,0x8c,0x85,0x01,0x59,0x48,0xe4, + 0x75,0xe3,0x8a,0xd3,0xfb,0x49,0x76,0x8f,0xf5,0xd7,0x57,0xfd,0x76, + 0xef,0x53,0xe1,0xa7,0x08,0xde,0x96,0x23,0x9d,0xbe,0x92,0x8d,0xbb, + 0xdb,0xcb,0x7b,0xaf,0xd5,0xec,0x7b,0x2e,0xc9,0x59,0x50,0x86,0x56, + 0x04,0x90,0xb8,0x27,0x24,0x20,0x57,0x2b,0xb8,0xe1,0xb1,0x92,0x36, + 0xf4,0xe9,0x86,0xf9,0xaa,0x67,0xb9,0x47,0xf3,0x0b,0x3e,0xd6,0x92, + 0x42,0xa4,0xe0,0x8d,0xb8,0xc3,0x9e,0x83,0x6f,0x27,0x92,0x3f,0x2e, + 0x2b,0xce,0x60,0xf1,0x5d,0xf2,0x44,0x44,0x9e,0x54,0xb1,0x65,0xa6, + 0x45,0x32,0x34,0x4c,0xaf,0x33,0x47,0xe6,0x22,0x16,0x5d,0xc7,0x2b, + 0x1f,0xa8,0x55,0xdc,0xc4,0x82,0x54,0x9a,0xd9,0xb3,0xf1,0x3d,0xb3, + 0xbc,0x49,0x24,0x2f,0xba,0x5b,0xa7,0x0e,0xac,0xdb,0x95,0x56,0x54, + 0xdf,0xb5,0x50,0xaa,0xb6,0x54,0x2e,0xd0,0x4a,0x8e,0x39,0xe9,0xd7, + 0x68,0x66,0x14,0x5b,0xb3,0x6a,0xee,0xc9,0x6f,0x6b,0xbd,0x36,0xeb, + 0xad,0xbf,0x1f,0x97,0x9d,0x5f,0x26,0xc5,0xd3,0xbc,0x94,0x39,0xe1, + 0x4d,0x37,0xcf,0x09,0x26,0x9d,0xb5,0xd9,0xda,0x51,0xd1,0x75,0x47, + 0x5a,0x02,0x46,0x91,0x1f,0x95,0x80,0x8c,0xe0,0x83,0x9c,0xe4,0x0c, + 0x9c,0x7c,0xbc,0x64,0x67,0x91,0xef,0xf5,0x68,0x72,0x5d,0x9b,0xcc, + 0x27,0x2f,0xb8,0x0e,0x32,0x32,0x07,0x20,0x7b,0xe0,0x0e,0xe7,0x80, + 0x47,0x7c,0xe4,0x7f,0x6a,0xdb,0x4f,0x1e,0xc8,0xb6,0x96,0x0e,0x80, + 0x87,0x2d,0xbc,0x2e,0xec,0x81,0xc1,0x1b,0x94,0x8c,0x86,0x27,0xa7, + 0xd3,0xa4,0xcb,0x21,0x8f,0xcc,0x45,0x4c,0xbb,0xc8,0x71,0xf7,0x82, + 0xec,0xc0,0x23,0x0c,0xdc,0x0e,0xbf,0x2f,0x52,0x31,0xc7,0x6a,0xe9, + 0x85,0x6a,0x72,0xfb,0x5d,0x6d,0xb3,0x57,0xfb,0xd6,0xe7,0x9f,0x2c, + 0x35,0x58,0x35,0x29,0xc7,0x93,0xa2,0x8c,0x9c,0x6e,0xfc,0xd6,0xba, + 0x2e,0xbf,0xf0,0xec,0xb3,0x1c,0x66,0x58,0x59,0xc3,0x63,0x66,0xd5, + 0x39,0xc6,0x4e,0x65,0xdd,0x91,0xfd,0xe3,0x83,0xd0,0x10,0x33,0xd4, + 0x74,0x34,0xe9,0xc9,0x58,0xae,0x02,0x7c,0xce,0x16,0x52,0x65,0x1b, + 0x77,0x32,0x94,0x95,0x9d,0x86,0x7d,0x06,0x49,0x1d,0x30,0xb8,0x07, + 0x8c,0x18,0x96,0x42,0xbf,0xba,0x46,0x05,0x25,0x0a,0x1b,0xaa,0xe1, + 0xa3,0x19,0xc8,0x3d,0x8e,0x4f,0x27,0xbd,0x46,0xee,0xcb,0x0c,0xcd, + 0x8e,0x44,0x73,0xfc,0xa5,0xbb,0x84,0x07,0xa0,0xe7,0xb7,0x6e,0x9b, + 0xbd,0xc8,0xa6,0xe6,0xd5,0xad,0x6b,0x7b,0x4c,0x3f,0xfe,0xa4,0xd1, + 0xeb,0xfd,0x5b,0x70,0xa7,0x17,0xed,0x39,0x5a,0xd7,0x96,0x7d,0x74, + 0xfe,0x1c,0xbe,0x4f,0xfa,0xea,0x7f,0xa7,0xbf,0xec,0x3c,0x7f,0xe3, + 0x0b,0xff,0x00,0x64,0x7c,0x73,0xff,0x00,0x18,0xc5,0xf0,0x03,0xff, + 0x00,0x55,0x27,0x83,0xeb,0xea,0x3a,0xf9,0x6f,0xf6,0x1d,0x24,0xfe, + 0xc5,0xdf,0xb2,0x31,0x3d,0x7f,0xe1,0x98,0x7f,0x67,0xff,0x00,0x5f, + 0xfa,0x24,0x7e,0x0f,0xf5,0xe7,0xaf,0xae,0x0d,0x7d,0x49,0x5f,0xf3, + 0xb7,0xc5,0x8f,0xfe,0x32,0x9e,0x24,0xff,0x00,0xb1,0xfe,0x71,0xff, + 0x00,0xab,0x0c,0x41,0xfe,0xc8,0xf0,0xdf,0xfc,0x93,0xd9,0x17,0xfd, + 0x89,0xf2,0xdf,0xfd,0x43,0xa2,0x14,0x51,0x45,0x7c,0xf9,0xed,0x05, + 0x14,0x51,0x40,0x05,0x14,0x51,0x40,0x05,0x14,0x51,0x40,0x1f,0xe4, + 0x8b,0xe5,0x32,0x17,0x0a,0x48,0xc2,0xc8,0x70,0xf9,0x01,0xa2,0x2a, + 0x33,0xbc,0x75,0x55,0x07,0x04,0x1e,0x72,0xd8,0xe7,0x38,0x15,0x58, + 0x46,0xde,0x51,0x30,0x95,0x2f,0x1b,0x86,0x5c,0x16,0x3f,0x7a,0x44, + 0x5d,0xb9,0xff,0x00,0x6b,0x1d,0xc6,0x47,0x4e,0x6a,0xeb,0xba,0xa1, + 0x9d,0x25,0x93,0x61,0x95,0x25,0x04,0x1c,0x05,0xf2,0xcc,0x6b,0x24, + 0x4b,0xe6,0xe5,0x99,0x87,0x04,0xed,0x70,0xad,0x9c,0x1e,0x40,0x20, + 0xe0,0xea,0x1a,0xee,0x9d,0xa7,0x35,0xd7,0x97,0x32,0xb8,0x48,0xe1, + 0x8d,0xc2,0xa8,0x52,0x3e,0x44,0x05,0xb3,0x9f,0xbd,0xbb,0x73,0x8c, + 0x80,0xd8,0xdd,0x81,0x92,0x0d,0x7f,0xd1,0xa5,0x4c,0x5c,0x20,0xd3, + 0x72,0xf6,0x71,0x5a,0xc9,0x4b,0x96,0xed,0x2d,0x5d,0xb5,0x7a,0xb5, + 0x74,0xb5,0x5a,0x9f,0xe3,0xad,0x0a,0x15,0xea,0xcf,0xd9,0xc2,0x2e, + 0xa4,0xe4,0xd5,0x92,0x8c,0xed,0x76,0xec,0xae,0xd2,0x4b,0x56,0xfa, + 0xe8,0xba,0xb3,0xa0,0x29,0x9d,0xd0,0x85,0x65,0x92,0x25,0x5c,0xb3, + 0x82,0x10,0xf0,0x47,0xcd,0x8e,0x81,0x06,0xe1,0x95,0xc8,0x67,0xe7, + 0x18,0xa4,0x68,0x0c,0xec,0x66,0x52,0x14,0x28,0x69,0x0a,0x38,0x23, + 0xe5,0x89,0x06,0xed,0xa5,0x73,0x8f,0x9d,0x3c,0xb1,0xb9,0xb1,0x96, + 0xce,0x70,0x2b,0xcf,0xdb,0xc7,0x91,0x40,0x5c,0xc7,0x0b,0x48,0x5a, + 0x47,0x40,0xcc,0x18,0x8f,0x28,0xa2,0xaa,0x10,0x70,0x46,0xfc,0x28, + 0x04,0x8e,0x55,0x48,0xe9,0xb9,0x8d,0x71,0xb7,0x1e,0x2e,0xd4,0x67, + 0x96,0x46,0x4b,0xa3,0x6f,0x15,0xcf,0x9b,0x19,0x44,0x55,0x2a,0x55, + 0xd4,0x06,0x56,0x62,0xd9,0x01,0x86,0x59,0x8e,0x3e,0x6c,0xf0,0x73, + 0xd3,0x8e,0xb6,0x6f,0x46,0x9d,0xe5,0x0f,0xde,0x45,0x2f,0x85,0x34, + 0x9b,0x6d,0xdb,0x7d,0x76,0xba,0x7f,0x9d,0xb7,0x3d,0x9c,0x3f,0x0d, + 0xe6,0x18,0x89,0xc9,0xce,0x9a,0xa0,0xa2,0x92,0x52,0x9b,0xd1,0xbd, + 0x13,0x56,0x5f,0x7e,0x9d,0xd7,0x4b,0x9e,0xbd,0x75,0xa9,0xd9,0xc1, + 0x1a,0xdc,0xdc,0xcc,0x83,0xca,0x76,0xdb,0x0e,0x1c,0xbc,0xb8,0xc3, + 0x3a,0xa6,0x09,0xc1,0x55,0x24,0x8d,0xd8,0x04,0x75,0xf5,0xac,0x67, + 0xf1,0xbd,0xb0,0x86,0x48,0x52,0x23,0x24,0xbe,0x71,0x31,0x10,0xb1, + 0xe0,0x8d,0xa7,0x73,0x89,0x17,0xe6,0x1b,0x99,0x33,0x86,0x25,0x98, + 0x72,0xa0,0x0e,0x0f,0x8b,0xc9,0xa9,0x2b,0x02,0x7e,0xd1,0x24,0xe8, + 0x8e,0x37,0x16,0x76,0x21,0x08,0x21,0x50,0x2f,0x18,0x19,0x23,0x93, + 0xce,0x54,0x15,0x3d,0x49,0x09,0x35,0xc2,0x4b,0xbd,0x92,0x58,0x55, + 0xb2,0xcb,0xd3,0x61,0xf9,0x47,0x25,0x70,0x70,0x03,0x14,0x61,0xd3, + 0x27,0x72,0xf6,0x15,0xe3,0x56,0xce,0x31,0x35,0x6e,0x97,0xee,0xa2, + 0xdd,0xd2,0x5c,0xb2,0x92,0xd2,0xd6,0xbf,0x2a,0x4d,0x75,0xee,0xbf, + 0x13,0xdf,0xa1,0xc2,0x78,0x68,0xa5,0x1c,0x53,0xa9,0x5a,0xed,0x37, + 0x28,0xde,0x9c,0x55,0x9e,0xdc,0x9a,0xb7,0xa7,0x5e,0x67,0xd7,0x4d, + 0x4e,0xff,0x00,0x54,0xf1,0xa5,0xc4,0xcb,0x1a,0x46,0xad,0x15,0xb2, + 0xb9,0x92,0x28,0xd5,0xd8,0xa2,0xcc,0x23,0xc6,0xee,0x39,0x56,0x6c, + 0x0e,0xa4,0x85,0x01,0x4f,0xcc,0x5c,0xaa,0xf2,0xef,0x7c,0xea,0xe2, + 0x4b,0x9b,0x81,0x24,0x9b,0x96,0x78,0xcb,0xb3,0x72,0x18,0x1f,0x39, + 0x58,0xab,0x6d,0x46,0xca,0x72,0x71,0xf7,0x89,0x5c,0x03,0x81,0x5c, + 0xcc,0xf7,0x2c,0x91,0x06,0x56,0x2c,0x41,0xb6,0x66,0xf9,0x8b,0x2e, + 0x0f,0xca,0x55,0x78,0x5d,0xc3,0x62,0xa0,0xe7,0xa3,0x02,0x01,0xeb, + 0x4a,0x27,0x79,0xd7,0x04,0x21,0x56,0x8d,0x7d,0xc8,0x46,0x63,0xcf, + 0x0b,0xf7,0xf7,0x64,0x9e,0x72,0x58,0x1e,0x07,0x06,0xb9,0x25,0x88, + 0x53,0xd6,0x72,0x9b,0x77,0xbb,0x7a,0xea,0xde,0xef,0x47,0xf3,0xd9, + 0x6e,0x7d,0x16,0x1f,0x29,0xc2,0x61,0x68,0xa8,0xd1,0xa5,0x18,0x2b, + 0xda,0xfc,0xa9,0xc9,0xa5,0xb7,0x3c,0x9d,0xdb,0x7d,0xf5,0x69,0xb6, + 0xfb,0x9b,0x5f,0x69,0x12,0xb1,0x00,0xa2,0xa3,0x6e,0x25,0x92,0x42, + 0x54,0x2c,0x71,0xa3,0xb6,0x0b,0x72,0xb8,0x21,0x55,0x8f,0x55,0xf3, + 0x00,0x38,0x1b,0x85,0x54,0x49,0x58,0x38,0x0e,0xc5,0xf6,0xfd,0xa1, + 0xc0,0xdc,0x1b,0xcc,0x90,0x36,0xd9,0x36,0xf7,0xfb,0x82,0x12,0x32, + 0x0a,0x9d,0x8b,0xcf,0x35,0x55,0x1a,0x37,0x8d,0x50,0x99,0x03,0xb4, + 0x8a,0x0b,0xb1,0xdc,0xab,0x13,0x20,0x59,0x80,0x07,0x04,0x1d,0xcb, + 0x9c,0x72,0x09,0xda,0x3a,0x8c,0x53,0x4c,0xdf,0x65,0x19,0x59,0x0b, + 0xf9,0x8a,0xc2,0x29,0x76,0x28,0x64,0x49,0x1f,0x24,0x28,0xc9,0x2b, + 0xe6,0x84,0x5c,0xe4,0x82,0x46,0xe1,0x81,0x93,0x58,0x4a,0xab,0x76, + 0xb6,0x9e,0x91,0x8a,0xfc,0x97,0xa9,0xd3,0x08,0x5a,0xfc,0xab,0x64, + 0xd5,0xb5,0x6e,0xd6,0x7a,0x2b,0xdf,0xcf,0xcf,0xd0,0xb4,0x09,0x79, + 0x53,0xe4,0xfd,0xcb,0x31,0x8a,0x77,0x39,0x53,0x99,0xda,0x20,0x5c, + 0x02,0x78,0x64,0x38,0x42,0xd8,0xda,0x30,0x4f,0xd5,0x97,0xf2,0x18, + 0xed,0x5b,0xcb,0x45,0x56,0xde,0x91,0xef,0x07,0x38,0xcb,0xa0,0xc3, + 0xb0,0xe3,0xee,0x00,0x41,0x6c,0x1d,0xa4,0x76,0xc1,0xa6,0x8b,0xc8, + 0x59,0xbf,0x76,0x48,0x62,0xb0,0xac,0x4f,0x20,0x1f,0x2b,0x79,0x84, + 0x48,0xeb,0xd3,0xab,0x80,0xca,0x1b,0x38,0x5d,0xc3,0x1d,0x29,0xc6, + 0x58,0x64,0x90,0xc6,0xea,0x8a,0x1a,0x62,0xf9,0x6d,0xcc,0x36,0x10, + 0xa4,0xb8,0x42,0x36,0x9c,0x36,0x02,0x86,0xdc,0x54,0x64,0x0c,0xa6, + 0x2a,0x79,0xe7,0x7b,0xf3,0x6b,0xf2,0xff,0x00,0x21,0xa8,0x3e,0x78, + 0x39,0x42,0x56,0x52,0x4f,0x5b,0xad,0x13,0x4d,0xf5,0xf9,0x69,0xf9, + 0x16,0x60,0xf3,0x61,0x8c,0xf9,0xaa,0x7c,0xb4,0xf2,0x9c,0x48,0x0e, + 0x59,0x4a,0x4e,0xee,0x8a,0x43,0x61,0x81,0x72,0xec,0x48,0x20,0x65, + 0x98,0x3f,0x50,0x32,0xe8,0xe7,0x8d,0x4a,0x34,0x65,0x4b,0x09,0x55, + 0xcb,0xbe,0x79,0x88,0x46,0x64,0x27,0x9c,0x00,0x80,0x0c,0x30,0x39, + 0x2a,0x79,0x19,0x02,0xa0,0x4f,0x9a,0x39,0x42,0x33,0x13,0x33,0x98, + 0xf0,0x49,0x2c,0x44,0x6d,0x99,0x9f,0x0d,0x9c,0x0c,0x90,0xac,0x32, + 0x09,0x18,0x0a,0x2a,0x15,0x71,0x28,0x00,0xed,0x2c,0xbb,0x94,0xec, + 0x04,0x0f,0x2c,0x97,0x12,0x12,0xc3,0x22,0x45,0x3b,0x15,0x30,0x39, + 0x8d,0x07,0x00,0x81,0x54,0xaa,0xcb,0xab,0x6d,0x5b,0xb2,0x09,0x43, + 0x9a,0x4d,0x74,0x4e,0x4d,0x6e,0x92,0x52,0x6d,0xaf,0xcf,0xfc,0xb4, + 0x34,0x21,0x78,0xde,0x49,0x57,0x6f,0xfa,0x95,0x0c,0x63,0x39,0xc3, + 0x31,0xe3,0x2a,0x9c,0x1f,0x2d,0xd2,0x45,0x24,0x8e,0x0b,0x83,0x8a, + 0x77,0x9c,0x51,0x42,0x02,0x43,0x18,0x00,0x50,0x63,0x52,0x43,0x8d, + 0xd1,0x90,0xc5,0xb9,0x56,0x6c,0x71,0xbb,0x2c,0x4e,0x40,0xe3,0x81, + 0x8d,0xe6,0x90,0xcc,0xee,0x58,0x73,0x0e,0x5d,0x78,0x24,0xa4,0x62, + 0x31,0xb5,0xbe,0x6f,0x93,0x72,0x3b,0x05,0xc1,0xce,0x03,0x1c,0x13, + 0x8a,0x6a,0x5c,0xc9,0xb4,0xc8,0xd9,0x72,0xf2,0x13,0x96,0xea,0x5e, + 0x38,0x84,0xa8,0x49,0xc8,0xcb,0xae,0x38,0xc0,0xc6,0x18,0xe7,0x75, + 0x69,0xed,0x69,0xbb,0x5e,0xff,0x00,0x77,0xf9,0x3e,0xa4,0xbc,0x3a, + 0x6e,0xfb,0xab,0x2d,0x35,0xb2,0x7b,0xbf,0xc5,0x75,0xf3,0x34,0x56, + 0xe1,0x5c,0xef,0x42,0xb9,0x67,0x41,0x97,0x18,0xe5,0x93,0x6c,0x84, + 0x70,0x41,0x04,0x82,0x39,0x23,0x8c,0xf6,0x04,0x89,0x16,0xf2,0x65, + 0x85,0x1c,0x10,0x4c,0xb2,0x8f,0xbb,0x95,0x74,0x53,0x80,0x11,0x56, + 0x3e,0x01,0x27,0xa1,0x60,0x18,0x9c,0x75,0xc5,0x61,0xb3,0xb7,0x10, + 0x20,0x62,0x59,0x62,0xdb,0x83,0x8e,0x46,0x18,0x64,0xff,0x00,0x7c, + 0x87,0x25,0xba,0x00,0x00,0x51,0xef,0x64,0x4b,0x85,0x46,0x05,0xc0, + 0x66,0x66,0xda,0xb8,0x58,0xb2,0x00,0xc9,0x00,0x9d,0xc7,0x6b,0x63, + 0x0c,0x3f,0x88,0x7d,0xde,0x49,0xa7,0xed,0x69,0xbb,0x5e,0xfa,0x6d, + 0xa7,0xfc,0x1e,0x9f,0xf0,0xc3,0x95,0x08,0xd9,0xa6,0x94,0x96,0xfe, + 0xf4,0x53,0x6a,0xdd,0x56,0x9b,0xfc,0xed,0x74,0x74,0x71,0x6b,0x72, + 0xc4,0x8a,0x22,0xdc,0x51,0xc3,0x2b,0x6d,0xdc,0x5f,0x6a,0x48,0x06, + 0xf6,0x1b,0x46,0x54,0xb9,0x50,0xc4,0x37,0x72,0x47,0x43,0x5a,0x51, + 0xf8,0x9d,0x04,0xeb,0xb9,0x3c,0xbd,0xae,0xa0,0xab,0x1d,0xc3,0x79, + 0x07,0x24,0x13,0x92,0x0b,0x67,0xd7,0x04,0x00,0x47,0x23,0x9e,0x36, + 0x3d,0xe0,0x04,0x46,0x2a,0xd9,0x79,0x15,0xc7,0x40,0x9e,0x67,0x98, + 0x14,0x64,0x64,0x17,0x65,0xc8,0xe3,0x92,0x14,0x90,0xbd,0x2a,0xfa, + 0xf9,0x0b,0xfb,0xbb,0x98,0x99,0xa4,0x20,0x31,0x65,0x31,0xba,0xb5, + 0xc4,0x1c,0x48,0xa3,0x25,0x76,0xb3,0x65,0x8b,0x8f,0x9b,0xae,0x53, + 0x35,0xb5,0x3a,0xae,0xdc,0xd0,0xe8,0xf6,0x76,0xde,0xc7,0x1d,0x5c, + 0x0e,0x12,0x51,0x9d,0xe9,0xde,0xf7,0xf7,0x95,0xf9,0xf7,0xbd,0xd2, + 0xbf,0x2f,0x45,0xdb,0xf0,0x3d,0x02,0x3b,0xaf,0x38,0x16,0x0c,0xa7, + 0xc9,0x2e,0xde,0x62,0xe1,0xb0,0xcc,0x44,0xa9,0xb8,0x64,0x8e,0x43, + 0x15,0x2b,0xd0,0xf1,0xbb,0x00,0x0a,0x24,0x91,0x9d,0x4c,0xb2,0xcd, + 0xb6,0x47,0x09,0x27,0x96,0x81,0x19,0x37,0x49,0x2b,0x06,0xf7,0x01, + 0x54,0x60,0x8e,0x30,0x0e,0xdf,0xba,0x05,0x70,0x3b,0x67,0xf2,0xe5, + 0xb6,0xb6,0x99,0xa3,0x6c,0x47,0x23,0x96,0x90,0x6d,0x2e,0x59,0x95, + 0x91,0xb6,0xfc,0xd8,0x56,0x1c,0xb0,0x1c,0xa8,0x35,0x3c,0x1a,0xab, + 0xc4,0xe1,0x3e,0x47,0x41,0x24,0xe1,0xc7,0xde,0x25,0x63,0x0a,0xd9, + 0x50,0x0e,0x42,0x82,0x77,0x1c,0x1c,0x10,0x3b,0x72,0x2b,0xaa,0x38, + 0x97,0x65,0xce,0x9a,0xd1,0xeb,0x16,0xde,0xbd,0x34,0xd3,0xef,0xe9, + 0xd7,0x43,0xca,0x9e,0x53,0x25,0x1e,0x6a,0x53,0x4d,0x26,0xda,0x8c, + 0xa2,0xd4,0xb9,0x56,0xba,0xbb,0xca,0x3a,0xfa,0x2d,0xfa,0x75,0xee, + 0x92,0x5c,0x2e,0x7c,0xd2,0x4b,0xb3,0xbe,0x19,0x0f,0x44,0x3b,0x03, + 0xee,0x50,0x76,0xaa,0x0c,0x1c,0x02,0x14,0xf4,0x20,0xe0,0x90,0xc6, + 0x30,0x87,0x44,0x01,0x98,0x05,0x20,0x7f,0x10,0x2f,0x94,0x55,0x20, + 0x76,0xf9,0xb0,0x39,0x1c,0x1e,0xbc,0x60,0x9c,0x74,0xd4,0x2d,0xe7, + 0xf2,0xcc,0xd3,0x34,0x6e,0xd1,0x60,0x2c,0x5c,0xe1,0xc3,0xb2,0xc6, + 0xae,0xa4,0x7c,0xbb,0x98,0x87,0x24,0x13,0x90,0xa3,0x76,0x33,0x82, + 0xc9,0x5a,0x48,0x99,0x5c,0x30,0xd9,0xf2,0x48,0x0a,0x85,0x0b,0xbd, + 0xbc,0xb5,0x6d,0xf8,0xc9,0x21,0xb6,0x9f,0x93,0x70,0x21,0xc9,0x63, + 0xc0,0xc5,0x6f,0x1a,0xb1,0x7b,0x49,0x74,0xdd,0xbf,0xc7,0x5d,0x1f, + 0xa5,0xfb,0x1c,0xb1,0xc0,0xd4,0x6d,0xdd,0xb5,0xda,0xeb,0x4e,0xbd, + 0x6c,0xb4,0xfe,0xba,0x9b,0xeb,0x22,0x34,0x92,0x46,0xa5,0xd1,0x63, + 0x28,0x8c,0x54,0xb0,0x29,0x23,0xc6,0xe7,0x2a,0x37,0x1c,0x6f,0xdb, + 0x81,0x82,0x4b,0x0c,0xe3,0xa5,0x4c,0xb7,0x31,0xc9,0x16,0x2d,0xdd, + 0xcc,0xa2,0x40,0xe1,0x98,0x92,0x43,0x49,0xf2,0xc9,0xf3,0x3f,0xcf, + 0xf2,0x20,0x0c,0x06,0x7e,0x65,0x24,0x7d,0xec,0x0a,0xc1,0x8e,0xe7, + 0x6c,0xdb,0x9c,0x80,0xcc,0x58,0xcb,0x87,0x0c,0x04,0x91,0x46,0xcc, + 0xac,0x0a,0x92,0x3e,0x60,0xc4,0x2f,0x4c,0x16,0x1c,0xf3,0x48,0x6e, + 0x22,0x1b,0x50,0x13,0xc4,0x9e,0x60,0x4e,0x3c,0xcc,0x38,0x0b,0xb0, + 0x3e,0x39,0x7c,0x36,0xf0,0x47,0x40,0x46,0x3b,0xd5,0x5f,0xcd,0x7f, + 0xe4,0xe4,0x4f,0x03,0x6f,0x85,0xc9,0xa5,0xab,0x8e,0xbc,0xad,0xad, + 0xee,0xb4,0xe6,0xbd,0xbd,0x3e,0xed,0x7a,0xcb,0x7b,0x96,0x94,0xec, + 0x79,0xc4,0x6c,0x2d,0x94,0xb6,0x63,0x11,0x14,0xb8,0x83,0x6c,0x61, + 0x5e,0x51,0xf3,0x15,0x62,0x42,0x96,0x23,0x38,0x04,0x63,0x69,0x06, + 0xb5,0x2c,0xf5,0x7b,0xf5,0x63,0x06,0xf4,0x9d,0xf6,0xa9,0x1e,0x60, + 0x19,0xf9,0xd7,0x72,0x84,0x0f,0xc6,0xf0,0x00,0x47,0x1b,0x97,0x6f, + 0x99,0xc3,0xae,0x09,0x3c,0x52,0x5d,0x2c,0x3e,0x6c,0xaf,0xb8,0x93, + 0xf2,0x48,0xc4,0xf1,0xb9,0x98,0x0f,0x98,0x60,0x62,0x37,0x00,0x67, + 0x01,0xb7,0x05,0x00,0xe0,0x1f,0x9a,0x75,0xba,0xdf,0x34,0x73,0x44, + 0x14,0x7d,0x9f,0xcc,0x88,0x47,0x86,0x2a,0xbb,0xd4,0x2b,0x3e,0x09, + 0x19,0x6c,0x90,0x53,0x27,0xaf,0x27,0x1d,0x05,0xa9,0xc9,0x7c,0x32, + 0xb6,0xba,0x69,0x2d,0xbe,0x77,0xdf,0xf2,0xd9,0x9c,0x15,0xb0,0x31, + 0xa8,0x9f,0x3d,0x2a,0x6e,0x29,0x5e,0xee,0x17,0x49,0xad,0x79,0x6e, + 0x95,0xec,0xda,0x4b,0xe2,0x56,0xbd,0xf5,0xd8,0xf4,0x0b,0x2f,0x13, + 0xc5,0x21,0x6f,0x3d,0x36,0xca,0x8c,0xad,0x24,0x8a,0x73,0x00,0x8f, + 0x00,0x05,0x5c,0x63,0xb2,0x90,0x18,0x80,0x49,0xec,0x7a,0xd6,0xb8, + 0xd4,0xad,0x24,0x82,0xe1,0xcc,0xaa,0x9b,0x61,0x9c,0xec,0x24,0x99, + 0x14,0xcd,0x1a,0x95,0xe0,0x71,0xcf,0x23,0x83,0xc6,0x09,0x38,0xaf, + 0x32,0x37,0xbe,0x5a,0xa1,0xca,0x29,0xf3,0xde,0x49,0xc0,0x5c,0x80, + 0xdc,0xb1,0x0a,0x41,0xc6,0x30,0x59,0x59,0x5f,0x38,0xc1,0x65,0x1d, + 0x29,0xff,0x00,0x68,0x12,0xc5,0x3a,0x87,0x58,0xc8,0x5b,0xb0,0x42, + 0x92,0x8c,0x0c,0x91,0x46,0xe5,0x47,0x41,0xf2,0x90,0x4f,0xfb,0x24, + 0xe0,0x6e,0x56,0xae,0xa8,0x63,0x2a,0x42,0x3e,0xf7,0xbc,0xa3,0xcb, + 0x2e,0xbf,0x66,0x71,0x9c,0x1e,0xda,0xda,0x49,0x3b,0x5f,0x5e,0x5d, + 0x6f,0xb1,0xc1,0xfd,0x85,0x86,0xa9,0x57,0xda,0x42,0x33,0xa7,0xcc, + 0xe3,0xd6,0xf1,0x5c,0xd6,0x83,0x49,0x28,0xd9,0x5e,0xed,0x69,0xd3, + 0x5d,0x37,0x3f,0xd5,0x5f,0xf6,0x1b,0x20,0xfe,0xc5,0x9f,0xb2,0x21, + 0x53,0xb9,0x4f,0xec,0xc1,0xfb,0x3f,0x95,0x23,0xba,0x9f,0x84,0x7e, + 0x0f,0x20,0xfe,0x23,0x9a,0xfa,0x96,0xbe,0x4f,0xfd,0x83,0x98,0xb7, + 0xec,0x43,0xfb,0x1d,0xb6,0x77,0x6e,0xfd,0x96,0x3f,0x67,0x73,0xbb, + 0x1d,0x73,0xf0,0x77,0xc1,0x67,0x3d,0x4f,0x5c,0xe7,0x9a,0xfa,0xc2, + 0xbf,0xe7,0xd7,0x8a,0xaf,0xfe,0xb3,0xf1,0x1b,0x7d,0x73,0xdc,0xdd, + 0xfd,0xf8,0xfc,0x43,0xfd,0x4f,0xf5,0x73,0x87,0xe1,0xec,0xf2,0x1c, + 0x96,0x1b,0xf2,0x65,0x39,0x74,0x7e,0xec,0x25,0x14,0x14,0x51,0x45, + 0x78,0x27,0xae,0x14,0x51,0x45,0x00,0x14,0x51,0x45,0x00,0x14,0x51, + 0x45,0x00,0x7f,0x8d,0xd4,0xde,0x2e,0xd5,0xa6,0x33,0x2c,0x97,0x77, + 0x4b,0x23,0x6d,0x0e,0x0c,0x83,0x96,0x09,0xb0,0xbe,0xe0,0x36,0x47, + 0xfb,0xb6,0x6c,0xfc,0xae,0x7b,0x8e,0x06,0x2b,0x29,0xf5,0x4b,0xa6, + 0x58,0xc4,0xcc,0x5d,0xe5,0x0c,0x56,0x52,0xc3,0xcc,0xc2,0x3e,0x36, + 0x1e,0x33,0xc9,0x19,0xf9,0xc9,0x3c,0x02,0x48,0xe0,0x55,0x25,0x92, + 0x30,0x1d,0x91,0x8a,0xc8,0xc8,0x71,0xbb,0xb0,0x0a,0xaa,0xca,0x47, + 0x21,0x72,0x77,0x73,0x8e,0x83,0xea,0x6a,0xa1,0x05,0xc2,0xb4,0x7b, + 0x98,0x2b,0xc8,0x0b,0x67,0x3f,0x20,0x50,0xdc,0x77,0xeb,0xfc,0x7d, + 0x06,0x79,0xe7,0xaf,0xfb,0xf0,0xaa,0x4a,0x5b,0xb7,0xf3,0x6d,0xff, + 0x00,0x57,0x3f,0xce,0x0a,0x58,0x3c,0x24,0x14,0xb9,0x30,0xf4,0xe9, + 0xbd,0x35,0x50,0x4b,0x54,0xad,0xbd,0xbe,0xeb,0x6f,0xd2,0xf6,0x34, + 0x85,0xe5,0xd2,0xa6,0xff,0x00,0x38,0x64,0x32,0x61,0x09,0xf9,0x8a, + 0xb1,0x66,0xf9,0xb0,0x01,0xc0,0x53,0x92,0x0f,0xb7,0x1d,0xcd,0x34, + 0x99,0xb1,0x0b,0x9c,0xb9,0x46,0x1b,0x72,0x38,0xe2,0x36,0x0c,0x18, + 0x0c,0x67,0x71,0x53,0xb4,0x1e,0x4f,0x5e,0x33,0x81,0x07,0xcc,0x30, + 0x8c,0xa4,0x0f,0x91,0x4f,0x72,0x43,0x2b,0x1e,0x0e,0x32,0x3b,0x0e, + 0x4f,0x6e,0x38,0xa6,0xa9,0x92,0x34,0x07,0x6b,0x00,0xbb,0x25,0x27, + 0x38,0xce,0x64,0x21,0x3a,0x86,0x1c,0x9c,0xf3,0xc1,0x27,0xb7,0xa9, + 0x7d,0x2d,0xd3,0xb7,0x43,0xa6,0x14,0xa3,0x1f,0xb3,0x15,0xef,0x26, + 0xad,0x15,0xda,0xdb,0xad,0xdb,0xbf,0x77,0xd9,0xdf,0x52,0xd2,0xe1, + 0x63,0x92,0x10,0xb9,0x0e,0x0c,0x91,0xca,0xbd,0x38,0x1c,0xe3,0x9e, + 0x48,0x27,0x61,0x24,0x60,0x9d,0xc7,0x8d,0xa0,0xd3,0x23,0x91,0x77, + 0xc6,0xd8,0xfe,0xe9,0xe4,0x63,0x3e,0x5a,0x9d,0xca,0x49,0x27,0x9e, + 0x99,0x1e,0x9c,0xe7,0xb1,0xad,0x96,0xfd,0xe0,0x76,0x70,0xca,0x92, + 0x70,0xdd,0x72,0xd2,0x0e,0x9b,0x4f,0x1b,0xb2,0x33,0x93,0x8c,0x9c, + 0x52,0xf9,0x9c,0x42,0xd9,0x40,0xd1,0xe5,0xb0,0x31,0xb8,0xe1,0x80, + 0x2a,0xca,0x7b,0x05,0xf9,0xb8,0xc6,0x72,0x46,0x70,0x05,0x06,0xbf, + 0x25,0xaf,0xe3,0xd8,0x91,0xd9,0xdf,0x70,0x21,0xf6,0x21,0x95,0x86, + 0x3e,0x50,0x15,0x30,0x14,0x0c,0xe4,0x60,0x38,0x27,0x18,0xc8,0x24, + 0xe3,0xa9,0xa4,0x32,0xbe,0x47,0x96,0x0f,0xcc,0x15,0x42,0x9f,0x93, + 0x69,0x0b,0xdb,0x18,0xcf,0x42,0x0b,0x63,0xdf,0x1c,0xf1,0x0c,0xd7, + 0x46,0x22,0xa7,0x69,0x0a,0x3c,0xcd,0xce,0xaa,0x32,0xc2,0x56,0x05, + 0x54,0x81,0xcb,0x21,0x1c,0x06,0xe9,0xc6,0x07,0x43,0x52,0x9f,0xf5, + 0x9b,0xd7,0x38,0x93,0xee,0x80,0x5b,0x86,0x30,0x9f,0x94,0x71,0xc3, + 0x16,0x70,0x78,0x19,0x18,0x3d,0xf9,0xa0,0xa7,0x4d,0xc6,0x29,0xb8, + 0x25,0x19,0x6b,0x17,0x65,0x67,0x7d,0x76,0xf4,0x6a,0xfd,0xfc,0x8b, + 0x0a,0xe5,0x4b,0xe5,0x9c,0x01,0x95,0x01,0x98,0x60,0x99,0x01,0xf9, + 0x41,0x1d,0x94,0x82,0x41,0xf5,0x20,0xf3,0xd6,0x99,0x1b,0x06,0x30, + 0x46,0xcc,0x41,0x31,0xa1,0x19,0x5c,0x82,0xde,0x63,0x05,0x03,0x95, + 0xdc,0x4e,0x71,0xdf,0x1d,0x49,0x20,0x1c,0xd4,0x8e,0x43,0xb1,0xd4, + 0x90,0x49,0xfb,0xaa,0x41,0x27,0x7a,0xab,0x01,0x86,0x00,0xe0,0x8e, + 0xa3,0xd7,0x1d,0x2a,0x17,0x2e,0x2f,0x2d,0xc8,0x0e,0x15,0x10,0x94, + 0xf4,0x63,0x8d,0xc3,0x8c,0x64,0x74,0x7c,0xb7,0x3c,0xe3,0x3f,0x7a, + 0x81,0x53,0xa4,0x9b,0x9e,0xda,0x46,0x52,0xbd,0xb7,0xe5,0x57,0xb7, + 0xab,0x7e,0x7f,0xe4,0x5e,0x52,0xfb,0xe3,0x40,0x7c,0xb9,0x3c,0xdd, + 0x83,0x77,0xcc,0x3e,0x52,0x49,0x25,0x87,0xf7,0x5c,0x1e,0x9d,0x3d, + 0x4f,0x15,0x29,0x77,0xfd,0xe0,0xdc,0x43,0x0d,0x88,0xd9,0x3c,0x02, + 0xd2,0x28,0x04,0x1f,0xf6,0x4a,0xee,0x03,0x8e,0xbd,0xc0,0xc5,0x57, + 0x2e,0xcf,0x2c,0x72,0x03,0xb8,0x2c,0x91,0x21,0xc8,0xc7,0x27,0x92, + 0x40,0x3d,0x46,0x07,0x3c,0x8c,0xf1,0xf5,0xa7,0x97,0x25,0x4b,0x20, + 0xdd,0x89,0x1c,0xc8,0xd8,0x1c,0xfe,0xf3,0x78,0xcf,0x19,0xc8,0x3c, + 0x28,0x63,0xc1,0xe9,0x40,0xac,0xb4,0xba,0x5a,0x7f,0x5d,0x7c,0xcb, + 0x30,0xdc,0xc8,0x86,0x7c,0xbb,0x48,0x4b,0x48,0x89,0xc9,0x23,0x24, + 0xee,0xde,0x48,0xc6,0x4b,0xec,0xcb,0x0e,0x30,0x4e,0x7a,0x66,0x86, + 0xbb,0x91,0xed,0xc2,0xf9,0xa1,0x51,0x1a,0x6e,0xe4,0x12,0x1a,0x3c, + 0xf4,0x18,0xc7,0x53,0x80,0x57,0xef,0x03,0xeb,0x54,0x2d,0xdc,0x67, + 0xee,0x67,0x6c,0x84,0xf3,0x9e,0x71,0xc6,0x06,0xd1,0xef,0xc7,0x1d, + 0xea,0x6b,0x70,0xad,0x2d,0xc9,0x60,0xf8,0x0f,0x6f,0x23,0xa9,0xf9, + 0x32,0x8b,0x1b,0xab,0x33,0x60,0x6e,0xc6,0xe6,0x04,0xed,0xc6,0xe0, + 0x07,0xbd,0x02,0x54,0x60,0xe5,0x26,0xe2,0xbd,0xd8,0xf3,0x68,0x92, + 0x77,0x4d,0x2b,0x7c,0xfa,0x32,0xda,0x5d,0xfc,0xa8,0xee,0x51,0x90, + 0xa2,0xa6,0x32,0x70,0x1a,0x34,0x1c,0xf0,0x3e,0xf1,0x0c,0x49,0xe3, + 0x19,0x26,0xa1,0x2d,0x22,0xb0,0xf9,0x89,0x56,0x6c,0x80,0x0e,0xf1, + 0xb5,0xa1,0xdb,0xd3,0x03,0x07,0x04,0x0f,0xa7,0x53,0xda,0x98,0x40, + 0x12,0x05,0x46,0x6d,0xbf,0x3a,0xee,0xe4,0x9f,0x9b,0x1b,0x72,0x40, + 0x04,0x9c,0x75,0x23,0xf3,0xc7,0x14,0xd7,0x93,0xe6,0x2f,0x86,0x38, + 0x88,0x1c,0x6e,0x23,0x0c,0x49,0x50,0x4e,0x07,0x3d,0x72,0x41,0xe3, + 0x18,0x1d,0x7a,0x04,0x7b,0x38,0x5e,0xf1,0xeb,0x7d,0x1e,0xb6,0x4f, + 0xcb,0xe6,0xbc,0xbf,0x02,0x46,0x90,0xa9,0x59,0x11,0xb9,0xf2,0x8b, + 0x00,0x39,0x00,0xaa,0xaa,0x73,0x93,0x9c,0x00,0x4b,0x0e,0x99,0x07, + 0x1d,0x31,0x4e,0x32,0xc8,0x00,0x24,0x92,0x63,0xb5,0x63,0x8c,0x6d, + 0xc1,0x2f,0xe5,0xb6,0x73,0x90,0x4e,0xe0,0x47,0x6c,0x82,0x58,0x60, + 0x0e,0x6b,0x96,0x4e,0x23,0xf9,0x70,0xa9,0xf2,0x83,0x92,0x37,0xba, + 0xfd,0xf3,0x9c,0xb6,0xec,0x81,0x80,0x38,0xe8,0x07,0x19,0x14,0xaa, + 0xed,0x24,0xce,0x1c,0x7c,0x9e,0x59,0x42,0x72,0x40,0xca,0xf2,0xcc, + 0xe7,0xa9,0x53,0x8c,0x81,0xfe,0x02,0x82,0xa4,0xa1,0x66,0xf9,0x62, + 0xd2,0x8b,0x7b,0x2d,0x55,0xb6,0x5f,0x7f,0x4f,0xc8,0xd7,0xb5,0x99, + 0x90,0xee,0x0c,0x49,0xf2,0xd3,0xf7,0x65,0x01,0x46,0x2c,0x49,0x6c, + 0xfa,0xed,0xc2,0xed,0xfe,0xf1,0x23,0x3c,0x55,0x93,0x2a,0xc8,0xc7, + 0x28,0x41,0x49,0x83,0x6f,0x91,0x86,0x0b,0x7f,0xa9,0xdc,0x14,0x60, + 0x13,0xb5,0x11,0xb7,0x1e,0x07,0x2d,0xcf,0x4a,0xc8,0x5b,0xb2,0x2d, + 0x5b,0x62,0x00,0xca,0xd0,0x9d,0xb8,0x3c,0x14,0x7d,0x84,0x0f,0xf6, + 0x98,0x80,0x4f,0x38,0xa9,0xee,0x24,0x72,0xb6,0xeb,0xd0,0x12,0x59, + 0xc1,0xce,0xec,0x92,0x03,0x0d,0xc3,0xb6,0x46,0x7a,0x60,0x60,0x53, + 0x52,0x92,0xd1,0x36,0x97,0x93,0x68,0xe3,0xa9,0x45,0xa9,0xd9,0x24, + 0x93,0x7c,0xb7,0x5d,0x2d,0x1b,0xde,0xcb,0x7b,0xde,0xdd,0xbc,0xcd, + 0xd5,0x91,0x1a,0x55,0x66,0x6e,0x24,0x94,0x16,0x91,0x46,0xc4,0xf2, + 0x04,0xa5,0xa4,0x53,0x8f,0x9b,0xef,0x49,0x20,0xc8,0x3c,0x20,0xc8, + 0xed,0x86,0xa1,0x48,0x0c,0xe8,0x63,0x51,0x21,0x85,0x55,0x18,0x8f, + 0xf5,0xab,0x14,0x8c,0x8f,0x19,0xe3,0xe5,0x76,0x64,0x55,0x3d,0x43, + 0x28,0x23,0x2c,0x4d,0x62,0x34,0xe5,0xbe,0xcc,0x88,0x80,0x47,0x10, + 0xb9,0x8f,0x2c,0x57,0x2b,0xfb,0xc5,0x29,0x97,0x1d,0x7e,0x62,0x09, + 0x2d,0xea,0xdd,0xb1,0x5b,0x36,0xf2,0x0d,0xb1,0x87,0x90,0x3a,0x2b, + 0x23,0x08,0x95,0x57,0x2c,0x00,0x59,0x50,0x99,0x64,0xc0,0x00,0x33, + 0x18,0xc0,0x3f,0x2e,0xe2,0x5b,0x19,0xa7,0xcf,0x3f,0xe6,0x97,0xde, + 0xff,0x00,0xcc,0xca,0xa4,0x1d,0x36,0x95,0xef,0x7b,0xdf,0xa5,0xac, + 0xed,0xdf,0xfe,0x00,0xf4,0x66,0x0c,0xe1,0x0e,0xd9,0x76,0x84,0x5c, + 0x15,0xdc,0xcd,0x27,0x95,0x84,0x00,0x8f,0x48,0xf7,0x0c,0x9c,0xe7, + 0x25,0x89,0x24,0xe6,0x78,0xe7,0x93,0x31,0x1d,0xed,0x20,0x90,0xa9, + 0x60,0x0e,0x50,0x32,0x82,0x24,0x0d,0x19,0xea,0x5e,0x41,0xe6,0x6e, + 0x5c,0x0c,0xfc,0x8b,0x80,0x71,0x59,0xee,0xe1,0x0b,0x32,0x15,0x2e, + 0xd2,0x45,0x18,0x39,0x3b,0x57,0x1f,0x3e,0x54,0xe7,0x93,0xd0,0x12, + 0xd9,0xe7,0x23,0xee,0xe2,0xa6,0x75,0x49,0xcb,0x18,0x8b,0x2b,0x45, + 0x12,0x82,0xdb,0x08,0x8c,0xc8,0x83,0xef,0x86,0x07,0x01,0x72,0x48, + 0x18,0x00,0x30,0x19,0xc6,0x41,0xab,0x85,0x47,0x16,0xdb,0xbb,0xbf, + 0x99,0x84,0xa3,0xcd,0x65,0xa5,0x97,0x95,0xcd,0x98,0xaf,0x2d,0xcc, + 0x47,0x7c,0x4b,0xe6,0xbc,0x65,0x17,0x09,0xd4,0x2a,0xef,0x20,0x15, + 0x38,0x0d,0xb4,0x91,0xbf,0xe6,0xda,0xdf,0x29,0xdc,0x47,0x16,0xad, + 0xd5,0x2e,0x16,0x29,0x63,0x2a,0x81,0xd1,0x90,0xa3,0x33,0x15,0x2f, + 0xf7,0xd6,0x75,0xcf,0x20,0x8d,0xa2,0x1c,0x1c,0x02,0x4f,0x5e,0x05, + 0x63,0x2f,0xee,0x25,0x1e,0x68,0x1c,0x15,0x2e,0x85,0x58,0x2c,0x91, + 0xc8,0xc9,0xc6,0xdc,0x2e,0x47,0x98,0xac,0xc1,0x87,0x24,0x65,0x7a, + 0xbd,0x5f,0x92,0x68,0xd9,0x37,0x42,0xc0,0x3c,0x0f,0x0e,0x14,0x49, + 0xb0,0x4a,0xed,0xc4,0xa3,0x8f,0xf9,0x66,0x5d,0x46,0xc5,0x03,0x11, + 0x79,0x6e,0x4e,0x19,0xc5,0x75,0x43,0x1b,0x2b,0xa5,0x24,0xac,0xe4, + 0x93,0x76,0x5b,0x5f,0xe7,0xd3,0x5d,0x0e,0x0a,0x94,0x2c,0xad,0x06, + 0xe2,0xe5,0x74,0xf9,0xb5,0x8f,0x2b,0x5a,0xab,0x3d,0x3a,0xab,0x37, + 0xb2,0x5a,0x1a,0x52,0x92,0xca,0x59,0x98,0x0c,0x65,0xd4,0xe3,0x8d, + 0xd1,0x46,0x77,0xab,0x2b,0x06,0xe3,0x1b,0x98,0x13,0x9c,0x9c,0xe0, + 0x76,0x15,0xde,0x3b,0xf8,0x5b,0x76,0xf1,0xb4,0xaa,0xb3,0x72,0x59, + 0x95,0x42,0xa8,0x51,0x83,0x9e,0xc2,0x3c,0x9e,0xec,0xe0,0x10,0x31, + 0x92,0xf8,0xde,0x40,0xd1,0xc8,0xcc,0x9b,0x8b,0xe0,0xa8,0xde,0x23, + 0x55,0x91,0xc1,0xdd,0xb8,0xe0,0x05,0x2a,0x01,0x66,0x3c,0xec,0xe0, + 0x86,0xc1,0xa7,0x5c,0xdc,0xb4,0x32,0xc8,0x24,0x47,0x8d,0xa4,0x47, + 0x7d,0xad,0xb9,0x4a,0xb3,0x0d,0xdb,0xc3,0x60,0xf1,0xe6,0x2f,0x2a, + 0x3e,0x43,0xb4,0x64,0xf1,0x81,0xdf,0x0a,0xd0,0x9b,0xb2,0xd5,0x37, + 0x6b,0xfb,0xbd,0xaf,0xb7,0x2f,0xea,0xbf,0x03,0x96,0x9a,0xf7,0x5d, + 0x25,0x15,0x39,0x39,0x3d,0xd2,0x6b,0x4b,0x3d,0x9f,0x45,0x6f,0x4b, + 0xf9,0x8b,0x1c,0xd7,0x0a,0x01,0x94,0x09,0x72,0x41,0x27,0x8f,0x95, + 0x8e,0x47,0xcc,0x3a,0x64,0x83,0xc7,0x1d,0x38,0xeb,0xd2,0xc0,0xbb, + 0x1e,0x4c,0xb1,0x48,0x84,0xb9,0x8a,0xe5,0xb3,0x9f,0x9b,0x2c,0x0b, + 0x6f,0x0c,0x4f,0x41,0xe5,0xaa,0x64,0xf1,0xc1,0x4e,0x39,0x27,0x2e, + 0x0b,0xc5,0x93,0xcc,0xb7,0x99,0x9b,0x74,0xee,0x4e,0xe5,0x18,0x18, + 0x40,0x92,0x12,0x3d,0x02,0xf5,0x39,0x00,0x28,0x1e,0x9d,0x65,0x0b, + 0x12,0x43,0x19,0xde,0xee,0x5a,0x1b,0xc4,0x00,0x1d,0xc4,0x97,0x32, + 0x36,0xe2,0xd9,0xe7,0x0d,0xc6,0x31,0xb1,0x41,0x6c,0x72,0x79,0xd2, + 0x4d,0x72,0xca,0xcf,0x7e,0x54,0xd5,0x92,0xd1,0xcd,0x69,0xa5,0xaf, + 0xd3,0xf0,0xeb,0xb5,0x52,0xa3,0x7a,0xf0,0x55,0x57,0x2a,0x55,0x29, + 0xb8,0xc6,0x2a,0xc9,0xae,0x6b,0xdf,0x46,0x92,0x4a,0xcd,0x35,0x6e, + 0x97,0xe8,0xcf,0xf5,0x73,0xfd,0x81,0x89,0x3f,0xb0,0xcf,0xec,0x68, + 0x4f,0x7f,0xd9,0x4b,0xf6,0x73,0x3c,0xfb,0xfc,0x1a,0xf0,0x4d,0x7d, + 0x6b,0x5f,0x24,0xfe,0xc0,0x99,0x1f,0xb0,0xc7,0xec,0x66,0x0f,0x6f, + 0xd9,0x47,0xf6,0x72,0x1f,0xf9,0x86,0x7c,0x13,0xfe,0x7b,0xd7,0xd6, + 0xd5,0xfe,0x02,0x71,0x5f,0xfc,0x95,0x1c,0x47,0xff,0x00,0x63,0xdc, + 0xdb,0xff,0x00,0x53,0xeb,0x9f,0xe9,0x86,0x4d,0xa6,0x4f,0x94,0xae, + 0xd9,0x6e,0x07,0xff,0x00,0x51,0x69,0x05,0x14,0x51,0x5e,0x01,0xe9, + 0x05,0x14,0x51,0x40,0x05,0x14,0x51,0x40,0x05,0x14,0x51,0x40,0x1f, + 0xe5,0xf9,0x1f,0xfc,0x10,0x9b,0xfe,0x0a,0xbe,0xca,0xa2,0x5f,0xd8, + 0xcf,0xc7,0x2a,0x41,0x21,0x7f,0xe2,0xb4,0xf8,0x1e,0x57,0x0e,0xec, + 0xe7,0x77,0xfc,0x5e,0x2c,0x8c,0x70,0x18,0x0c,0xf5,0xe0,0xe2,0xac, + 0xc9,0xff,0x00,0x04,0x28,0xff,0x00,0x82,0xb0,0x12,0x0a,0xfe,0xc6, + 0x9e,0x34,0xc2,0x00,0x83,0x1e,0x35,0xf8,0x1d,0xca,0xa8,0xc1,0x24, + 0x1f,0x8c,0x47,0x79,0x71,0xc3,0x12,0x33,0xc0,0xeb,0x8a,0xff,0x00, + 0x4f,0x5f,0x22,0x1f,0xf9,0xe3,0x17,0xfd,0xfb,0x4f,0xf0,0xa3,0xc8, + 0x87,0xfe,0x78,0xc5,0xff,0x00,0x7e,0xd3,0xfc,0x2b,0xfb,0x03,0xfe, + 0x27,0x47,0xc4,0xb4,0xd3,0xfe,0xc1,0xe0,0xbd,0x1a,0x7a,0xe5,0xf9, + 0xc3,0xbb,0x5f,0xf7,0x5d,0x3f,0x1a,0x7e,0x08,0xf0,0xbb,0x92,0x97, + 0xd7,0xf3,0xd5,0x67,0xa2,0xfa,0xde,0x11,0xa5,0x76,0x9f,0xfd,0x0b, + 0xd5,0xf6,0xeb,0xd3,0xaf,0x6f,0xf3,0x03,0x6f,0xf8,0x21,0x4f,0xfc, + 0x15,0x89,0x9b,0xcd,0xff,0x00,0x86,0x33,0xf1,0xba,0xbe,0x73,0x8f, + 0xf8,0x4d,0x7e,0x07,0xe3,0x0a,0xe4,0x85,0x5f,0xf8,0xbc,0x18,0xce, + 0x32,0x37,0x1e,0xa0,0xf2,0x38,0xa6,0x0f,0xf8,0x21,0x3f,0xfc,0x15, + 0x87,0x23,0x3f,0xb1,0x8f,0x8d,0xf6,0xae,0xe5,0x51,0xff,0x00,0x09, + 0xbf,0xc1,0x02,0x0a,0xba,0x92,0x4b,0x2f,0xfc,0x2e,0x20,0x09,0x5d, + 0xc0,0x2f,0x70,0xc0,0x91,0x8e,0xdf,0xe9,0xff,0x00,0xe4,0x43,0xff, + 0x00,0x3c,0x62,0xff,0x00,0xbf,0x69,0xfe,0x14,0x79,0x10,0xff,0x00, + 0xcf,0x18,0xbf,0xef,0xda,0x7f,0x85,0x68,0xfe,0x9a,0xbe,0x25,0xb4, + 0xd3,0xc8,0x78,0x2f,0x5e,0xd9,0x7e,0x71,0xe5,0xff,0x00,0x53,0xdf, + 0x2f,0xea,0xe5,0xbf,0x04,0xf8,0x5a,0xdf,0xef,0xd9,0xed,0xf5,0xff, + 0x00,0x98,0xbc,0x27,0xff,0x00,0x30,0x7e,0x2e,0xef,0xe7,0xaa,0xff, + 0x00,0x2f,0xb7,0xff,0x00,0x82,0x13,0xff,0x00,0xc1,0x59,0x59,0x5b, + 0xfe,0x30,0xc7,0xc7,0x26,0x4d,0x81,0x44,0x9f,0xf0,0x9b,0x7c,0x0e, + 0xc9,0x3b,0x81,0xcf,0xfc,0x96,0x3c,0x93,0xc7,0x56,0xfc,0x3b,0xd5, + 0x59,0x7f,0xe0,0x84,0x9f,0xf0,0x56,0x9f,0x32,0x31,0x17,0xec,0x5f, + 0xe3,0xad,0xa1,0x79,0x6f,0xf8,0x4d,0x7e,0x03,0xe0,0x1d,0x8a,0x0f, + 0x12,0x7c,0x66,0x0c,0x79,0x07,0x82,0x31,0xe9,0xbb,0x9a,0xff,0x00, + 0x50,0xef,0x22,0x1f,0xf9,0xe3,0x17,0xfd,0xfb,0x4f,0xf0,0xa3,0xc8, + 0x83,0xfe,0x78,0xc5,0xff,0x00,0x7e,0xd3,0xff,0x00,0x89,0xa9,0xff, + 0x00,0x89,0xd3,0xf1,0x2f,0x97,0x97,0xfb,0x07,0x82,0x9a,0xf3,0xcb, + 0xf3,0x87,0xd5,0xbf,0xfa,0x1e,0xae,0xff,0x00,0xd3,0xd4,0xb8,0x78, + 0x2f,0xc3,0x10,0x77,0xfa,0xe6,0x73,0xaa,0x6b,0x5c,0x46,0x0a,0x6b, + 0x55,0x6f,0x86,0xa6,0x5f,0x25,0xfd,0x3e,0x8d,0x9f,0xe5,0xe0,0x7f, + 0xe0,0x84,0x9f,0xf0,0x56,0xce,0x4b,0x7e,0xc5,0xde,0x3a,0x62,0x11, + 0x02,0xff,0x00,0xc5,0x6f,0xf0,0x0b,0x19,0x52,0xe4,0xae,0x07,0xc6, + 0x73,0xc1,0x18,0xe4,0x73,0x93,0x53,0x8f,0xf8,0x21,0x27,0xfc,0x15, + 0x9b,0xf7,0x78,0xfd,0x8c,0xbc,0x71,0x90,0xab,0x1b,0x6f,0xf1,0xaf, + 0xc0,0xe2,0x42,0x9e,0x09,0xf9,0x7e,0x31,0x6d,0x24,0x64,0x92,0x47, + 0x1e,0x9c,0x57,0xfa,0x83,0xfd,0x9e,0x0f,0xf9,0xe1,0x0f,0xfd,0xfa, + 0x4f,0xfe,0x26,0x97,0xc8,0x87,0xfe,0x78,0xc5,0xff,0x00,0x7e,0xd3, + 0xfc,0x2a,0x97,0xd3,0x57,0xc4,0xbb,0x5b,0xfb,0x03,0x82,0x57,0xf8, + 0x72,0xfc,0xe5,0x7d,0xff,0x00,0xf0,0xbc,0xca,0x9f,0x83,0x1c,0x31, + 0x3b,0x5f,0x1b,0x9c,0xab,0x3f,0xb1,0x57,0x2f,0xa7,0xe5,0x66,0xe9, + 0xe5,0xb1,0x6d,0x5a,0xf6,0x4d,0xdb,0x57,0x6b,0x1f,0xe5,0xe0,0xbf, + 0xf0,0x42,0x2f,0xf8,0x2b,0x52,0x12,0x3f,0xe1,0x8c,0xfc,0x72,0xc3, + 0xcd,0x90,0xe4,0xf8,0xdf,0xe0,0x76,0x70,0x37,0x80,0x4e,0x3e,0x32, + 0x64,0x86,0xce,0x57,0xb8,0xe9,0x81,0x53,0xa7,0xfc,0x10,0x8f,0xfe, + 0x0a,0xca,0x30,0xcd,0xfb,0x19,0x78,0xe3,0x24,0x0c,0x8f,0xf8,0x4d, + 0xbe,0x07,0xf1,0xc6,0x31,0xff,0x00,0x25,0x8c,0xf4,0xfc,0x3b,0x93, + 0x5f,0xea,0x11,0xe4,0x43,0xff,0x00,0x3c,0x62,0xff,0x00,0xbf,0x69, + 0xfe,0x14,0x79,0x10,0xff,0x00,0xcf,0x18,0xbf,0xef,0xda,0x7f,0x85, + 0x1f,0xf1,0x3a,0xbe,0x26,0x7f,0xd0,0x87,0x82,0xfe,0x59,0x7e,0x70, + 0xbf,0x2c,0xf4,0x99,0x78,0x2f,0xc3,0x12,0xdf,0x19,0x9d,0x76,0xba, + 0xc5,0x61,0x17,0xa6,0x9f,0x50,0x6a,0xfb,0x6c,0x7f,0x97,0xc2,0xff, + 0x00,0xc1,0x09,0xbf,0xe0,0xac,0xe0,0x61,0x7f,0x63,0x2f,0x1c,0x0c, + 0x10,0x47,0xfc,0x56,0xdf,0x03,0xc7,0xdd,0x04,0x0c,0xe7,0xe3,0x16, + 0x46,0x7e,0xa7,0xf2,0x3c,0xb9,0x7f,0xe0,0x84,0xbf,0xf0,0x56,0x51, + 0x1c,0xc0,0xfe,0xc6,0x9e,0x38,0x0c,0xe5,0x89,0xff,0x00,0x8a,0xd7, + 0xe0,0x7f,0xcf,0x92,0x4f,0x18,0xf8,0xc6,0x71,0xce,0x0e,0x09,0x1c, + 0x0c,0x77,0xaf,0xf5,0x05,0xf2,0x21,0xff,0x00,0x9e,0x31,0x7f,0xdf, + 0xb4,0xff,0x00,0x0a,0x3c,0x88,0x7f,0xe7,0x8c,0x5f,0xf7,0xed,0x3f, + 0xc2,0x8f,0xf8,0x9d,0x5f,0x12,0xff,0x00,0xe8,0x43,0xc1,0x7f,0xf8, + 0x41,0x9c,0xff,0x00,0xf3,0xf8,0x87,0xe0,0xa7,0x0c,0x7f,0xd0,0x6e, + 0x77,0x6b,0xa7,0xfe,0xf7,0x84,0xbe,0x8e,0xf6,0xbf,0xd4,0x3f,0x4f, + 0xc4,0xff,0x00,0x2f,0x35,0xff,0x00,0x82,0x11,0x7f,0xc1,0x59,0x81, + 0x38,0xfd,0x8c,0x7c,0x71,0xd0,0x00,0x4f,0x8d,0xbe,0x07,0x0e,0xc7, + 0x24,0xff,0x00,0xc5,0xe3,0xee,0x40,0xe0,0x0e,0x07,0x4a,0x9e,0x3f, + 0xf8,0x21,0x2f,0xfc,0x15,0x99,0x4d,0xc6,0x7f,0x63,0x3f,0x1c,0x6d, + 0x78,0x82,0xaf,0xfc,0x57,0x1f,0x04,0x39,0x21,0x17,0x80,0xbf,0xf0, + 0xb8,0x71,0x90,0x47,0x52,0x40,0x38,0xc0,0xf7,0xff,0x00,0x50,0x5f, + 0x22,0x1f,0xf9,0xe3,0x17,0xfd,0xfb,0x4f,0xf0,0xa3,0xc8,0x87,0xfe, + 0x78,0xc5,0xff,0x00,0x7e,0xd3,0xfc,0x28,0x7f,0x4d,0x5f,0x13,0x1f, + 0xfc,0xc8,0x78,0x2f,0xff,0x00,0x0d,0xf9,0xc7,0x5d,0x3f,0xe8,0x7a, + 0x54,0xbc,0x16,0xe1,0x89,0x5e,0xf8,0xec,0xef,0x54,0x97,0xfb,0xde, + 0x13,0xa5,0xbf,0xea,0x03,0x4d,0xad,0xe7,0x73,0xfc,0xbe,0xd3,0xfe, + 0x08,0x4b,0xff,0x00,0x05,0x63,0x2c,0xe5,0xff,0x00,0x63,0x2f,0x1c, + 0x92,0x40,0xda,0xc7,0xc6,0xbf,0x03,0x87,0xce,0xaa,0xc1,0x49,0xc7, + 0xc6,0x33,0x85,0x04,0x27,0x20,0x74,0xcf,0x19,0xe2,0x9f,0xff,0x00, + 0x0e,0x24,0xff,0x00,0x82,0xb0,0x08,0x81,0xff,0x00,0x86,0x32,0xf1, + 0xc7,0x9a,0x25,0x84,0x05,0x1e,0x35,0xf8,0x1c,0x54,0xc2,0xb8,0x67, + 0x07,0x3f,0x18,0x73,0xbb,0x79,0xc0,0x6e,0xe0,0x73,0xeb,0x5f,0xea, + 0x03,0xe4,0x43,0xff,0x00,0x3c,0x62,0xff,0x00,0xbf,0x69,0xfe,0x14, + 0x79,0x10,0xff,0x00,0xcf,0x18,0xbf,0xef,0xda,0x7f,0x85,0x3f,0xf8, + 0x9d,0x6f,0x13,0x3f,0xe8,0x43,0xc1,0x5d,0xbf,0xe4,0x5f,0x9c,0x7f, + 0xf3,0xf7,0xf1,0x0f,0xf8,0x82,0xbc,0x2e,0xf5,0x78,0xec,0xf3,0xd1, + 0x62,0xb0,0x76,0x76,0xff,0x00,0xb9,0x03,0xfc,0xbc,0x63,0xff,0x00, + 0x82,0x12,0x7f,0xc1,0x5a,0x93,0x63,0x7f,0xc3,0x17,0x78,0xe8,0x1c, + 0xf3,0x9f,0x1b,0xfc,0x04,0xca,0x29,0x73,0xc1,0xdb,0xf1,0x94,0xb6, + 0x02,0x9e,0x76,0x82,0x7f,0x1a,0xba,0xff,0x00,0xf0,0x42,0xaf,0xf8, + 0x2b,0x32,0x93,0xe5,0xfe,0xc6,0x3e,0x38,0x39,0xdc,0x09,0x3e,0x35, + 0xf8,0x1c,0x41,0x07,0x18,0xff,0x00,0x9a,0xc5,0xce,0x01,0x6f,0x4e, + 0xde,0xf5,0xfe,0xa0,0x3e,0x44,0x1f,0xf3,0xc6,0x2f,0xfb,0xf6,0x9f, + 0xe1,0x47,0x91,0x0f,0xfc,0xf1,0x8b,0xfe,0xfd,0xa7,0xf8,0x51,0xff, + 0x00,0x13,0xad,0xe2,0x67,0xfd,0x08,0x38,0x25,0x7a,0x65,0xd9,0xc2, + 0xfb,0xff,0x00,0xe1,0x77,0x7f,0xb9,0x79,0x15,0x3f,0x05,0xf8,0x62, + 0x6d,0x37,0x8d,0xce,0x74,0xbf,0xc3,0x5f,0x03,0x4d,0x3b,0xf7,0xf6, + 0x79,0x74,0x53,0xb6,0xda,0xa7,0xeb,0xa1,0xfe,0x5e,0x8f,0xff,0x00, + 0x04,0x28,0xff,0x00,0x82,0xb5,0xec,0x93,0x67,0xec,0x65,0xe3,0xa0, + 0xcc,0xa0,0x00,0xbe,0x35,0xf8,0x1c,0xa0,0xfe,0xf3,0x38,0xff,0x00, + 0x92,0xc7,0xc0,0xee,0x79,0xfe,0x75,0x76,0x5f,0xf8,0x21,0x5f,0xfc, + 0x15,0x95,0xca,0x13,0xfb,0x1a,0x78,0xe1,0xb6,0xb9,0xc2,0xff,0x00, + 0xc2,0x69,0xf0,0x38,0xed,0x01,0x90,0x83,0xf3,0x7c,0x61,0xee,0x01, + 0x1c,0x01,0x9c,0x7a,0x71,0x5f,0xe9,0xfd,0xe4,0x43,0xff,0x00,0x3c, + 0x62,0xff,0x00,0xbf,0x69,0xfe,0x14,0x79,0x10,0xff,0x00,0xcf,0x18, + 0xbf,0xef,0xda,0x7f,0x85,0x2f,0xf8,0x9d,0x5f,0x12,0xff,0x00,0xe8, + 0x41,0xc1,0x5f,0xf8,0x6f,0xce,0x2f,0xf7,0xff,0x00,0x6e,0xdf,0xa9, + 0x0f,0xc1,0x5e,0x16,0x7c,0xbf,0xed,0x99,0xd5,0xe2,0xdb,0x4f,0xeb, + 0x58,0x4b,0xfb,0xc9,0x27,0xaf,0xf6,0x7d,0xfa,0x69,0x6e,0xef,0xa1, + 0xfe,0x60,0x8b,0xff,0x00,0x04,0x2a,0xff,0x00,0x82,0xb1,0x04,0x75, + 0xff,0x00,0x86,0x31,0xf1,0xa9,0x2d,0xbb,0x93,0xe3,0x5f,0x82,0x19, + 0x05,0x98,0x92,0xdc,0x7c,0x62,0xe7,0xa0,0x3c,0xe7,0xf5,0x22,0x84, + 0xff,0x00,0x82,0x16,0x7f,0xc1,0x59,0x95,0x4a,0x8f,0xd8,0xcb,0xc6, + 0xcb,0xb5,0x55,0x40,0xff,0x00,0x84,0xdf,0xe0,0x86,0x0e,0xde,0xe0, + 0x8f,0x8c,0x7d,0xf2,0x4f,0x66,0x0d,0xce,0x32,0x2b,0xfd,0x3e,0xfc, + 0x88,0x7f,0xe7,0x8c,0x5f,0xf7,0xed,0x3f,0xc2,0x8f,0x22,0x1f,0xf9, + 0xe3,0x17,0xfd,0xfb,0x4f,0xf0,0xa1,0xfd,0x35,0x7c,0x4c,0x7f,0xf3, + 0x21,0xe0,0xbf,0x96,0x5f,0x9c,0x2f,0xfd,0xee,0x99,0xcb,0xc1,0x1e, + 0x16,0x95,0xef,0x8e,0xcf,0x1d,0xda,0x6e,0xf8,0xbc,0x2e,0xeb,0xfe, + 0xe4,0x3d,0x7e,0x5d,0xb5,0xbf,0xf9,0x87,0xa7,0xfc,0x10,0xb3,0xfe, + 0x0a,0xc0,0x50,0xab,0x7e,0xc6,0xbe,0x36,0x04,0xba,0x39,0x2d,0xe3, + 0x7f,0x82,0x24,0x1d,0x80,0xf0,0x31,0xf1,0x87,0x20,0x9e,0x00,0x24, + 0xe0,0x74,0x39,0xe2,0xae,0x45,0xff,0x00,0x04,0x2f,0xff,0x00,0x82, + 0xac,0x99,0x00,0x3f,0xb1,0xbf,0x8d,0xe3,0x8c,0xae,0x64,0x0f,0xe3, + 0x5f,0x82,0x65,0x59,0x88,0x60,0x55,0x42,0x7c,0x62,0xe3,0x85,0x52, + 0x0f,0x00,0x12,0x00,0xf9,0x41,0x35,0xfe,0x9c,0x9e,0x44,0x3f,0xf3, + 0xc6,0x2f,0xfb,0xf6,0x9f,0xe1,0x47,0x91,0x0f,0xfc,0xf1,0x8b,0xfe, + 0xfd,0xa7,0xf8,0x51,0xff,0x00,0x13,0xab,0xe2,0x5e,0x97,0xc8,0x38, + 0x29,0xdb,0xfe,0xa5,0xf9,0xc7,0xe3,0xff,0x00,0x0b,0xba,0x99,0x4b, + 0xc0,0xbe,0x14,0x92,0xb3,0xcc,0x33,0xe5,0xe9,0x8b,0xc1,0xfb,0xba, + 0x25,0xa2,0x79,0x7b,0x5d,0x16,0xeb,0x4e,0x87,0xf9,0x90,0xc5,0xff, + 0x00,0x04,0x34,0xff,0x00,0x82,0xaf,0x2a,0x07,0x6f,0xd8,0xef,0xc6, + 0xe6,0x58,0xa5,0x2f,0x10,0x3e,0x34,0xf8,0x20,0x19,0xb2,0xeb,0xb0, + 0xb9,0xff,0x00,0x85,0xc2,0x46,0x22,0xf2,0xd5,0xf6,0xe4,0xe3,0x77, + 0xcb,0x9c,0x30,0xa4,0x5f,0xf8,0x21,0x9f,0xfc,0x15,0x6d,0x67,0x7d, + 0xbf,0xb1,0xbf,0x8d,0x02,0xb3,0xed,0x2e,0x7c,0x6b,0xf0,0x4b,0x0d, + 0x19,0x73,0x9d,0xb9,0xf8,0xc1,0xb9,0x0f,0x25,0xbc,0xcc,0x65,0x54, + 0x05,0xdb,0xb8,0x9c,0x7f,0xa6,0xff,0x00,0x91,0x0f,0xfc,0xf1,0x8b, + 0xfe,0xfd,0xa7,0xf8,0x51,0xe4,0x43,0xff,0x00,0x3c,0x62,0xff,0x00, + 0xbf,0x69,0xfe,0x14,0x7f,0xc4,0xea,0xf8,0x97,0xff,0x00,0x42,0x0e, + 0x0a,0xff,0x00,0xc2,0x0c,0xe7,0xff,0x00,0x9f,0xbf,0x2f,0xf8,0x77, + 0x78,0x7e,0x03,0xf0,0x93,0xbf,0xfc,0x28,0x67,0xfa,0xee,0x96,0x2b, + 0x05,0x65,0x7d,0x74,0x5f,0xd9,0xf6,0x76,0x7d,0xfb,0xf6,0x51,0x4b, + 0xfc,0xcc,0x07,0xfc,0x10,0xef,0xfe,0x0a,0xb9,0x16,0xc6,0x1f,0xb1, + 0xe7,0x8d,0xe4,0x62,0x86,0x36,0x1f,0xf0,0x9b,0x7c,0x10,0x05,0x4c, + 0x40,0x18,0xdb,0x0d,0xf1,0x7f,0x61,0x0e,0x72,0x32,0x4e,0x48,0x07, + 0x76,0x33,0x5a,0x6b,0xff,0x00,0x04,0x4a,0xff,0x00,0x82,0xad,0x48, + 0x3c,0xb9,0xff,0x00,0x63,0x8f,0x1a,0x3c,0x46,0x30,0x8c,0x64,0xf1, + 0xa7,0xc1,0x02,0xdb,0x5c,0x00,0xea,0x98,0xf8,0xbf,0xf2,0x8c,0x28, + 0xcf,0xf1,0xee,0x24,0xe4,0xe4,0x9a,0xff,0x00,0x4b,0xcf,0x22,0x1f, + 0xf9,0xe3,0x17,0xfd,0xfb,0x4f,0xf0,0xa3,0xc8,0x87,0xfe,0x78,0xc5, + 0xff,0x00,0x7e,0xd3,0xfc,0x2b,0x58,0xfd,0x36,0xbc,0x4d,0x82,0x71, + 0x5c,0x3f,0xc1,0x0d,0x3e,0xf9,0x7e,0x72,0xfa,0x25,0xff,0x00,0x43, + 0xee,0xb6,0xeb,0x73,0x09,0xfd,0x1f,0xf8,0x3a,0x7b,0xe6,0x1c,0x40, + 0x9f,0xf3,0x47,0x17,0x82,0x8c,0x96,0xb7,0x56,0x6b,0x2f,0xd2,0xdb, + 0x2d,0x36,0xde,0xfb,0x9f,0xe6,0x65,0x71,0xff,0x00,0x04,0x35,0xff, + 0x00,0x82,0xa8,0x0c,0x88,0x3f,0x63,0xaf,0x1c,0x05,0xe4,0x85,0x4f, + 0x1c,0x7c,0x13,0x39,0xe4,0x70,0xe5,0xbe,0x2f,0x03,0x8c,0x71,0x85, + 0xe0,0x8f,0xa6,0x6a,0xa7,0xfc,0x38,0xfb,0xfe,0x0a,0xbf,0x0c,0x61, + 0x23,0xfd,0x8d,0xfc,0x72,0x42,0x23,0x8c,0x2f,0x8d,0x7e,0x08,0x8c, + 0x96,0x57,0x55,0x20,0xff,0x00,0xc2,0xdf,0x27,0x21,0xca,0xb1,0x19, + 0xfb,0x80,0xe0,0x06,0xc1,0x1f,0xe9,0xb1,0xe4,0x43,0xff,0x00,0x3c, + 0x62,0xff,0x00,0xbf,0x69,0xfe,0x14,0x79,0x10,0xff,0x00,0xcf,0x18, + 0xbf,0xef,0xda,0x7f,0x85,0x6c,0xbe,0x9c,0x3e,0x28,0x28,0x72,0x2e, + 0x1e,0xe0,0x6e,0x5d,0x13,0x4f,0x2d,0xce,0x9a,0x69,0x49,0x49,0xa9, + 0x2f,0xed,0xfb,0x34,0xed,0xb7,0x47,0x66,0xb5,0x48,0xd2,0x9f,0x80, + 0x7c,0x21,0x4e,0x2a,0x3f,0xda,0x1c,0x41,0x35,0x16,0x9a,0xe7,0xc5, + 0x60,0x65,0x76,0x9f,0x32,0xe6,0xff,0x00,0x84,0xe5,0xcd,0xf3,0xf2, + 0xec,0x7c,0xe3,0xfb,0x1b,0x78,0x3f,0xc5,0x3f,0x0f,0x3f,0x64,0x8f, + 0xd9,0x7b,0xc0,0x1e,0x38,0xd1,0xee,0x3c,0x3f,0xe3,0x4f,0x03,0x7e, + 0xce,0xff,0x00,0x04,0x7c,0x1d,0xe2,0xfd,0x06,0xee,0x4b,0x49,0xae, + 0xb4,0x4f,0x14,0x78,0x5b,0xe1,0x8f,0x85,0xb4,0x0f,0x10,0xe9,0x17, + 0x13,0x69,0xf7,0x37,0xb6,0x13,0x4d,0xa6,0xeb,0x1a,0x75,0xed,0x94, + 0x93,0xd8,0xde,0xde,0xd9,0x4c,0xf0,0x34,0xb6,0x97,0x77,0x36,0xcf, + 0x14,0xf2,0x7d,0x27,0x48,0x00,0x1c,0x01,0x81,0xd3,0x03,0xa0,0xc7, + 0x4c,0x0e,0xd8,0xe9,0xf4,0xc0,0xe8,0x05,0x2d,0x7f,0x1d,0xe3,0xf1, + 0xb5,0x73,0x1c,0x76,0x37,0x30,0xaf,0x1a,0x71,0xaf,0x8e,0xc5,0xe2, + 0x31,0x95,0xa3,0x49,0x4e,0x34,0xa3,0x57,0x13,0x5a,0x75,0xaa,0x46, + 0x92,0xa9,0x3a,0x93,0x54,0xe3,0x29,0xb5,0x05,0x3a,0x95,0x26,0xa2, + 0x92,0x94,0xe7,0x2b,0xc9,0xfe,0xd3,0x85,0xa1,0x1c,0x2e,0x1b,0x0f, + 0x85,0xa6,0xe5,0x28,0x61,0xa8,0x52,0xc3,0xc2,0x53,0xb3,0x9c,0xa1, + 0x46,0x9c,0x69,0xc5,0xc9,0xc6,0x31,0x8f,0x33,0x51,0x4e,0x5c,0xb1, + 0x8c,0x6f,0x7b,0x45,0x2d,0x02,0x8a,0x28,0xae,0x43,0x70,0xa2,0x8a, + 0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28, + 0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00, + 0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2, + 0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a, + 0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28, + 0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00, + 0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2, + 0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a, + 0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28, + 0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00, + 0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2, + 0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a, + 0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28, + 0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00, + 0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2, + 0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a, + 0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28, + 0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00, + 0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2, + 0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a, + 0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28, + 0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00, + 0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2, + 0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a, + 0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28,0x00,0xa2,0x8a,0x28, + 0x00,0xa2,0x8a,0x28,0x00,0xff,0xd9,0xd9 +}; +#define UX_TEST_JPEG_IMAGE_LENGTH sizeof(ux_test_jpeg_image) + +#endif \ No newline at end of file diff --git a/test/regression/ux_test_race_condition_overrides.c b/test/regression/ux_test_race_condition_overrides.c new file mode 100644 index 00000000..21d7fbe7 --- /dev/null +++ b/test/regression/ux_test_race_condition_overrides.c @@ -0,0 +1,198 @@ +#include "ux_test.h" +#include "ux_api.h" +#include "ux_host_class_storage.h" + +#ifdef UX_TEST_RACE_CONDITION_TESTS_ON + +/* We override this so we can disconnect the device right before the device state check. We can't do it in the HCD + because that's after the device state check and that's the only thing that can make us return an error. */ +UINT _ux_host_stack_transfer_request(UX_TRANSFER *transfer_request) +{ + +UX_ENDPOINT *endpoint; +UX_DEVICE *device; +UX_HCD *hcd; +UINT status; +#ifdef BUGFIX /* USBX_162 */ +TX_THREAD *this_thread; +UINT old_threshold; +#endif +UX_TEST_HOST_STACK_TRANSFER_REQUEST_PARAMS params = { transfer_request }; +UX_TEST_ACTION action; + + + action = ux_test_action_handler(UX_TEST_HOST_STACK_TRANSFER_REQUEST, ¶ms); + ux_test_do_action_before(&action, ¶ms); + + /* Get the endpoint container from the transfer_request */ + endpoint = transfer_request -> ux_transfer_request_endpoint; + + /* Get the device container from the endpoint. */ + device = endpoint -> ux_endpoint_device; + +#ifdef BUGFIX /* USBX_162 */ + /* Get the pointer to this thread. */ + this_thread = tx_thread_identify(); + + /* Make the following check and assignment atomic. */ + tx_thread_preemption_change(this_thread, 0, &old_threshold); + + /* We can only transfer when the device is ATTACHED, ADDRESSED OR CONFIGURED. */ + if ((device -> ux_device_state == UX_DEVICE_ATTACHED) || (device -> ux_device_state == UX_DEVICE_ADDRESSED) + || (device -> ux_device_state == UX_DEVICE_CONFIGURED)) + { + + /* Set the pending transfer request. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_STATUS_PENDING; + +#ifdef BUGFIX /* USBX_115 */ + /* Save the thread waiting for the transfer to complete. */ + transfer_request -> ux_transfer_request_thread_pending = this_thread; +#endif + } + + tx_thread_preemption_change(this_thread, old_threshold, &old_threshold); + + if (transfer_request -> ux_transfer_request_completion_code != UX_TRANSFER_STATUS_PENDING) + return(UX_TRANSFER_NOT_READY); + + /* If trace is enabled, insert this event into the trace buffer. */ + UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_STACK_TRANSFER_REQUEST, device, endpoint, transfer_request, 0, UX_TRACE_HOST_STACK_EVENTS, 0, 0) + + /* With the device we have the pointer to the HCD. */ + hcd = UX_DEVICE_HCD_GET(device); + + /* If this is endpoint 0, we protect the endpoint from a possible re-entry. */ + if ((endpoint -> ux_endpoint_descriptor.bEndpointAddress & (UINT)~UX_ENDPOINT_DIRECTION) == 0) + { + + /* Check if the class has already protected it. */ + if (device -> ux_device_protection_semaphore.tx_semaphore_count != 0) + { + + /* We are using endpoint 0. Protect with semaphore. */ + status = _ux_utility_semaphore_get(&device -> ux_device_protection_semaphore, UX_WAIT_FOREVER); + + /* Check for status. */ + if (status != UX_SUCCESS) + + /* Something went wrong. */ + return(status); + } + } + + /* Send the command to the controller. */ + status = hcd -> ux_hcd_entry_function(hcd, UX_HCD_TRANSFER_REQUEST, transfer_request); + + /* Check result from transfer request preparation. */ + if (status == UX_SUCCESS) + { + + /* If this is endpoint 0, we unprotect the endpoint. */ + if ((endpoint -> ux_endpoint_descriptor.bEndpointAddress & (UINT)~UX_ENDPOINT_DIRECTION) == 0) + + /* We are using endpoint 0. Unprotect with semaphore. */ + _ux_utility_semaphore_put(&device -> ux_device_protection_semaphore); + } +#else + /* We can only transfer when the device is ATTACHED, ADDRESSED OR CONFIGURED. */ + if ((device -> ux_device_state == UX_DEVICE_ATTACHED) || (device -> ux_device_state == UX_DEVICE_ADDRESSED) + || (device -> ux_device_state == UX_DEVICE_CONFIGURED)) + { + + + /* If trace is enabled, insert this event into the trace buffer. */ + UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_STACK_TRANSFER_REQUEST, device, endpoint, transfer_request, 0, UX_TRACE_HOST_STACK_EVENTS, 0, 0) + + /* With the device we have the pointer to the HCD. */ + hcd = UX_DEVICE_HCD_GET(device); + + /* If this is endpoint 0, we protect the endpoint from a possible re-entry. */ + if ((endpoint -> ux_endpoint_descriptor.bEndpointAddress & (UINT)~UX_ENDPOINT_DIRECTION) == 0) + { + + /* Check if the class has already protected it. */ + if (device -> ux_device_protection_semaphore.tx_semaphore_count != 0) + { + + /* We are using endpoint 0. Protect with semaphore. */ + status = _ux_utility_semaphore_get(&device -> ux_device_protection_semaphore, UX_WAIT_FOREVER); + + /* Check for status. */ + if (status != UX_SUCCESS) + + /* Something went wrong. */ + return(status); + } + } + + /* Set the pending transfer request. */ + transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_STATUS_PENDING; + + /* Send the command to the controller. */ + status = hcd -> ux_hcd_entry_function(hcd, UX_HCD_TRANSFER_REQUEST, transfer_request); + + /* Check result from transfer request preparation. */ + if (status == UX_SUCCESS) + { + + /* If this is endpoint 0, we unprotect the endpoint. */ + if ((endpoint -> ux_endpoint_descriptor.bEndpointAddress & (UINT)~UX_ENDPOINT_DIRECTION) == 0) + + /* We are using endpoint 0. Unprotect with semaphore. */ + _ux_utility_semaphore_put(&device -> ux_device_protection_semaphore); + } + } + else + + /* We come here when the device is not in a state which allows transmission. */ + status = UX_TRANSFER_NOT_READY; +#endif + + ux_test_do_action_after(&action, ¶ms); + + /* And return the status. */ + return(status); +} + +UINT _ux_host_stack_interface_set(UX_INTERFACE *interface) +{ + +UX_DEVICE *device; +UX_CONFIGURATION *configuration; +UX_TRANSFER *transfer_request; +UINT status; +UX_ENDPOINT *control_endpoint; +UX_TEST_HOST_STACK_TRANSFER_REQUEST_PARAMS params = { transfer_request }; +UX_TEST_ACTION action; + + + /* If trace is enabled, insert this event into the trace buffer. */ + UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_STACK_INTERFACE_SET, interface, 0, 0, 0, UX_TRACE_HOST_STACK_EVENTS, 0, 0) + + /* Retrieve the pointer to the control endpoint and its transfer_request. + From the interface we go back to the configuration, then the device. + The device contains the default control endpoint container. */ + configuration = interface -> ux_interface_configuration; + device = configuration -> ux_configuration_device; + control_endpoint = &device -> ux_device_control_endpoint; + transfer_request = &control_endpoint -> ux_endpoint_transfer_request; + + /* Create a transfer_request for the SET_INTERFACE request. No data for this request */ + transfer_request -> ux_transfer_request_requested_length = 0; + transfer_request -> ux_transfer_request_function = UX_SET_INTERFACE; + transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_INTERFACE; + transfer_request -> ux_transfer_request_index = (USHORT) interface -> ux_interface_descriptor.bInterfaceNumber; + transfer_request -> ux_transfer_request_value = (USHORT) interface -> ux_interface_descriptor.bAlternateSetting; + + action = ux_test_action_handler(UX_TEST_HOST_STACK_INTERFACE_SET, ¶ms); + ux_test_do_action_before(&action, ¶ms); + + /* Send request to HCD layer. */ + status = _ux_host_stack_hcd_transfer_request(transfer_request); + + /* Return status completion. */ + return(status); +} + +#endif \ No newline at end of file diff --git a/test/regression/ux_test_standalone_references.c b/test/regression/ux_test_standalone_references.c new file mode 100644 index 00000000..a21b23ea --- /dev/null +++ b/test/regression/ux_test_standalone_references.c @@ -0,0 +1,25 @@ + +/* Pure UX configurations, isolate other headers configurations. */ +#include "ux_api.h" + +#if defined(UX_HOST_STANDALONE) && !defined(_ux_utility_time_get) +extern ULONG _tx_time_get(VOID); +ULONG _ux_utility_time_get(VOID) +{ + return(_tx_time_get()); +} +#endif +#if defined(UX_STANDALONE) && !defined(_ux_utility_interrupt_disable) +extern ALIGN_TYPE _tx_thread_interrupt_disable(VOID); +ALIGN_TYPE _ux_utility_interrupt_disable(VOID) +{ + return _tx_thread_interrupt_disable(); +} +#endif +#if defined(UX_STANDALONE) && !defined(_ux_utility_interrupt_restore) +extern VOID _tx_thread_interrupt_restore(ALIGN_TYPE flags); +VOID _ux_utility_interrupt_restore(ALIGN_TYPE flags) +{ + _tx_thread_interrupt_restore(flags); +} +#endif diff --git a/test/regression/ux_test_utility_sim.c b/test/regression/ux_test_utility_sim.c new file mode 100644 index 00000000..84c57b51 --- /dev/null +++ b/test/regression/ux_test_utility_sim.c @@ -0,0 +1,2967 @@ +/* This test simulator is designed to simulate ux_utility_ APIs for test. */ + +#include + +#define TX_SOURCE_CODE +#include "tx_api.h" +#include "tx_thread.h" +#include "tx_trace.h" +#include "tx_mutex.h" +#include "tx_semaphore.h" +#include "tx_event_flags.h" +#include "tx_initialize.h" + + +#define NX_SOURCE_CODE +#include "nx_api.h" +#include "nx_packet.h" + + +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" +#include "ux_hcd_sim_host.h" +#include "ux_dcd_sim_slave.h" +#include "ux_device_stack.h" +#include "ux_test_utility_sim.h" +#include "ux_test_hcd_sim_host.h" +#include "ux_test_dcd_sim_slave.h" +#include "ux_host_class_storage.h" + +#include "ux_test.h" + +#define FAIL_DISABLE ((ULONG)~0x00) +#define SYSTEM_MUTEX_ALLOC_LOG_SIZE 1024 + +typedef struct UX_TEST_UTILITY_SIM_SEM_EXCEPT_STRUCT +{ + + struct UX_TEST_UTILITY_SIM_SEM_EXCEPT_STRUCT *next; + + TX_SEMAPHORE *semaphore; /* UX_NULL to match any */ + ULONG semaphore_signal; +} UX_TEST_UTILITY_SIM_SEM_EXCEPT; + +typedef struct UX_TEST_UTILITY_SIM_MEMD_STRUCT +{ + + struct UX_TEST_UTILITY_SIM_MEMD_STRUCT *next; + VOID *mem; +} UX_TEST_UTILITY_SIM_MEMD; + +typedef struct UX_TEST_UTILITY_SYSTEM_MUTEX_ALLOC_LOG_STRUCT +{ + + ULONG first_count; + ULONG last_count; +} UX_TEST_UTILITY_SYSTEM_MUTEX_ALLOC_LOG; + +static ULONG sem_create_count = 0; +static ULONG sem_create_fail_after = FAIL_DISABLE; + +static ULONG sem_get_count = 0; +static ULONG sem_get_fail_after = FAIL_DISABLE; + +static UX_TEST_UTILITY_SIM_SEM_EXCEPT *excepts = UX_NULL; + +static ULONG mutex_create_count = 0; +static ULONG mutex_fail_after = FAIL_DISABLE; + +static ULONG mutex_on_count = 0; +static ULONG mutex_on_fail_after = FAIL_DISABLE; + +static ULONG event_create_count = 0; +static ULONG event_fail_after = FAIL_DISABLE; + +static void ux_system_mutex_create_callback(UX_TEST_ACTION *action, VOID *params); +static void ux_system_mutex_get_callback(UX_TEST_ACTION *action, VOID *params); +static void ux_system_mutex_put_callback(UX_TEST_ACTION *action, VOID *params); + +/* Create - 0, get - 1, put - 2 */ +static UX_TEST_ACTION ux_system_mutex_hooks[4] = { + { + .usbx_function = UX_TEST_OVERRIDE_TX_MUTEX_CREATE, + .name_ptr = "ux_system_mutex", + .mutex_ptr = UX_NULL, /* Don't care. */ + .inherit = TX_NO_INHERIT, + .do_after = UX_TRUE, + .action_func = ux_system_mutex_create_callback, + }, + { + .usbx_function = UX_TEST_OVERRIDE_TX_MUTEX_GET, + .mutex_ptr = UX_NULL, /* Replaced on creation callback. */ + .wait_option = TX_WAIT_FOREVER, + .do_after = UX_FALSE, + .action_func = ux_system_mutex_get_callback, + }, + { + .usbx_function = UX_TEST_OVERRIDE_TX_MUTEX_PUT, + .mutex_ptr = UX_NULL, /* Replaced on creation callback. */ + .do_after = UX_TRUE, + .action_func = ux_system_mutex_put_callback, + }, +{ 0 }, +}; + +static ULONG ux_system_mutex_on_count = 0; +static ULONG ux_system_mutex_off_count = 0; +UCHAR ux_system_mutex_callback_skip = UX_FALSE; +static ULONG rmem_free = 0; +static ULONG cmem_free = 0; +static UX_TEST_UTILITY_SYSTEM_MUTEX_ALLOC_LOG ux_system_mutex_alloc_logs[SYSTEM_MUTEX_ALLOC_LOG_SIZE]; +static ULONG ux_system_mutex_alloc_logs_count = 0; +static ULONG ux_system_mutex_alloc_logs_match = 0; +static UCHAR ux_system_mutex_alloc_logs_area = UX_FALSE; +static UCHAR ux_system_mutex_alloc_logs_lock = UX_FALSE; + +static ULONG thread_create_count = 0; +static ULONG thread_create_fail_after = FAIL_DISABLE; + +static UX_TEST_UTILITY_SIM_MEMD first_allocate[2]; +static UX_TEST_UTILITY_SIM_MEMD *sim_allocates [2] = {UX_NULL, UX_NULL}; +static VOID *last_allocate [2] = {UX_NULL, UX_NULL}; + +static ULONG mem_alloc_count = 0; +static ULONG mem_alloc_fail_after = FAIL_DISABLE; +ULONG mem_alloc_do_fail = UX_FALSE; + +VOID ux_test_utility_sim_cleanup(VOID) +{ + + sem_create_count = 0; + sem_create_fail_after = FAIL_DISABLE; + + sem_get_count = 0; + sem_get_fail_after = FAIL_DISABLE; + + excepts = UX_NULL; + + mutex_create_count = 0; + mutex_fail_after = FAIL_DISABLE; + + mutex_on_count = 0; + mutex_on_fail_after = FAIL_DISABLE; + + event_create_count = 0; + event_fail_after = FAIL_DISABLE; + + thread_create_count = 0; + thread_create_fail_after = FAIL_DISABLE; + + sim_allocates[0] = UX_NULL; + sim_allocates[1] = UX_NULL; + last_allocate[0] = UX_NULL; + last_allocate[1] = UX_NULL; + + ux_test_remove_hooks_from_array(ux_system_mutex_hooks); + + mem_alloc_count = 0; + mem_alloc_fail_after = FAIL_DISABLE; + mem_alloc_do_fail = UX_FALSE; + + ux_system_mutex_on_count = 0; + ux_system_mutex_off_count = 0; + ux_system_mutex_callback_skip = UX_FALSE; + ux_system_mutex_alloc_logs_count = 0; + ux_system_mutex_alloc_logs_match = 0; + ux_system_mutex_alloc_logs_area = UX_FALSE; + ux_system_mutex_alloc_logs_lock = UX_FALSE; + _ux_utility_memory_set(ux_system_mutex_alloc_logs, 0, sizeof(ux_system_mutex_alloc_logs)); +} + +/* Semaphore handling simulation */ + +VOID ux_test_utility_sim_sem_create_count_reset(VOID) +{ + + sem_create_count = 0; +} + +ULONG ux_test_utility_sim_sem_create_count(VOID) +{ + + return sem_create_count; +} + +VOID ux_test_utility_sim_sem_error_generation_start(ULONG fail_after) +{ + + sem_create_count = 0; + sem_create_fail_after = fail_after; +} + +VOID ux_test_utility_sim_sem_error_generation_stop(VOID) +{ + + sem_create_fail_after = FAIL_DISABLE; + sem_create_count = 0; +} + +UINT _tx_semaphore_create(TX_SEMAPHORE *semaphore_ptr, CHAR *name_ptr, ULONG initial_count) +{ + +TX_INTERRUPT_SAVE_AREA + +TX_SEMAPHORE *next_semaphore; +TX_SEMAPHORE *previous_semaphore; +UX_TEST_OVERRIDE_TX_SEMAPHORE_CREATE_PARAMS action_params = { semaphore_ptr, name_ptr, initial_count }; +UX_TEST_ACTION action; + + + if (sem_create_fail_after != FAIL_DISABLE) + { + + if (sem_create_count >= sem_create_fail_after) + { + + /* Return testing error instead of actual creation. */ + return UX_MUTEX_ERROR; + } + } + + /* Perform action. */ + action = ux_test_action_handler(UX_TEST_OVERRIDE_TX_SEMAPHORE_CREATE, &action_params); + ux_test_do_action_before(&action, &action_params); + if (ux_test_is_expedient_on()) + { + if (action.matched && !action.do_after) + { + if (!action.no_return) + { + return action.status; + } + } + } + + /* Do actual creating. */ + sem_create_count ++; + + /* Initialize semaphore control block to all zeros. */ + TX_MEMSET(semaphore_ptr, 0, (sizeof(TX_SEMAPHORE))); + + /* Setup the basic semaphore fields. */ + semaphore_ptr -> tx_semaphore_name = name_ptr; + semaphore_ptr -> tx_semaphore_count = initial_count; + + /* Disable interrupts to place the semaphore on the created list. */ + TX_DISABLE + + /* Setup the semaphore ID to make it valid. */ + semaphore_ptr -> tx_semaphore_id = TX_SEMAPHORE_ID; + + /* Place the semaphore on the list of created semaphores. First, + check for an empty list. */ + if (_tx_semaphore_created_count == TX_EMPTY) + { + + /* The created semaphore list is empty. Add semaphore to empty list. */ + _tx_semaphore_created_ptr = semaphore_ptr; + semaphore_ptr -> tx_semaphore_created_next = semaphore_ptr; + semaphore_ptr -> tx_semaphore_created_previous = semaphore_ptr; + } + else + { + + /* This list is not NULL, add to the end of the list. */ + next_semaphore = _tx_semaphore_created_ptr; + previous_semaphore = next_semaphore -> tx_semaphore_created_previous; + + /* Place the new semaphore in the list. */ + next_semaphore -> tx_semaphore_created_previous = semaphore_ptr; + previous_semaphore -> tx_semaphore_created_next = semaphore_ptr; + + /* Setup this semaphore's next and previous created links. */ + semaphore_ptr -> tx_semaphore_created_previous = previous_semaphore; + semaphore_ptr -> tx_semaphore_created_next = next_semaphore; + } + + /* Increment the created count. */ + _tx_semaphore_created_count++; + + /* Optional semaphore create extended processing. */ + TX_SEMAPHORE_CREATE_EXTENSION(semaphore_ptr) + + /* If trace is enabled, register this object. */ + TX_TRACE_OBJECT_REGISTER(TX_TRACE_OBJECT_TYPE_SEMAPHORE, semaphore_ptr, name_ptr, initial_count, 0) + + /* If trace is enabled, insert this event into the trace buffer. */ + TX_TRACE_IN_LINE_INSERT(TX_TRACE_SEMAPHORE_CREATE, semaphore_ptr, initial_count, TX_POINTER_TO_ULONG_CONVERT(&next_semaphore), 0, TX_TRACE_SEMAPHORE_EVENTS) + + /* Log this kernel call. */ + TX_EL_SEMAPHORE_CREATE_INSERT + + /* Restore interrupts. */ + TX_RESTORE + + /* Return TX_SUCCESS. */ + return(TX_SUCCESS); +} + +VOID ux_test_utility_sim_sem_get_count_reset (VOID) +{ + + sem_get_count = 0; +} + +ULONG ux_test_utility_sim_sem_get_count (VOID) +{ + + return sem_get_count; +} + +VOID ux_test_utility_sim_sem_get_error_generation_start(ULONG fail_after) +{ + + sem_get_count = 0; + sem_get_fail_after = fail_after; +} + +VOID ux_test_utility_sim_sem_get_error_generation_stop (VOID) +{ + + sem_get_fail_after = FAIL_DISABLE; + sem_get_count = 0; +} + +VOID ux_test_utility_sim_sem_get_error_exception_reset(VOID) +{ + + excepts = UX_NULL; +} + +VOID ux_test_utility_sim_sem_get_error_exception_add(TX_SEMAPHORE *semaphore, ULONG semaphore_signal) +{ +UX_TEST_UTILITY_SIM_SEM_EXCEPT* except; + + if (_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start == UX_NULL) + return; + + except = (UX_TEST_UTILITY_SIM_SEM_EXCEPT *)ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_TEST_UTILITY_SIM_SEM_EXCEPT)); + if (except == UX_NULL) + return; + + /* Save exception */ + except->semaphore = semaphore; + except->semaphore_signal = semaphore_signal; + + /* Link to head */ + except->next = excepts; + excepts = except; +} + +static UCHAR ux_test_utility_sim_sem_in_exception_list(TX_SEMAPHORE *semaphore, ULONG semaphore_signal) +{ +UX_TEST_UTILITY_SIM_SEM_EXCEPT* except; + + except = excepts; + while(except) + { + + if (except->semaphore == UX_NULL && semaphore_signal == except->semaphore_signal) + return UX_TRUE; + + if (except->semaphore == semaphore && semaphore_signal == except->semaphore_signal) + return UX_TRUE; + + except = except->next; + } + return UX_FALSE; +} + +UINT _tx_semaphore_get(TX_SEMAPHORE *semaphore_ptr, ULONG wait_option) +{ + +TX_INTERRUPT_SAVE_AREA + +TX_THREAD *thread_ptr; +TX_THREAD *next_thread; +TX_THREAD *previous_thread; +UINT status; +UX_TEST_OVERRIDE_TX_SEMAPHORE_GET_PARAMS params = { semaphore_ptr, wait_option }; +UX_TEST_ACTION action; + + + /* Perform hooked callbacks. */ + ux_test_do_hooks_before(UX_TEST_OVERRIDE_TX_SEMAPHORE_GET, ¶ms); + + action = ux_test_action_handler(UX_TEST_OVERRIDE_TX_SEMAPHORE_GET, ¶ms); + ux_test_do_action_before(&action, ¶ms); + + if (ux_test_is_expedient_on()) + { + + if (sem_get_fail_after != FAIL_DISABLE) + + if (sem_get_count >= sem_get_fail_after) + + /* Return testing error instead of actual creation. */ + if (!ux_test_utility_sim_sem_in_exception_list(semaphore_ptr, wait_option)) + + return UX_SEMAPHORE_ERROR; + } + + /* Default the status to TX_SUCCESS. */ + status = TX_SUCCESS; + + /* Disable interrupts to get an instance from the semaphore. */ + TX_DISABLE + +#ifdef TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO + + /* Increment the total semaphore get counter. */ + _tx_semaphore_performance_get_count++; + + /* Increment the number of attempts to get this semaphore. */ + semaphore_ptr -> tx_semaphore_performance_get_count++; +#endif + + /* If trace is enabled, insert this event into the trace buffer. */ + TX_TRACE_IN_LINE_INSERT(TX_TRACE_SEMAPHORE_GET, semaphore_ptr, wait_option, semaphore_ptr -> tx_semaphore_count, TX_POINTER_TO_ULONG_CONVERT(&thread_ptr), TX_TRACE_SEMAPHORE_EVENTS) + + /* Log this kernel call. */ + TX_EL_SEMAPHORE_GET_INSERT + + /* Determine if there is an instance of the semaphore. */ + if (semaphore_ptr -> tx_semaphore_count != ((ULONG) 0)) + { + + /* Decrement the semaphore count. */ + semaphore_ptr -> tx_semaphore_count--; + + /* Restore interrupts. */ + TX_RESTORE + } + + /* Determine if the request specifies suspension. */ + else if (wait_option != TX_NO_WAIT) + { + + /* Prepare for suspension of this thread. */ + +#ifdef TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO + + /* Increment the total semaphore suspensions counter. */ + _tx_semaphore_performance_suspension_count++; + + /* Increment the number of suspensions on this semaphore. */ + semaphore_ptr -> tx_semaphore_performance_suspension_count++; +#endif + + /* Pickup thread pointer. */ + TX_THREAD_GET_CURRENT(thread_ptr) + + /* Setup cleanup routine pointer. */ + thread_ptr -> tx_thread_suspend_cleanup = &(_tx_semaphore_cleanup); + + /* Setup cleanup information, i.e. this semaphore control + block. */ + thread_ptr -> tx_thread_suspend_control_block = (VOID *) semaphore_ptr; + + /* Setup suspension list. */ + if (semaphore_ptr -> tx_semaphore_suspended_count == TX_NO_SUSPENSIONS) + { + + /* No other threads are suspended. Setup the head pointer and + just setup this threads pointers to itself. */ + semaphore_ptr -> tx_semaphore_suspension_list = thread_ptr; + thread_ptr -> tx_thread_suspended_next = thread_ptr; + thread_ptr -> tx_thread_suspended_previous = thread_ptr; + } + else + { + + /* This list is not NULL, add current thread to the end. */ + next_thread = semaphore_ptr -> tx_semaphore_suspension_list; + thread_ptr -> tx_thread_suspended_next = next_thread; + previous_thread = next_thread -> tx_thread_suspended_previous; + thread_ptr -> tx_thread_suspended_previous = previous_thread; + previous_thread -> tx_thread_suspended_next = thread_ptr; + next_thread -> tx_thread_suspended_previous = thread_ptr; + } + + /* Increment the number of suspensions. */ + semaphore_ptr -> tx_semaphore_suspended_count++; + + /* Set the state to suspended. */ + thread_ptr -> tx_thread_state = TX_SEMAPHORE_SUSP; + +#ifdef TX_NOT_INTERRUPTABLE + + /* Call actual non-interruptable thread suspension routine. */ + _tx_thread_system_ni_suspend(thread_ptr, wait_option); + + /* Restore interrupts. */ + TX_RESTORE +#else + + /* Set the suspending flag. */ + thread_ptr -> tx_thread_suspending = TX_TRUE; + + /* Setup the timeout period. */ + thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = wait_option; + + /* Temporarily disable preemption. */ + _tx_thread_preempt_disable++; + + /* Restore interrupts. */ + TX_RESTORE + + /* Call actual thread suspension routine. */ + _tx_thread_system_suspend(thread_ptr); +#endif + + /* Return the completion status. */ + status = thread_ptr -> tx_thread_suspend_status; + } + else + { + + /* Restore interrupts. */ + TX_RESTORE + + /* Immediate return, return error completion. */ + status = TX_NO_INSTANCE; + } + + ux_test_do_action_after(&action, ¶ms); + + /* Perform hooked callbacks. */ + ux_test_do_hooks_after(UX_TEST_OVERRIDE_TX_SEMAPHORE_GET, ¶ms); + + /* Return completion status. */ + return(status); +} + +/* Mutex handling simulation */ + +VOID ux_test_utility_sim_mutex_create_count_reset(VOID) +{ + + mutex_create_count = 0; +} + +ULONG ux_test_utility_sim_mutex_create_count(VOID) +{ + + return mutex_create_count; +} + +VOID ux_test_utility_sim_mutex_error_generation_start(ULONG fail_after) +{ + + mutex_create_count = 0; + mutex_fail_after = fail_after; +} + +VOID ux_test_utility_sim_mutex_error_generation_stop(VOID) +{ + + mutex_fail_after = FAIL_DISABLE; + mutex_create_count = 0; +} + +UINT _tx_mutex_create(TX_MUTEX *mutex_ptr, CHAR *name_ptr, UINT inherit) +{ + +TX_INTERRUPT_SAVE_AREA + +TX_MUTEX *next_mutex; +TX_MUTEX *previous_mutex; + +UX_TEST_OVERRIDE_TX_MUTEX_CREATE_PARAMS action_params = { mutex_ptr, name_ptr, inherit }; +UX_TEST_ACTION action; + + /* Perform hooked callbacks. */ + ux_test_do_hooks_before(UX_TEST_OVERRIDE_TX_MUTEX_CREATE, &action_params); + + /* Perform action. */ + action = ux_test_action_handler(UX_TEST_OVERRIDE_TX_MUTEX_CREATE, &action_params); + ux_test_do_action_before(&action, &action_params); + + if (mutex_fail_after != FAIL_DISABLE) + { + + if (mutex_create_count >= mutex_fail_after) + { + + /* Return testing error instead of actual creation. */ + return UX_MUTEX_ERROR; + } + } + + /* Do actual creating. */ + mutex_create_count ++; + + /* Initialize mutex control block to all zeros. */ + TX_MEMSET(mutex_ptr, 0, (sizeof(TX_MUTEX))); + + /* Setup the basic mutex fields. */ + mutex_ptr -> tx_mutex_name = name_ptr; + mutex_ptr -> tx_mutex_inherit = inherit; + + /* Disable interrupts to place the mutex on the created list. */ + TX_DISABLE + + /* Setup the mutex ID to make it valid. */ + mutex_ptr -> tx_mutex_id = TX_MUTEX_ID; + + /* Setup the thread mutex release function pointer. */ + _tx_thread_mutex_release = &(_tx_mutex_thread_release); + + /* Place the mutex on the list of created mutexes. First, + check for an empty list. */ + if (_tx_mutex_created_count == TX_EMPTY) + { + + /* The created mutex list is empty. Add mutex to empty list. */ + _tx_mutex_created_ptr = mutex_ptr; + mutex_ptr -> tx_mutex_created_next = mutex_ptr; + mutex_ptr -> tx_mutex_created_previous = mutex_ptr; + } + else + { + + /* This list is not NULL, add to the end of the list. */ + next_mutex = _tx_mutex_created_ptr; + previous_mutex = next_mutex -> tx_mutex_created_previous; + + /* Place the new mutex in the list. */ + next_mutex -> tx_mutex_created_previous = mutex_ptr; + previous_mutex -> tx_mutex_created_next = mutex_ptr; + + /* Setup this mutex's next and previous created links. */ + mutex_ptr -> tx_mutex_created_previous = previous_mutex; + mutex_ptr -> tx_mutex_created_next = next_mutex; + } + + /* Increment the ownership count. */ + _tx_mutex_created_count++; + + /* Optional mutex create extended processing. */ + TX_MUTEX_CREATE_EXTENSION(mutex_ptr) + + /* If trace is enabled, register this object. */ + TX_TRACE_OBJECT_REGISTER(TX_TRACE_OBJECT_TYPE_MUTEX, mutex_ptr, name_ptr, inherit, 0) + + /* If trace is enabled, insert this event into the trace buffer. */ + TX_TRACE_IN_LINE_INSERT(TX_TRACE_MUTEX_CREATE, mutex_ptr, inherit, TX_POINTER_TO_ULONG_CONVERT(&next_mutex), 0, TX_TRACE_MUTEX_EVENTS) + + /* Log this kernel call. */ + TX_EL_MUTEX_CREATE_INSERT + + /* Restore interrupts. */ + TX_RESTORE + + ux_test_do_action_after(&action, &action_params); + + /* Perform hooked callbacks. */ + ux_test_do_hooks_after(UX_TEST_OVERRIDE_TX_MUTEX_CREATE, &action_params); + + /* Return TX_SUCCESS. */ + return(TX_SUCCESS); +} + +VOID ux_test_utility_sim_mutex_on_count_reset (VOID) +{ + + mutex_on_count = 0; +} +ULONG ux_test_utility_sim_mutex_on_count (VOID) +{ + + return mutex_on_count; +} + +VOID ux_test_utility_sim_mutex_on_error_generation_start(ULONG fail_after) +{ + + mutex_on_count = 0; + mutex_on_fail_after = fail_after; +} +VOID ux_test_utility_sim_mutex_on_error_generation_stop (VOID) +{ + + mutex_on_fail_after = FAIL_DISABLE; + mutex_on_count = 0; +} + +/* Thread handling simulation */ + +VOID ux_test_utility_sim_thread_create_count_reset(VOID) +{ + + thread_create_count = 0; +} + +ULONG ux_test_utility_sim_thread_create_count(VOID) +{ + + return thread_create_count; +} + +VOID ux_test_utility_sim_thread_error_generation_start(ULONG fail_after) +{ + + thread_create_count = 0; + thread_create_fail_after = fail_after; +} + +VOID ux_test_utility_sim_thread_error_generation_stop(VOID) +{ + + thread_create_fail_after = FAIL_DISABLE; + thread_create_count = 0; +} + +UINT _tx_thread_create(TX_THREAD *thread_ptr, CHAR *name_ptr, VOID (*entry_function)(ULONG id), ULONG entry_input, + VOID *stack_start, ULONG stack_size, UINT priority, UINT preempt_threshold, + ULONG time_slice, UINT auto_start) +{ + +TX_INTERRUPT_SAVE_AREA + +TX_THREAD *next_thread; +TX_THREAD *previous_thread; +TX_THREAD *saved_thread_ptr; +UINT saved_threshold = ((UINT) 0); +UCHAR *temp_ptr; +UX_TEST_OVERRIDE_TX_THREAD_CREATE_PARAMS action_params = { name_ptr }; +UX_TEST_ACTION action; + +#ifdef TX_ENABLE_STACK_CHECKING +ULONG new_stack_start; +ULONG updated_stack_start; +#endif + + + if (thread_create_fail_after != FAIL_DISABLE) + { + + if (thread_create_count >= thread_create_fail_after) + { + + /* Return testing error instead of actual creation. */ + return UX_MUTEX_ERROR; + } + } + + /* Perform action. */ + action = ux_test_action_handler(UX_TEST_OVERRIDE_TX_THREAD_CREATE, &action_params); + ux_test_do_action_before(&action, &action_params); + if (ux_test_is_expedient_on()) + { + if (action.matched && !action.do_after) + { + if (!action.no_return) + { + return action.status; + } + } + } + + /* Do actual creating. */ + thread_create_count ++; + +#ifndef TX_DISABLE_STACK_FILLING + + /* Set the thread stack to a pattern prior to creating the initial + stack frame. This pattern is used by the stack checking routines + to see how much has been used. */ + TX_MEMSET(stack_start, ((UCHAR) TX_STACK_FILL), stack_size); +#endif + +#ifdef TX_ENABLE_STACK_CHECKING + + /* Ensure that there are two ULONG of 0xEF patterns at the top and + bottom of the thread's stack. This will be used to check for stack + overflow conditions during run-time. */ + stack_size = ((stack_size/(sizeof(ULONG))) * (sizeof(ULONG))) - (sizeof(ULONG)); + + /* Ensure the starting stack address is evenly aligned. */ + new_stack_start = TX_POINTER_TO_ULONG_CONVERT(stack_start); + updated_stack_start = ((((ULONG) new_stack_start) + ((sizeof(ULONG)) - ((ULONG) 1)) ) & (~((sizeof(ULONG)) - ((ULONG) 1)))); + + /* Determine if the starting stack address is different. */ + if (new_stack_start != updated_stack_start) + { + + /* Yes, subtract another ULONG from the size to avoid going past the stack area. */ + stack_size = stack_size - (sizeof(ULONG)); + } + + /* Update the starting stack pointer. */ + stack_start = TX_ULONG_TO_POINTER_CONVERT(updated_stack_start); +#endif + + /* Prepare the thread control block prior to placing it on the created + list. */ + + /* Initialize thread control block to all zeros. */ + TX_MEMSET(thread_ptr, 0, (sizeof(TX_THREAD))); + + /* Place the supplied parameters into the thread's control block. */ + thread_ptr -> tx_thread_name = name_ptr; + thread_ptr -> tx_thread_entry = entry_function; + thread_ptr -> tx_thread_entry_parameter = entry_input; + thread_ptr -> tx_thread_stack_start = stack_start; + thread_ptr -> tx_thread_stack_size = stack_size; + thread_ptr -> tx_thread_stack_end = (VOID *) (TX_UCHAR_POINTER_ADD(stack_start, (stack_size - ((ULONG) 1)))); + thread_ptr -> tx_thread_priority = priority; + thread_ptr -> tx_thread_user_priority = priority; + thread_ptr -> tx_thread_time_slice = time_slice; + thread_ptr -> tx_thread_new_time_slice = time_slice; + thread_ptr -> tx_thread_inherit_priority = ((UINT) TX_MAX_PRIORITIES); + + /* Calculate the end of the thread's stack area. */ + temp_ptr = TX_VOID_TO_UCHAR_POINTER_CONVERT(stack_start); + temp_ptr = (TX_UCHAR_POINTER_ADD(temp_ptr, (stack_size - ((ULONG) 1)))); + thread_ptr -> tx_thread_stack_end = TX_UCHAR_TO_VOID_POINTER_CONVERT(temp_ptr); + +#ifndef TX_DISABLE_PREEMPTION_THRESHOLD + + /* Preemption-threshold is enabled, setup accordingly. */ + thread_ptr -> tx_thread_preempt_threshold = preempt_threshold; + thread_ptr -> tx_thread_user_preempt_threshold = preempt_threshold; +#else + + /* Preemption-threshold is disabled, determine if preemption-threshold was required. */ + if (priority != preempt_threshold) + { + + /* Preemption-threshold specified. Since specific preemption-threshold is not supported, + disable all preemption. */ + thread_ptr -> tx_thread_preempt_threshold = ((UINT) 0); + thread_ptr -> tx_thread_user_preempt_threshold = ((UINT) 0); + } + else + { + + /* Preemption-threshold is not specified, just setup with the priority. */ + thread_ptr -> tx_thread_preempt_threshold = priority; + thread_ptr -> tx_thread_user_preempt_threshold = priority; + } +#endif + + /* Now fill in the values that are required for thread initialization. */ + thread_ptr -> tx_thread_state = TX_SUSPENDED; + + /* Setup the necessary fields in the thread timer block. */ + TX_THREAD_CREATE_TIMEOUT_SETUP(thread_ptr) + + /* Perform any additional thread setup activities for tool or user purpose. */ + TX_THREAD_CREATE_INTERNAL_EXTENSION(thread_ptr) + + /* Call the target specific stack frame building routine to build the + thread's initial stack and to setup the actual stack pointer in the + control block. */ + _tx_thread_stack_build(thread_ptr, _tx_thread_shell_entry); + +#ifdef TX_ENABLE_STACK_CHECKING + + /* Setup the highest usage stack pointer. */ + thread_ptr -> tx_thread_stack_highest_ptr = thread_ptr -> tx_thread_stack_ptr; +#endif + + /* Prepare to make this thread a member of the created thread list. */ + TX_DISABLE + + /* Load the thread ID field in the thread control block. */ + thread_ptr -> tx_thread_id = TX_THREAD_ID; + + /* Place the thread on the list of created threads. First, + check for an empty list. */ + if (_tx_thread_created_count == TX_EMPTY) + { + + /* The created thread list is empty. Add thread to empty list. */ + _tx_thread_created_ptr = thread_ptr; + thread_ptr -> tx_thread_created_next = thread_ptr; + thread_ptr -> tx_thread_created_previous = thread_ptr; + } + else + { + + /* This list is not NULL, add to the end of the list. */ + next_thread = _tx_thread_created_ptr; + previous_thread = next_thread -> tx_thread_created_previous; + + /* Place the new thread in the list. */ + next_thread -> tx_thread_created_previous = thread_ptr; + previous_thread -> tx_thread_created_next = thread_ptr; + + /* Setup this thread's created links. */ + thread_ptr -> tx_thread_created_previous = previous_thread; + thread_ptr -> tx_thread_created_next = next_thread; + } + + /* Increment the thread created count. */ + _tx_thread_created_count++; + + /* If trace is enabled, register this object. */ + TX_TRACE_OBJECT_REGISTER(TX_TRACE_OBJECT_TYPE_THREAD, thread_ptr, name_ptr, TX_POINTER_TO_ULONG_CONVERT(stack_start), stack_size) + + /* If trace is enabled, insert this event into the trace buffer. */ + TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_CREATE, thread_ptr, priority, TX_POINTER_TO_ULONG_CONVERT(stack_start), stack_size, TX_TRACE_THREAD_EVENTS) + + /* Register thread in the thread array structure. */ + TX_EL_THREAD_REGISTER(thread_ptr) + + /* Log this kernel call. */ + TX_EL_THREAD_CREATE_INSERT + +#ifndef TX_NOT_INTERRUPTABLE + + /* Temporarily disable preemption. */ + _tx_thread_preempt_disable++; +#endif + + /* Determine if an automatic start was requested. If so, call the resume + thread function and then check for a preemption condition. */ + if (auto_start == TX_AUTO_START) + { + + /* Determine if the create call is being called from initialization. */ + if (TX_THREAD_GET_SYSTEM_STATE() >= TX_INITIALIZE_IN_PROGRESS) + { + + /* Yes, this create call was made from initialization. */ + + /* Pickup the current thread execute pointer, which corresponds to the + highest priority thread ready to execute. Interrupt lockout is + not required, since interrupts are assumed to be disabled during + initialization. */ + saved_thread_ptr = _tx_thread_execute_ptr; + + /* Determine if there is thread ready for execution. */ + if (saved_thread_ptr != TX_NULL) + { + + /* Yes, a thread is ready for execution when initialization completes. */ + + /* Save the current preemption-threshold. */ + saved_threshold = saved_thread_ptr -> tx_thread_preempt_threshold; + + /* For initialization, temporarily set the preemption-threshold to the + priority level to make sure the highest-priority thread runs once + initialization is complete. */ + saved_thread_ptr -> tx_thread_preempt_threshold = saved_thread_ptr -> tx_thread_priority; + } + } + else + { + + /* Simply set the saved thread pointer to NULL. */ + saved_thread_ptr = TX_NULL; + } + +#ifdef TX_NOT_INTERRUPTABLE + + /* Perform any additional activities for tool or user purpose. */ + TX_THREAD_CREATE_EXTENSION(thread_ptr) + + /* Resume the thread! */ + _tx_thread_system_ni_resume(thread_ptr); + + /* Restore previous interrupt posture. */ + TX_RESTORE +#else + + /* Restore previous interrupt posture. */ + TX_RESTORE + + /* Perform any additional activities for tool or user purpose. */ + TX_THREAD_CREATE_EXTENSION(thread_ptr) + + /* Call the resume thread function to make this thread ready. */ + _tx_thread_system_resume(thread_ptr); +#endif + + /* Determine if the thread's preemption-threshold needs to be restored. */ + if (saved_thread_ptr != TX_NULL) + { + + /* Yes, restore the previous highest-priority thread's preemption-threshold. This + can only happen if this routine is called from initialization. */ + saved_thread_ptr -> tx_thread_preempt_threshold = saved_threshold; + } + } + else + { + +#ifdef TX_NOT_INTERRUPTABLE + + /* Perform any additional activities for tool or user purpose. */ + TX_THREAD_CREATE_EXTENSION(thread_ptr) + + /* Restore interrupts. */ + TX_RESTORE +#else + + /* Restore interrupts. */ + TX_RESTORE + + /* Perform any additional activities for tool or user purpose. */ + TX_THREAD_CREATE_EXTENSION(thread_ptr) + + /* Disable interrupts. */ + TX_DISABLE + + /* Re-enable preemption. */ + _tx_thread_preempt_disable--; + + /* Restore interrupts. */ + TX_RESTORE + + /* Check for preemption. */ + _tx_thread_system_preempt_check(); +#endif + } + + /* Always return a success. */ + return(TX_SUCCESS); +} + +UINT _tx_mutex_get(TX_MUTEX *mutex_ptr, ULONG wait_option) +{ + +TX_INTERRUPT_SAVE_AREA + +TX_THREAD *thread_ptr; +TX_MUTEX *next_mutex; +TX_MUTEX *previous_mutex; +TX_THREAD *mutex_owner; +TX_THREAD *next_thread; +TX_THREAD *previous_thread; +UINT status; +UX_TEST_OVERRIDE_TX_MUTEX_GET_PARAMS action_params = { mutex_ptr, wait_option }; +UX_TEST_ACTION action; + + /* Perform hooked callbacks. */ + ux_test_do_hooks_before(UX_TEST_OVERRIDE_TX_MUTEX_GET, &action_params); + + /* Perform action. */ + action = ux_test_action_handler(UX_TEST_OVERRIDE_TX_MUTEX_GET, &action_params); + ux_test_do_action_before(&action, &action_params); + + /* Disable interrupts to get an instance from the mutex. */ + TX_DISABLE + +#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO + + /* Increment the total mutex get counter. */ + _tx_mutex_performance_get_count++; + + /* Increment the number of attempts to get this mutex. */ + mutex_ptr -> tx_mutex_performance_get_count++; +#endif + + /* If trace is enabled, insert this event into the trace buffer. */ + TX_TRACE_IN_LINE_INSERT(TX_TRACE_MUTEX_GET, mutex_ptr, wait_option, TX_POINTER_TO_ULONG_CONVERT(mutex_ptr -> tx_mutex_owner), mutex_ptr -> tx_mutex_ownership_count, TX_TRACE_MUTEX_EVENTS) + + /* Log this kernel call. */ + TX_EL_MUTEX_GET_INSERT + + /* Pickup thread pointer. */ + TX_THREAD_GET_CURRENT(thread_ptr) + + /* Determine if this mutex is available. */ + if (mutex_ptr -> tx_mutex_ownership_count == ((UINT) 0)) + { + + /* Set the ownership count to 1. */ + mutex_ptr -> tx_mutex_ownership_count = ((UINT) 1); + + /* Remember that the calling thread owns the mutex. */ + mutex_ptr -> tx_mutex_owner = thread_ptr; + + /* Determine if the thread pointer is valid. */ + if (thread_ptr != TX_NULL) + { + + /* Determine if priority inheritance is required. */ + if (mutex_ptr -> tx_mutex_inherit == TX_TRUE) + { + + /* Remember the current priority of thread. */ + mutex_ptr -> tx_mutex_original_priority = thread_ptr -> tx_thread_priority; + + /* Setup the highest priority waiting thread. */ + mutex_ptr -> tx_mutex_highest_priority_waiting = ((UINT) TX_MAX_PRIORITIES); + } + + /* Pickup next mutex pointer, which is the head of the list. */ + next_mutex = thread_ptr -> tx_thread_owned_mutex_list; + + /* Determine if this thread owns any other mutexes that have priority inheritance. */ + if (next_mutex != TX_NULL) + { + + /* Non-empty list. Link up the mutex. */ + + /* Pickup the next and previous mutex pointer. */ + previous_mutex = next_mutex -> tx_mutex_owned_previous; + + /* Place the owned mutex in the list. */ + next_mutex -> tx_mutex_owned_previous = mutex_ptr; + previous_mutex -> tx_mutex_owned_next = mutex_ptr; + + /* Setup this mutex's next and previous created links. */ + mutex_ptr -> tx_mutex_owned_previous = previous_mutex; + mutex_ptr -> tx_mutex_owned_next = next_mutex; + } + else + { + + /* The owned mutex list is empty. Add mutex to empty list. */ + thread_ptr -> tx_thread_owned_mutex_list = mutex_ptr; + mutex_ptr -> tx_mutex_owned_next = mutex_ptr; + mutex_ptr -> tx_mutex_owned_previous = mutex_ptr; + } + + /* Increment the number of mutexes owned counter. */ + thread_ptr -> tx_thread_owned_mutex_count++; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Return success. */ + status = TX_SUCCESS; + } + + /* Otherwise, see if the owning thread is trying to obtain the same mutex. */ + else if (mutex_ptr -> tx_mutex_owner == thread_ptr) + { + + /* The owning thread is requesting the mutex again, just + increment the ownership count. */ + mutex_ptr -> tx_mutex_ownership_count++; + + /* Restore interrupts. */ + TX_RESTORE + + /* Return success. */ + status = TX_SUCCESS; + } + else + { + + /* Determine if the request specifies suspension. */ + if (wait_option != TX_NO_WAIT) + { + + /* Prepare for suspension of this thread. */ + + /* Pickup the mutex owner. */ + mutex_owner = mutex_ptr -> tx_mutex_owner; + +#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO + + /* Increment the total mutex suspension counter. */ + _tx_mutex_performance_suspension_count++; + + /* Increment the number of suspensions on this mutex. */ + mutex_ptr -> tx_mutex_performance_suspension_count++; + + /* Determine if a priority inversion is present. */ + if (thread_ptr -> tx_thread_priority < mutex_owner -> tx_thread_priority) + { + + /* Yes, priority inversion is present! */ + + /* Increment the total mutex priority inversions counter. */ + _tx_mutex_performance_priority_inversion_count++; + + /* Increment the number of priority inversions on this mutex. */ + mutex_ptr -> tx_mutex_performance_priority_inversion_count++; + +#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO + + /* Increment the number of total thread priority inversions. */ + _tx_thread_performance_priority_inversion_count++; + + /* Increment the number of priority inversions for this thread. */ + thread_ptr -> tx_thread_performance_priority_inversion_count++; +#endif + } +#endif + + /* Setup cleanup routine pointer. */ + thread_ptr -> tx_thread_suspend_cleanup = &(_tx_mutex_cleanup); + + /* Setup cleanup information, i.e. this mutex control + block. */ + thread_ptr -> tx_thread_suspend_control_block = (VOID *) mutex_ptr; + + /* Setup suspension list. */ + if (mutex_ptr -> tx_mutex_suspended_count == TX_NO_SUSPENSIONS) + { + + /* No other threads are suspended. Setup the head pointer and + just setup this threads pointers to itself. */ + mutex_ptr -> tx_mutex_suspension_list = thread_ptr; + thread_ptr -> tx_thread_suspended_next = thread_ptr; + thread_ptr -> tx_thread_suspended_previous = thread_ptr; + } + else + { + + /* This list is not NULL, add current thread to the end. */ + next_thread = mutex_ptr -> tx_mutex_suspension_list; + thread_ptr -> tx_thread_suspended_next = next_thread; + previous_thread = next_thread -> tx_thread_suspended_previous; + thread_ptr -> tx_thread_suspended_previous = previous_thread; + previous_thread -> tx_thread_suspended_next = thread_ptr; + next_thread -> tx_thread_suspended_previous = thread_ptr; + } + + /* Increment the suspension count. */ + mutex_ptr -> tx_mutex_suspended_count++; + + /* Set the state to suspended. */ + thread_ptr -> tx_thread_state = TX_MUTEX_SUSP; + +#ifdef TX_NOT_INTERRUPTABLE + + /* Determine if we need to raise the priority of the thread + owning the mutex. */ + if (mutex_ptr -> tx_mutex_inherit == TX_TRUE) + { + + /* Determine if this is the highest priority to raise for this mutex. */ + if (mutex_ptr -> tx_mutex_highest_priority_waiting > thread_ptr -> tx_thread_priority) + { + + /* Remember this priority. */ + mutex_ptr -> tx_mutex_highest_priority_waiting = thread_ptr -> tx_thread_priority; + } + + /* Priority inheritance is requested, check to see if the thread that owns the mutex is lower priority. */ + if (mutex_owner -> tx_thread_priority > thread_ptr -> tx_thread_priority) + { + + /* Yes, raise the suspended, owning thread's priority to that + of the current thread. */ + _tx_mutex_priority_change(mutex_owner, thread_ptr -> tx_thread_priority); + +#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO + + /* Increment the total mutex priority inheritance counter. */ + _tx_mutex_performance__priority_inheritance_count++; + + /* Increment the number of priority inheritance situations on this mutex. */ + mutex_ptr -> tx_mutex_performance__priority_inheritance_count++; +#endif + } + } + + /* Call actual non-interruptable thread suspension routine. */ + _tx_thread_system_ni_suspend(thread_ptr, wait_option); + + /* Restore interrupts. */ + TX_RESTORE +#else + + /* Set the suspending flag. */ + thread_ptr -> tx_thread_suspending = TX_TRUE; + + /* Setup the timeout period. */ + thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = wait_option; + + /* Temporarily disable preemption. */ + _tx_thread_preempt_disable++; + + /* Restore interrupts. */ + TX_RESTORE + + /* Determine if we need to raise the priority of the thread + owning the mutex. */ + if (mutex_ptr -> tx_mutex_inherit == TX_TRUE) + { + + /* Determine if this is the highest priority to raise for this mutex. */ + if (mutex_ptr -> tx_mutex_highest_priority_waiting > thread_ptr -> tx_thread_priority) + { + + /* Remember this priority. */ + mutex_ptr -> tx_mutex_highest_priority_waiting = thread_ptr -> tx_thread_priority; + } + + /* Priority inheritance is requested, check to see if the thread that owns the mutex is lower priority. */ + if (mutex_owner -> tx_thread_priority > thread_ptr -> tx_thread_priority) + { + + /* Yes, raise the suspended, owning thread's priority to that + of the current thread. */ + _tx_mutex_priority_change(mutex_owner, thread_ptr -> tx_thread_priority); + +#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO + + /* Increment the total mutex priority inheritance counter. */ + _tx_mutex_performance__priority_inheritance_count++; + + /* Increment the number of priority inheritance situations on this mutex. */ + mutex_ptr -> tx_mutex_performance__priority_inheritance_count++; +#endif + } + } + + /* Call actual thread suspension routine. */ + _tx_thread_system_suspend(thread_ptr); +#endif + /* Return the completion status. */ + status = thread_ptr -> tx_thread_suspend_status; + } + else + { + + /* Restore interrupts. */ + TX_RESTORE + + /* Immediate return, return error completion. */ + status = TX_NOT_AVAILABLE; + } + } + + ux_test_do_action_after(&action, &action_params); + + /* Perform hooked callbacks. */ + ux_test_do_hooks_after(UX_TEST_OVERRIDE_TX_MUTEX_GET, &action_params); + + /* Return completion status. */ + return(status); +} + +/* Re-target the _ux_utility_memory_allocate for testing */ + +VOID ux_test_utility_sim_mem_alloc_log_enable(UCHAR enable_disable) +{ + if (enable_disable) + { + mem_alloc_fail_after = FAIL_DISABLE; + mem_alloc_count = 0; + mem_alloc_do_fail = UX_FALSE; + + ux_system_mutex_on_count = 0; + ux_system_mutex_off_count = 0; + ux_system_mutex_alloc_logs_count = 0; + ux_system_mutex_alloc_logs_match = 0; + ux_system_mutex_alloc_logs_area = UX_FALSE; + ux_system_mutex_alloc_logs_lock = UX_FALSE; + _ux_utility_memory_set(ux_system_mutex_alloc_logs, 0, sizeof(ux_system_mutex_alloc_logs)); + + ux_test_link_hooks_from_array(ux_system_mutex_hooks); + } + else + { + ux_test_remove_hooks_from_array(ux_system_mutex_hooks); + } +} + +VOID ux_test_utility_sim_mem_alloc_log_lock(VOID) +{ + ux_system_mutex_alloc_logs_lock = UX_TRUE; +#if 0 /* TODO: Dump mem alloc log map. */ + printf("Lock mem log map, %ld area:\n", ux_system_mutex_alloc_logs_count + 1); + for (int i = 0; i <= ux_system_mutex_alloc_logs_count; i ++) + { + printf(" : %6ld ~ %6ld\n", ux_system_mutex_alloc_logs[i].first_count, ux_system_mutex_alloc_logs[i].last_count); + } +#endif +} + +ULONG ux_test_utility_sim_mem_alloc_count(VOID) +{ + return mem_alloc_count; +} + +VOID ux_test_utility_sim_mem_alloc_count_reset(VOID) +{ + mem_alloc_fail_after = FAIL_DISABLE; + mem_alloc_do_fail = UX_FALSE; + mem_alloc_count = 0; + + ux_system_mutex_off_count = 0; + ux_system_mutex_on_count = 0; + + ux_system_mutex_alloc_logs_count = 0; + ux_system_mutex_alloc_logs_area = UX_FALSE; + ux_system_mutex_alloc_logs_lock = UX_FALSE; + _ux_utility_memory_set(ux_system_mutex_alloc_logs, 0, sizeof(ux_system_mutex_alloc_logs)); +} + +VOID ux_test_utility_sim_mem_alloc_error_generation_start(ULONG fail_after) +{ + + mem_alloc_count = 0; + mem_alloc_do_fail = UX_FALSE; + + ux_system_mutex_off_count = 0; + ux_system_mutex_on_count = 0; + + ux_system_mutex_alloc_logs_match = 0; + + mem_alloc_fail_after = fail_after; +} + +VOID ux_test_utility_sim_mem_alloc_error_generation_stop(VOID) +{ + + mem_alloc_fail_after = FAIL_DISABLE; + mem_alloc_count = 0; + + ux_system_mutex_off_count = 0; + ux_system_mutex_on_count = 0; +} + +UINT ux_test_utility_sim_mem_alloc_error_generation_active(VOID) +{ + if (mem_alloc_fail_after == FAIL_DISABLE) + return UX_ERROR; + if (mem_alloc_count >= mem_alloc_fail_after) + return UX_SUCCESS; + return UX_ERROR; +} + +/* Override. */ +UINT _tx_thread_preemption_change(TX_THREAD *thread_ptr, UINT new_threshold, UINT *old_threshold) +{ + +TX_INTERRUPT_SAVE_AREA + +#ifndef TX_DISABLE_PREEMPTION_THRESHOLD +ULONG priority_bit; +#if TX_MAX_PRIORITIES > 32 +UINT map_index; +#endif +#endif +UINT status; +UX_TEST_OVERRIDE_TX_THREAD_PREEMPTION_CHANGE_PARAMS params = { thread_ptr, new_threshold }; +UX_TEST_ACTION action; + + + action = ux_test_action_handler(UX_TEST_OVERRIDE_TX_THREAD_PREEMPTION_CHANGE, ¶ms); + ux_test_do_action_before(&action, ¶ms); + + /* Default status to success. */ + status = TX_SUCCESS; + +#ifdef TX_DISABLE_PREEMPTION_THRESHOLD + + /* Only allow 0 (disable all preemption) and returning preemption-threshold to the + current thread priority if preemption-threshold is disabled. All other threshold + values are converted to 0. */ + if (thread_ptr -> tx_thread_user_priority != new_threshold) + { + + /* Is the new threshold zero? */ + if (new_threshold != ((UINT) 0)) + { + + /* Convert the new threshold to disable all preemption, since preemption-threshold is + not supported. */ + new_threshold = ((UINT) 0); + } + } +#endif + + /* Lockout interrupts while the thread is being resumed. */ + TX_DISABLE + + /* If trace is enabled, insert this event into the trace buffer. */ + TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_PREEMPTION_CHANGE, thread_ptr, new_threshold, thread_ptr -> tx_thread_preempt_threshold, thread_ptr -> tx_thread_state, TX_TRACE_THREAD_EVENTS) + + /* Log this kernel call. */ + TX_EL_THREAD_PREEMPTION_CHANGE_INSERT + + /* Determine if the new threshold is greater than the current user priority. */ + if (new_threshold > thread_ptr -> tx_thread_user_priority) + { + + /* Return error. */ + status = TX_THRESH_ERROR; + } + else + { + +#ifndef TX_DISABLE_PREEMPTION_THRESHOLD + + /* Determine if the new threshold is the same as the priority. */ + if (thread_ptr -> tx_thread_user_priority == new_threshold) + { + + /* Determine if this thread is at the head of the list. */ + if (_tx_thread_priority_list[thread_ptr -> tx_thread_priority] == thread_ptr) + { + +#if TX_MAX_PRIORITIES > 32 + + /* Calculate the index into the bit map array. */ + map_index = (thread_ptr -> tx_thread_priority)/((UINT) 32); +#endif + + /* Yes, this thread is at the front of the list. Make sure + the preempted bit is cleared for this thread. */ + TX_MOD32_BIT_SET(thread_ptr -> tx_thread_priority, priority_bit) + _tx_thread_preempted_maps[MAP_INDEX] = _tx_thread_preempted_maps[MAP_INDEX] & (~(priority_bit)); + +#if TX_MAX_PRIORITIES > 32 + + /* Determine if there are any other bits set in this preempt map. */ + if (_tx_thread_preempted_maps[MAP_INDEX] == ((ULONG) 0)) + { + + /* No, clear the active bit to signify this preempt map has nothing set. */ + TX_DIV32_BIT_SET(thread_ptr -> tx_thread_priority, priority_bit) + _tx_thread_preempted_map_active = _tx_thread_preempted_map_active & (~(priority_bit)); + } +#endif + } + } +#endif + + /* Return the user's preemption-threshold. */ + *old_threshold = thread_ptr -> tx_thread_user_preempt_threshold; + + /* Setup the new threshold. */ + thread_ptr -> tx_thread_user_preempt_threshold = new_threshold; + + /* Determine if the new threshold represents a higher priority than the priority inheritance threshold. */ + if (new_threshold < thread_ptr -> tx_thread_inherit_priority) + { + + /* Update the actual preemption-threshold with the new threshold. */ + thread_ptr -> tx_thread_preempt_threshold = new_threshold; + } + else + { + + /* Update the actual preemption-threshold with the priority inheritance. */ + thread_ptr -> tx_thread_preempt_threshold = thread_ptr -> tx_thread_inherit_priority; + } + + /* Is the thread priority less than the current highest priority? If not, no preemption is required. */ + if (_tx_thread_highest_priority < thread_ptr -> tx_thread_priority) + { + + /* Is the new thread preemption-threshold less than the current highest priority? If not, no preemption is required. */ + if (_tx_thread_highest_priority < new_threshold) + { + + /* If the current execute pointer is the same at this thread, preemption needs to take place. */ + if (_tx_thread_execute_ptr == thread_ptr) + { + + /* Preemption needs to take place. */ + +#ifndef TX_DISABLE_PREEMPTION_THRESHOLD + + /* Determine if this thread has preemption threshold set. */ + if (thread_ptr -> tx_thread_preempt_threshold != thread_ptr -> tx_thread_priority) + { + +#if TX_MAX_PRIORITIES > 32 + + /* Calculate the index into the bit map array. */ + map_index = (thread_ptr -> tx_thread_priority)/((UINT) 32); + + /* Set the active bit to remember that the preempt map has something set. */ + TX_DIV32_BIT_SET(thread_ptr -> tx_thread_priority, priority_bit) + _tx_thread_preempted_map_active = _tx_thread_preempted_map_active | priority_bit; +#endif + + /* Remember that this thread was preempted by a thread above the thread's threshold. */ + TX_MOD32_BIT_SET(thread_ptr -> tx_thread_priority, priority_bit) + _tx_thread_preempted_maps[MAP_INDEX] = _tx_thread_preempted_maps[MAP_INDEX] | priority_bit; + } +#endif + +#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO + + /* Determine if the caller is an interrupt or from a thread. */ + if (TX_THREAD_GET_SYSTEM_STATE() == ((ULONG) 0)) + { + + /* Caller is a thread, so this is a solicited preemption. */ + _tx_thread_performance_solicited_preemption_count++; + + /* Increment the thread's solicited preemption counter. */ + thread_ptr -> tx_thread_performance_solicited_preemption_count++; + } + + /* Remember the thread that preempted this thread. */ + thread_ptr -> tx_thread_performance_last_preempting_thread = _tx_thread_priority_list[_tx_thread_highest_priority]; + + /* Is the execute pointer different? */ + if (_tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] != _tx_thread_execute_ptr) + { + + /* Move to next entry. */ + _tx_thread_performance__execute_log_index++; + + /* Check for wrap condition. */ + if (_tx_thread_performance__execute_log_index >= TX_THREAD_EXECUTE_LOG_SIZE) + { + + /* Set the index to the beginning. */ + _tx_thread_performance__execute_log_index = ((UINT) 0); + } + + /* Log the new execute pointer. */ + _tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] = _tx_thread_execute_ptr; + } +#endif + + /* Setup the highest priority thread to execute. */ + _tx_thread_execute_ptr = _tx_thread_priority_list[_tx_thread_highest_priority]; + + /* Restore interrupts. */ + TX_RESTORE + + /* Check for preemption. */ + _tx_thread_system_preempt_check(); + + /* Disable interrupts. */ + TX_DISABLE + } + } + } + } + + /* Restore interrupts. */ + TX_RESTORE + + ux_test_do_action_after(&action, ¶ms); + + /* Return completion status. */ + return(status); +} + +static void ux_system_mutex_create_callback(UX_TEST_ACTION *action, VOID *params) +{ +UX_TEST_OVERRIDE_TX_MUTEX_CREATE_PARAMS *mutex_create_param = params; + + /* Log mutex pointer. */ + ux_system_mutex_hooks[1].mutex_ptr = mutex_create_param->mutex_ptr; + ux_system_mutex_hooks[2].mutex_ptr = mutex_create_param->mutex_ptr; + + ux_system_mutex_off_count = 0; + ux_system_mutex_on_count = 0; + + mem_alloc_count = 0; +} + +static void ux_system_mutex_get_callback(UX_TEST_ACTION *action, VOID *params) +{ +UX_TEST_OVERRIDE_TX_MUTEX_GET_PARAMS *mutex_create_param = params; +ULONG this_count = ux_system_mutex_on_count; + + if (ux_system_mutex_callback_skip) + return; + + ux_system_mutex_on_count ++; + + rmem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + cmem_free = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available; + + /* Just return if error generation is disabled. */ + if (mem_alloc_fail_after == FAIL_DISABLE) + return; + + /* Always fail if we are short of logs. */ + /* When failing started, never stop it. */ + if (ux_system_mutex_alloc_logs_match > ux_system_mutex_alloc_logs_count || mem_alloc_do_fail == UX_TRUE) + mem_alloc_do_fail = UX_TRUE; + + /* Check log baseline to increase memory allocate count. */ + else if (this_count >= ux_system_mutex_alloc_logs[ux_system_mutex_alloc_logs_match].first_count && + this_count <= ux_system_mutex_alloc_logs[ux_system_mutex_alloc_logs_match].last_count) + { + /* Consume all memory if we will generate memory allocation error. */ + if (mem_alloc_count >= mem_alloc_fail_after) + { + // printf("%s:%d malloc error start @ %ld (%ld)\n", __FILE__, __LINE__, this_count, mem_alloc_count); + mem_alloc_do_fail = UX_TRUE; + } + mem_alloc_count ++; + + if (ux_system_mutex_on_count > ux_system_mutex_alloc_logs[ux_system_mutex_alloc_logs_match].last_count) + { + ux_system_mutex_alloc_logs_match ++; + } + } + + if (mem_alloc_do_fail) + { + ux_system_mutex_callback_skip = UX_TRUE; + ux_test_utility_sim_mem_allocate_until_flagged(0, UX_REGULAR_MEMORY); + ux_test_utility_sim_mem_allocate_until_flagged(0, UX_CACHE_SAFE_MEMORY); + ux_system_mutex_callback_skip = UX_FALSE; + } +} + +static void ux_system_mutex_put_callback(UX_TEST_ACTION *action, VOID *params) +{ +UX_TEST_OVERRIDE_TX_MUTEX_PUT_PARAMS *mutex_create_param = params; +ULONG this_count = ux_system_mutex_off_count; + + if (ux_system_mutex_callback_skip) + return; + + ux_system_mutex_off_count ++; + UX_TEST_ASSERT(ux_system_mutex_on_count == ux_system_mutex_off_count); + + if (mem_alloc_do_fail) + { + ux_system_mutex_callback_skip = UX_TRUE; + ux_test_utility_sim_mem_free_all_flagged(UX_REGULAR_MEMORY); + ux_test_utility_sim_mem_free_all_flagged(UX_CACHE_SAFE_MEMORY); + ux_system_mutex_callback_skip = UX_FALSE; + } + + /* We stop logging when generating errors. */ + if (mem_alloc_fail_after != FAIL_DISABLE) + return; + + /* We stop logging when it's locked. */ + if (ux_system_mutex_alloc_logs_lock) + return; + + /* It's memory allocate, if memory level down. */ + if (_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available < rmem_free || + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available < cmem_free) + { + /* Memory allocate count. */ + mem_alloc_count ++; + + /* Log memory allocate count. */ + if (ux_system_mutex_alloc_logs_area == UX_FALSE) + { + ux_system_mutex_alloc_logs_area = UX_TRUE; + ux_system_mutex_alloc_logs[ux_system_mutex_alloc_logs_count].first_count = this_count; + } + ux_system_mutex_alloc_logs[ux_system_mutex_alloc_logs_count].last_count = this_count; + } + else if(ux_system_mutex_alloc_logs_area == UX_TRUE) + { + ux_system_mutex_alloc_logs_area = UX_FALSE; + + UX_TEST_ASSERT(ux_system_mutex_alloc_logs_count != (SYSTEM_MUTEX_ALLOC_LOG_SIZE - 1)); + if (ux_system_mutex_alloc_logs_count < SYSTEM_MUTEX_ALLOC_LOG_SIZE - 1) + { + ux_system_mutex_alloc_logs_count ++; + } + else + { + ux_system_mutex_alloc_logs_lock = UX_TRUE; + } + } +} + +UINT _tx_mutex_put(TX_MUTEX *mutex_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + +TX_THREAD *thread_ptr; +TX_THREAD *old_owner; +UINT old_priority; +UINT status; +TX_MUTEX *next_mutex; +TX_MUTEX *previous_mutex; +UINT owned_count; +UINT suspended_count; +TX_THREAD *current_thread; +TX_THREAD *next_thread; +TX_THREAD *previous_thread; +TX_THREAD *suspended_thread; +UX_TEST_OVERRIDE_TX_MUTEX_PUT_PARAMS action_params = {mutex_ptr}; + + /* Perform hooked callbacks. */ + ux_test_do_hooks_before(UX_TEST_OVERRIDE_TX_MUTEX_PUT, &action_params); + + /* Setup status to indicate the processing is not complete. */ + status = TX_NOT_DONE; + + /* Disable interrupts to put an instance back to the mutex. */ + TX_DISABLE + +#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO + + /* Increment the total mutex put counter. */ + _tx_mutex_performance_put_count++; + + /* Increment the number of attempts to put this mutex. */ + mutex_ptr -> tx_mutex_performance_put_count++; +#endif + + /* If trace is enabled, insert this event into the trace buffer. */ + TX_TRACE_IN_LINE_INSERT(TX_TRACE_MUTEX_PUT, mutex_ptr, TX_POINTER_TO_ULONG_CONVERT(mutex_ptr -> tx_mutex_owner), mutex_ptr -> tx_mutex_ownership_count, TX_POINTER_TO_ULONG_CONVERT(&old_priority), TX_TRACE_MUTEX_EVENTS) + + /* Log this kernel call. */ + TX_EL_MUTEX_PUT_INSERT + + /* Determine if this mutex is owned. */ + if (mutex_ptr -> tx_mutex_ownership_count != ((UINT) 0)) + { + + /* Pickup the owning thread pointer. */ + thread_ptr = mutex_ptr -> tx_mutex_owner; + + /* Pickup thread pointer. */ + TX_THREAD_GET_CURRENT(current_thread) + + /* Check to see if the mutex is owned by the calling thread. */ + if (mutex_ptr -> tx_mutex_owner != current_thread) + { + + /* Determine if the preempt disable flag is set, indicating that + the caller is not the application but from ThreadX. In such + cases, the thread mutex owner does not need to match. */ + if (_tx_thread_preempt_disable == ((UINT) 0)) + { + + /* Invalid mutex release. */ + + /* Restore interrupts. */ + TX_RESTORE + + /* Caller does not own the mutex. */ + status = TX_NOT_OWNED; + } + } + + /* Determine if we should continue. */ + if (status == TX_NOT_DONE) + { + + /* Decrement the mutex ownership count. */ + mutex_ptr -> tx_mutex_ownership_count--; + + /* Determine if the mutex is still owned by the current thread. */ + if (mutex_ptr -> tx_mutex_ownership_count != ((UINT) 0)) + { + + /* Restore interrupts. */ + TX_RESTORE + + /* Mutex is still owned, just return successful status. */ + status = TX_SUCCESS; + } + else + { + + /* Check for a NULL thread pointer, which can only happen during initialization. */ + if (thread_ptr == TX_NULL) + { + + /* Restore interrupts. */ + TX_RESTORE + + /* Mutex is now available, return successful status. */ + status = TX_SUCCESS; + } + else + { + + /* The mutex is now available. */ + + /* Remove this mutex from the owned mutex list. */ + + /* Decrement the ownership count. */ + thread_ptr -> tx_thread_owned_mutex_count--; + + /* Determine if this mutex was the only one on the list. */ + if (thread_ptr -> tx_thread_owned_mutex_count == ((UINT) 0)) + { + + /* Yes, the list is empty. Simply set the head pointer to NULL. */ + thread_ptr -> tx_thread_owned_mutex_list = TX_NULL; + } + else + { + + /* No, there are more mutexes on the list. */ + + /* Link-up the neighbors. */ + next_mutex = mutex_ptr -> tx_mutex_owned_next; + previous_mutex = mutex_ptr -> tx_mutex_owned_previous; + next_mutex -> tx_mutex_owned_previous = previous_mutex; + previous_mutex -> tx_mutex_owned_next = next_mutex; + + /* See if we have to update the created list head pointer. */ + if (thread_ptr -> tx_thread_owned_mutex_list == mutex_ptr) + { + + /* Yes, move the head pointer to the next link. */ + thread_ptr -> tx_thread_owned_mutex_list = next_mutex; + } + } + + /* Determine if the simple, non-suspension, non-priority inheritance case is present. */ + if (mutex_ptr -> tx_mutex_suspension_list == TX_NULL) + { + + /* Is this a priority inheritance mutex? */ + if (mutex_ptr -> tx_mutex_inherit == TX_FALSE) + { + + /* Yes, we are done - set the mutex owner to NULL. */ + mutex_ptr -> tx_mutex_owner = TX_NULL; + + /* Restore interrupts. */ + TX_RESTORE + + /* Mutex is now available, return successful status. */ + status = TX_SUCCESS; + } + } + + /* Determine if the processing is complete. */ + if (status == TX_NOT_DONE) + { + + /* Initialize original owner and thread priority. */ + old_owner = TX_NULL; + old_priority = thread_ptr -> tx_thread_user_priority; + + /* Does this mutex support priority inheritance? */ + if (mutex_ptr -> tx_mutex_inherit == TX_TRUE) + { + +#ifndef TX_NOT_INTERRUPTABLE + + /* Temporarily disable preemption. */ + _tx_thread_preempt_disable++; + + /* Restore interrupts. */ + TX_RESTORE +#endif + + /* Search the owned mutexes for this thread to determine the highest priority for this + former mutex owner to return to. */ + next_mutex = thread_ptr -> tx_thread_owned_mutex_list; + while (next_mutex != TX_NULL) + { + + /* Does this mutex support priority inheritance? */ + if (next_mutex -> tx_mutex_inherit == TX_TRUE) + { + + /* Determine if highest priority field of the mutex is higher than the priority to + restore. */ + if (next_mutex -> tx_mutex_highest_priority_waiting < old_priority) + { + + /* Use this priority to return releasing thread to. */ + old_priority = next_mutex -> tx_mutex_highest_priority_waiting; + } + } + + /* Move mutex pointer to the next mutex in the list. */ + next_mutex = next_mutex -> tx_mutex_owned_next; + + /* Are we at the end of the list? */ + if (next_mutex == thread_ptr -> tx_thread_owned_mutex_list) + { + + /* Yes, set the next mutex to NULL. */ + next_mutex = TX_NULL; + } + } + +#ifndef TX_NOT_INTERRUPTABLE + + /* Disable interrupts. */ + TX_DISABLE + + /* Undo the temporarily preemption disable. */ + _tx_thread_preempt_disable--; +#endif + } + + /* Determine if priority inheritance is in effect and there are one or more + threads suspended on the mutex. */ + if (mutex_ptr -> tx_mutex_suspended_count > ((UINT) 1)) + { + + /* Is priority inheritance in effect? */ + if (mutex_ptr -> tx_mutex_inherit == TX_TRUE) + { + + /* Yes, this code is simply to ensure the highest priority thread is positioned + at the front of the suspension list. */ + +#ifndef TX_NOT_INTERRUPTABLE + + /* Temporarily disable preemption. */ + _tx_thread_preempt_disable++; + + /* Restore interrupts. */ + TX_RESTORE +#endif + + /* Call the mutex prioritize processing to ensure the + highest priority thread is resumed. */ +#ifdef TX_MISRA_ENABLE + do + { + status = _tx_mutex_prioritize(mutex_ptr); + } while (status != TX_SUCCESS); +#else + _tx_mutex_prioritize(mutex_ptr); +#endif + + /* At this point, the highest priority thread is at the + front of the suspension list. */ + +#ifndef TX_NOT_INTERRUPTABLE + + /* Disable interrupts. */ + TX_DISABLE + + /* Back off the preemption disable. */ + _tx_thread_preempt_disable--; +#endif + } + } + + /* Now determine if there are any threads still waiting on the mutex. */ + if (mutex_ptr -> tx_mutex_suspension_list == TX_NULL) + { + + /* No, there are no longer any threads waiting on the mutex. */ + +#ifndef TX_NOT_INTERRUPTABLE + + /* Temporarily disable preemption. */ + _tx_thread_preempt_disable++; + + /* Restore interrupts. */ + TX_RESTORE +#endif + + /* Mutex is not owned, but it is possible that a thread that + caused a priority inheritance to occur is no longer waiting + on the mutex. */ + if (mutex_ptr -> tx_mutex_inherit == TX_TRUE) + { + + /* Setup the highest priority waiting thread. */ + mutex_ptr -> tx_mutex_highest_priority_waiting = (UINT) TX_MAX_PRIORITIES; + + /* Determine if we need to restore priority. */ + if ((mutex_ptr -> tx_mutex_owner) -> tx_thread_priority != old_priority) + { + + /* Yes, restore the priority of thread. */ + _tx_mutex_priority_change(mutex_ptr -> tx_mutex_owner, old_priority); + } + } + +#ifndef TX_NOT_INTERRUPTABLE + + /* Disable interrupts again. */ + TX_DISABLE + + /* Back off the preemption disable. */ + _tx_thread_preempt_disable--; +#endif + + /* Clear the owner flag. */ + if (mutex_ptr -> tx_mutex_ownership_count == ((UINT) 0)) + { + + /* Set the mutex owner to NULL. */ + mutex_ptr -> tx_mutex_owner = TX_NULL; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Check for preemption. */ + _tx_thread_system_preempt_check(); + + /* Set status to success. */ + status = TX_SUCCESS; + } + else + { + + /* Pickup the thread at the front of the suspension list. */ + thread_ptr = mutex_ptr -> tx_mutex_suspension_list; + + /* Save the previous ownership information, if inheritance is + in effect. */ + if (mutex_ptr -> tx_mutex_inherit == TX_TRUE) + { + + /* Remember the old mutex owner. */ + old_owner = mutex_ptr -> tx_mutex_owner; + + /* Setup owner thread priority information. */ + mutex_ptr -> tx_mutex_original_priority = thread_ptr -> tx_thread_priority; + + /* Setup the highest priority waiting thread. */ + mutex_ptr -> tx_mutex_highest_priority_waiting = (UINT) TX_MAX_PRIORITIES; + } + + /* Determine how many mutexes are owned by this thread. */ + owned_count = thread_ptr -> tx_thread_owned_mutex_count; + + /* Determine if this thread owns any other mutexes that have priority inheritance. */ + if (owned_count == ((UINT) 0)) + { + + /* The owned mutex list is empty. Add mutex to empty list. */ + thread_ptr -> tx_thread_owned_mutex_list = mutex_ptr; + mutex_ptr -> tx_mutex_owned_next = mutex_ptr; + mutex_ptr -> tx_mutex_owned_previous = mutex_ptr; + } + else + { + + /* Non-empty list. Link up the mutex. */ + + /* Pickup tail pointer. */ + next_mutex = thread_ptr -> tx_thread_owned_mutex_list; + previous_mutex = next_mutex -> tx_mutex_owned_previous; + + /* Place the owned mutex in the list. */ + next_mutex -> tx_mutex_owned_previous = mutex_ptr; + previous_mutex -> tx_mutex_owned_next = mutex_ptr; + + /* Setup this mutex's next and previous created links. */ + mutex_ptr -> tx_mutex_owned_previous = previous_mutex; + mutex_ptr -> tx_mutex_owned_next = next_mutex; + } + + /* Increment the number of mutexes owned counter. */ + thread_ptr -> tx_thread_owned_mutex_count = owned_count + ((UINT) 1); + + /* Mark the Mutex as owned and fill in the corresponding information. */ + mutex_ptr -> tx_mutex_ownership_count = (UINT) 1; + mutex_ptr -> tx_mutex_owner = thread_ptr; + + /* Remove the suspended thread from the list. */ + + /* Decrement the suspension count. */ + mutex_ptr -> tx_mutex_suspended_count--; + + /* Pickup the suspended count. */ + suspended_count = mutex_ptr -> tx_mutex_suspended_count; + + /* See if this is the only suspended thread on the list. */ + if (suspended_count == TX_NO_SUSPENSIONS) + { + + /* Yes, the only suspended thread. */ + + /* Update the head pointer. */ + mutex_ptr -> tx_mutex_suspension_list = TX_NULL; + } + else + { + + /* At least one more thread is on the same expiration list. */ + + /* Update the list head pointer. */ + next_thread = thread_ptr -> tx_thread_suspended_next; + mutex_ptr -> tx_mutex_suspension_list = next_thread; + + /* Update the links of the adjacent threads. */ + previous_thread = thread_ptr -> tx_thread_suspended_previous; + next_thread -> tx_thread_suspended_previous = previous_thread; + previous_thread -> tx_thread_suspended_next = next_thread; + } + + /* Prepare for resumption of the first thread. */ + + /* Clear cleanup routine to avoid timeout. */ + thread_ptr -> tx_thread_suspend_cleanup = TX_NULL; + + /* Put return status into the thread control block. */ + thread_ptr -> tx_thread_suspend_status = TX_SUCCESS; + +#ifdef TX_NOT_INTERRUPTABLE + + /* Determine if priority inheritance is enabled for this mutex. */ + if (mutex_ptr -> tx_mutex_inherit == TX_TRUE) + { + + /* Yes, priority inheritance is requested. */ + + /* Determine if there are any more threads still suspended on the mutex. */ + if (mutex_ptr -> tx_mutex_suspended_count != ((ULONG) 0)) + { + + /* Determine if there are more than one thread suspended on the mutex. */ + if (mutex_ptr -> tx_mutex_suspended_count > ((ULONG) 1)) + { + + /* If so, prioritize the list so the highest priority thread is placed at the + front of the suspension list. */ +#ifdef TX_MISRA_ENABLE + do + { + status = _tx_mutex_prioritize(mutex_ptr); + } while (status != TX_SUCCESS); +#else + _tx_mutex_prioritize(mutex_ptr); +#endif + } + + /* Now, pickup the list head and set the priority. */ + + /* Determine if there still are threads suspended for this mutex. */ + suspended_thread = mutex_ptr -> tx_mutex_suspension_list; + if (suspended_thread != TX_NULL) + { + + /* Setup the highest priority thread waiting on this mutex. */ + mutex_ptr -> tx_mutex_highest_priority_waiting = suspended_thread -> tx_thread_priority; + } + } + + /* Restore previous priority needs to be restored after priority + inheritance. */ + if (old_owner != TX_NULL) + { + + /* Determine if we need to restore priority. */ + if (old_owner -> tx_thread_priority != old_priority) + { + + /* Restore priority of thread. */ + _tx_mutex_priority_change(old_owner, old_priority); + } + } + } + + /* Resume the thread! */ + _tx_thread_system_ni_resume(thread_ptr); + + /* Restore interrupts. */ + TX_RESTORE +#else + + /* Temporarily disable preemption. */ + _tx_thread_preempt_disable++; + + /* Restore interrupts. */ + TX_RESTORE + + /* Determine if priority inheritance is enabled for this mutex. */ + if (mutex_ptr -> tx_mutex_inherit == TX_TRUE) + { + + /* Yes, priority inheritance is requested. */ + + /* Determine if there are any more threads still suspended on the mutex. */ + if (mutex_ptr -> tx_mutex_suspended_count != TX_NO_SUSPENSIONS) + { + + /* Prioritize the list so the highest priority thread is placed at the + front of the suspension list. */ +#ifdef TX_MISRA_ENABLE + do + { + status = _tx_mutex_prioritize(mutex_ptr); + } while (status != TX_SUCCESS); +#else + _tx_mutex_prioritize(mutex_ptr); +#endif + + /* Now, pickup the list head and set the priority. */ + + /* Disable interrupts. */ + TX_DISABLE + + /* Determine if there still are threads suspended for this mutex. */ + suspended_thread = mutex_ptr -> tx_mutex_suspension_list; + if (suspended_thread != TX_NULL) + { + + /* Setup the highest priority thread waiting on this mutex. */ + mutex_ptr -> tx_mutex_highest_priority_waiting = suspended_thread -> tx_thread_priority; + } + + /* Restore interrupts. */ + TX_RESTORE + } + + /* Restore previous priority needs to be restored after priority + inheritance. */ + if (old_owner != TX_NULL) + { + + /* Is the priority different? */ + if (old_owner -> tx_thread_priority != old_priority) + { + + /* Restore the priority of thread. */ + _tx_mutex_priority_change(old_owner, old_priority); + } + } + } + + /* Resume thread. */ + _tx_thread_system_resume(thread_ptr); +#endif + + /* Return a successful status. */ + status = TX_SUCCESS; + } + } + } + } + } + } + else + { + + /* Restore interrupts. */ + TX_RESTORE + + /* Caller does not own the mutex. */ + status = TX_NOT_OWNED; + } + + /* Perform hooked callbacks. */ + ux_test_do_hooks_after(UX_TEST_OVERRIDE_TX_MUTEX_PUT, &action_params); + + /* Return the completion status. */ + return(status); +} + +UINT _nx_packet_pool_create(NX_PACKET_POOL *pool_ptr, CHAR *name_ptr, ULONG payload_size, + VOID *pool_start, ULONG pool_size) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_PACKET_POOL *tail_ptr; /* Working packet pool pointer */ +ULONG packets; /* Number of packets in pool */ +ULONG original_payload_size; /* Original payload size */ +ULONG header_size; /* Rounded header size */ +CHAR *packet_ptr; /* Working packet pointer */ +CHAR *next_packet_ptr; /* Next packet pointer */ +CHAR *end_of_pool; /* End of pool area */ +CHAR *payload_address; /* Address of the first payload*/ +VOID *rounded_pool_start; /* Rounded stating address */ +UX_TEST_OVERRIDE_TX_THREAD_CREATE_PARAMS action_params = { name_ptr }; +UX_TEST_ACTION action; + + + /* Perform action. */ + action = ux_test_action_handler(UX_TEST_OVERRIDE_NX_PACKET_POOL_CREATE, &action_params); + ux_test_do_action_before(&action, &action_params); + if (ux_test_is_expedient_on()) + { + if (action.matched && !action.do_after) + { + if (!action.no_return) + { + return action.status; + } + } + } + + /* Save the original payload size. */ + original_payload_size = payload_size; + + /* Align the starting address to four bytes. */ + /*lint -e{923} suppress cast between ULONG and pointer. */ + rounded_pool_start = (VOID *)((((ALIGN_TYPE)pool_start + NX_PACKET_ALIGNMENT - 1) / NX_PACKET_ALIGNMENT) * NX_PACKET_ALIGNMENT); + + /* Round the pool size down to something that is evenly divisible by alignment. */ + /*lint -e{923} suppress cast between ULONG and pointer. */ + pool_size = (ULONG)(((pool_size - ((ALIGN_TYPE)rounded_pool_start - (ALIGN_TYPE)pool_start)) / NX_PACKET_ALIGNMENT) * NX_PACKET_ALIGNMENT); + + /* Set the pool starting address. */ + pool_start = rounded_pool_start; + + /* Calculate the address of payload. */ + /*lint -e{923} suppress cast between ULONG and pointer. */ + payload_address = (CHAR *)((ALIGN_TYPE)rounded_pool_start + sizeof(NX_PACKET)); + + /* Align the address of payload. */ + /*lint -e{923} suppress cast between ULONG and pointer. */ + payload_address = (CHAR *)((((ALIGN_TYPE)payload_address + NX_PACKET_ALIGNMENT - 1) / NX_PACKET_ALIGNMENT) * NX_PACKET_ALIGNMENT); + + /* Calculate the header size. */ + /*lint -e{923} suppress cast between ULONG and pointer. */ + header_size = (ULONG)((ALIGN_TYPE)payload_address - (ALIGN_TYPE)rounded_pool_start); + + /* Round the packet size up to something that helps guarantee proper alignment for header and payload. */ + payload_size = (ULONG)(((header_size + payload_size + NX_PACKET_ALIGNMENT - 1) / NX_PACKET_ALIGNMENT) * NX_PACKET_ALIGNMENT - header_size); + + /* Clear pool fields. */ + memset(pool_ptr, 0, sizeof(NX_PACKET_POOL)); + + /* Setup the basic packet pool fields. */ + pool_ptr -> nx_packet_pool_name = name_ptr; + pool_ptr -> nx_packet_pool_suspension_list = TX_NULL; + pool_ptr -> nx_packet_pool_suspended_count = 0; + pool_ptr -> nx_packet_pool_start = (CHAR *)pool_start; + pool_ptr -> nx_packet_pool_size = pool_size; + pool_ptr -> nx_packet_pool_payload_size = original_payload_size; + + /* Calculate the end of the pool's memory area. */ + end_of_pool = ((CHAR *)pool_start) + pool_size; + + /* Walk through the pool area, setting up the available packet list. */ + packets = 0; + packet_ptr = (CHAR *)rounded_pool_start; + next_packet_ptr = packet_ptr + (payload_size + header_size); + + /*lint -e{946} suppress pointer subtraction, since it is necessary. */ + while (next_packet_ptr <= end_of_pool) + { + + /* Yes, we have another packet. Increment the packet count. */ + packets++; + + /* Setup the link to the next packet. */ + /*lint -e{929} -e{740} -e{826} suppress cast of pointer to pointer, since it is necessary */ + ((NX_PACKET *)packet_ptr) -> nx_packet_queue_next = (NX_PACKET *)next_packet_ptr; + + /* Remember that this packet pool is the owner. */ + /*lint -e{929} -e{740} -e{826} suppress cast of pointer to pointer, since it is necessary */ + ((NX_PACKET *)packet_ptr) -> nx_packet_pool_owner = pool_ptr; + +#ifndef NX_DISABLE_PACKET_CHAIN + /* Clear the next packet pointer. */ + /*lint -e{929} -e{740} -e{826} suppress cast of pointer to pointer, since it is necessary */ + ((NX_PACKET *)packet_ptr) -> nx_packet_next = (NX_PACKET *)NX_NULL; +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Mark the packet as free. */ + /*lint -e{929} -e{923} -e{740} -e{826} suppress cast of pointer to pointer, since it is necessary */ + ((NX_PACKET *)packet_ptr) -> nx_packet_union_next.nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_FREE; + + /* Setup the packet data pointers. */ + /*lint -e{929} -e{928} -e{740} -e{826} suppress cast of pointer to pointer, since it is necessary */ + ((NX_PACKET *)packet_ptr) -> nx_packet_data_start = (UCHAR *)(packet_ptr + header_size); + + /*lint -e{929} -e{928} -e{740} -e{826} suppress cast of pointer to pointer, since it is necessary */ + ((NX_PACKET *)packet_ptr) -> nx_packet_data_end = (UCHAR *)(packet_ptr + header_size + original_payload_size); + + /* Add debug information. */ + NX_PACKET_DEBUG(__FILE__, __LINE__, (NX_PACKET *)packet_ptr); + + /* Advance to the next packet. */ + packet_ptr = next_packet_ptr; + + /* Update the next packet pointer. */ + next_packet_ptr = packet_ptr + (payload_size + header_size); + } + + /* Backup to the last packet in the pool. */ + packet_ptr = packet_ptr - (payload_size + header_size); + + /* Set the last packet's forward pointer to NULL. */ + /*lint -e{929} -e{740} -e{826} suppress cast of pointer to pointer, since it is necessary */ + ((NX_PACKET *)packet_ptr) -> nx_packet_queue_next = NX_NULL; + + /* Save the remaining information in the pool control packet. */ + pool_ptr -> nx_packet_pool_available = packets; + pool_ptr -> nx_packet_pool_total = packets; + + /* Set the packet pool available list. */ + pool_ptr -> nx_packet_pool_available_list = (NX_PACKET *)pool_start; + + /* If trace is enabled, register this object. */ + NX_TRACE_OBJECT_REGISTER(NX_TRACE_OBJECT_TYPE_PACKET_POOL, pool_ptr, name_ptr, payload_size, packets); + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_PACKET_POOL_CREATE, pool_ptr, payload_size, pool_start, pool_size, NX_TRACE_PACKET_EVENTS, 0, 0); + + /* Disable interrupts to place the packet pool on the created list. */ + TX_DISABLE + + /* Setup the packet pool ID to make it valid. */ + pool_ptr -> nx_packet_pool_id = NX_PACKET_POOL_ID; + + /* Place the packet pool on the list of created packet pools. First, + check for an empty list. */ + if (_nx_packet_pool_created_ptr) + { + + /* Pickup tail pointer. */ + tail_ptr = _nx_packet_pool_created_ptr -> nx_packet_pool_created_previous; + + /* Place the new packet pool in the list. */ + _nx_packet_pool_created_ptr -> nx_packet_pool_created_previous = pool_ptr; + tail_ptr -> nx_packet_pool_created_next = pool_ptr; + + /* Setup this packet pool's created links. */ + pool_ptr -> nx_packet_pool_created_previous = tail_ptr; + pool_ptr -> nx_packet_pool_created_next = _nx_packet_pool_created_ptr; + } + else + { + + /* The created packet pool list is empty. Add packet pool to empty list. */ + _nx_packet_pool_created_ptr = pool_ptr; + pool_ptr -> nx_packet_pool_created_next = pool_ptr; + pool_ptr -> nx_packet_pool_created_previous = pool_ptr; + } + + /* Increment the number of packet pools created. */ + _nx_packet_pool_created_count++; + + /* Restore interrupts. */ + TX_RESTORE + + /* Return NX_SUCCESS. */ + return(NX_SUCCESS); +} + +UINT _nx_packet_allocate(NX_PACKET_POOL *pool_ptr, NX_PACKET **packet_ptr, + ULONG packet_type, ULONG wait_option) +{ +TX_INTERRUPT_SAVE_AREA + +UINT status; /* Return status */ +TX_THREAD *thread_ptr; /* Working thread pointer */ +NX_PACKET *work_ptr; /* Working packet pointer */ +UX_TEST_OVERRIDE_NX_PACKET_ALLOCATE_PARAMS action_params = { pool_ptr }; +UX_TEST_ACTION action; + + + /* Perform action. */ + action = ux_test_action_handler(UX_TEST_OVERRIDE_NX_PACKET_ALLOCATE, &action_params); + ux_test_do_action_before(&action, &action_params); + if (ux_test_is_expedient_on()) + { + if (action.matched && !action.do_after) + { + if (!action.no_return) + { + return action.status; + } + } + } + +#ifdef TX_ENABLE_EVENT_TRACE +TX_TRACE_BUFFER_ENTRY *trace_event; +ULONG trace_timestamp; +#endif + + /* Make sure the packet_type does not go beyond nx_packet_data_end. */ + if (pool_ptr -> nx_packet_pool_payload_size < packet_type) + { + return(NX_INVALID_PARAMETERS); + } + + /* Set the return pointer to NULL initially. */ + *packet_ptr = NX_NULL; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_PACKET_ALLOCATE, pool_ptr, 0, packet_type, pool_ptr -> nx_packet_pool_available, NX_TRACE_PACKET_EVENTS, &trace_event, &trace_timestamp); + + /* Disable interrupts to get a packet from the pool. */ + TX_DISABLE + + /* Determine if there is an available packet. */ + if (pool_ptr -> nx_packet_pool_available) + { + + /* Yes, a packet is available. Decrement the available count. */ + pool_ptr -> nx_packet_pool_available--; + + /* Pickup the current packet pointer. */ + work_ptr = pool_ptr -> nx_packet_pool_available_list; + + /* Modify the available list to point at the next packet in the pool. */ + pool_ptr -> nx_packet_pool_available_list = work_ptr -> nx_packet_queue_next; + + /* Setup various fields for this packet. */ + work_ptr -> nx_packet_queue_next = NX_NULL; +#ifndef NX_DISABLE_PACKET_CHAIN + work_ptr -> nx_packet_next = NX_NULL; + work_ptr -> nx_packet_last = NX_NULL; +#endif /* NX_DISABLE_PACKET_CHAIN */ + work_ptr -> nx_packet_length = 0; + work_ptr -> nx_packet_prepend_ptr = work_ptr -> nx_packet_data_start + packet_type; + work_ptr -> nx_packet_append_ptr = work_ptr -> nx_packet_prepend_ptr; + work_ptr -> nx_packet_address.nx_packet_interface_ptr = NX_NULL; +#ifdef NX_ENABLE_INTERFACE_CAPABILITY + work_ptr -> nx_packet_interface_capability_flag = 0; +#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ + /* Set the TCP queue to the value that indicates it has been allocated. */ + /*lint -e{923} suppress cast of ULONG to pointer. */ + work_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ALLOCATED; + +#ifdef FEATURE_NX_IPV6 + + /* Clear the option state. */ + work_ptr -> nx_packet_option_state = 0; +#endif /* FEATURE_NX_IPV6 */ + +#ifdef NX_IPSEC_ENABLE + + /* Clear the ipsec state. */ + work_ptr -> nx_packet_ipsec_state = 0; + work_ptr -> nx_packet_ipsec_sa_ptr = NX_NULL; +#endif /* NX_IPSEC_ENABLE */ + +#ifndef NX_DISABLE_IPV4 + /* Initialize the IP version field */ + work_ptr -> nx_packet_ip_version = NX_IP_VERSION_V4; +#endif /* !NX_DISABLE_IPV4 */ + + /* Initialize the IP identification flag. */ + work_ptr -> nx_packet_identical_copy = NX_FALSE; + + /* Initialize the IP header length. */ + work_ptr -> nx_packet_ip_header_length = 0; + +#ifdef NX_ENABLE_THREAD + work_ptr -> nx_packet_type = 0; +#endif /* NX_ENABLE_THREAD */ + + /* Place the new packet pointer in the return destination. */ + *packet_ptr = work_ptr; + + /* Set status to success. */ + status = NX_SUCCESS; + + /* Add debug information. */ + NX_PACKET_DEBUG(__FILE__, __LINE__, work_ptr); + } + else + { + +#ifndef NX_DISABLE_PACKET_INFO + /* Increment the packet pool empty request count. */ + pool_ptr -> nx_packet_pool_empty_requests++; +#endif + + /* Determine if the request specifies suspension. */ + if (wait_option) + { + + /* Prepare for suspension of this thread. */ + +#ifndef NX_DISABLE_PACKET_INFO + /* Increment the packet pool empty request suspension count. */ + pool_ptr -> nx_packet_pool_empty_suspensions++; +#endif + + /* Pickup thread pointer. */ + thread_ptr = _tx_thread_current_ptr; + + /* Setup cleanup routine pointer. */ + thread_ptr -> tx_thread_suspend_cleanup = _nx_packet_pool_cleanup; + + /* Setup cleanup information, i.e. this pool control + block. */ + thread_ptr -> tx_thread_suspend_control_block = (void *)pool_ptr; + + /* Save the return packet pointer address as well. */ + thread_ptr -> tx_thread_additional_suspend_info = (void *)packet_ptr; + + /* Save the packet type (or prepend offset) so this can be added + after a new packet becomes available. */ + thread_ptr -> tx_thread_suspend_info = packet_type; + + /* Setup suspension list. */ + if (pool_ptr -> nx_packet_pool_suspension_list) + { + + /* This list is not NULL, add current thread to the end. */ + thread_ptr -> tx_thread_suspended_next = + pool_ptr -> nx_packet_pool_suspension_list; + thread_ptr -> tx_thread_suspended_previous = + (pool_ptr -> nx_packet_pool_suspension_list) -> tx_thread_suspended_previous; + ((pool_ptr -> nx_packet_pool_suspension_list) -> tx_thread_suspended_previous) -> tx_thread_suspended_next = + thread_ptr; + (pool_ptr -> nx_packet_pool_suspension_list) -> tx_thread_suspended_previous = thread_ptr; + } + else + { + + /* No other threads are suspended. Setup the head pointer and + just setup this threads pointers to itself. */ + pool_ptr -> nx_packet_pool_suspension_list = thread_ptr; + thread_ptr -> tx_thread_suspended_next = thread_ptr; + thread_ptr -> tx_thread_suspended_previous = thread_ptr; + } + + /* Increment the suspended thread count. */ + pool_ptr -> nx_packet_pool_suspended_count++; + + /* Set the state to suspended. */ + thread_ptr -> tx_thread_state = TX_TCP_IP; + + /* Set the suspending flag. */ + thread_ptr -> tx_thread_suspending = TX_TRUE; + + /* Temporarily disable preemption. */ + _tx_thread_preempt_disable++; + + /* Save the timeout value. */ + thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = wait_option; + + /* Restore interrupts. */ + TX_RESTORE + + /* Call actual thread suspension routine. */ + _tx_thread_system_suspend(thread_ptr); + + /* Update the trace event with the status. */ + NX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, NX_TRACE_PACKET_ALLOCATE, 0, *packet_ptr, 0, 0); + +#ifdef NX_ENABLE_PACKET_DEBUG_INFO + if (thread_ptr -> tx_thread_suspend_status == NX_SUCCESS) + { + + /* Add debug information. */ + NX_PACKET_DEBUG(__FILE__, __LINE__, *packet_ptr); + } +#endif /* NX_ENABLE_PACKET_DEBUG_INFO */ + + /* Return the completion status. */ + return(thread_ptr -> tx_thread_suspend_status); + } + else + { + + /* Immediate return, return error completion. */ + status = NX_NO_PACKET; + } + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Update the trace event with the status. */ + NX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, NX_TRACE_PACKET_ALLOCATE, 0, *packet_ptr, 0, 0); + + /* Return completion status. */ + return(status); +} + +VOID ux_test_utility_sim_event_create_count_reset (VOID) +{ + event_create_count = 0; +} +ULONG ux_test_utility_sim_event_create_count (VOID) +{ + return event_create_count; +} +VOID ux_test_utility_sim_event_error_generation_start(ULONG fail_after) +{ + event_create_count = 0; + event_fail_after = fail_after; +} +VOID ux_test_utility_sim_event_error_generation_stop (VOID) +{ + event_fail_after = FAIL_DISABLE; + event_create_count = 0; +} + +UINT _tx_event_flags_create(TX_EVENT_FLAGS_GROUP *group_ptr, CHAR *name_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + +TX_EVENT_FLAGS_GROUP *next_group; +TX_EVENT_FLAGS_GROUP *previous_group; + + + if (event_fail_after != FAIL_DISABLE) + { + + if (event_create_count >= event_fail_after) + { + + /* Return testing error instead of actual creation. */ + return UX_MUTEX_ERROR; + } + } + + /* Do actual creating. */ + event_create_count ++; + + + /* Initialize event flags control block to all zeros. */ + TX_MEMSET(group_ptr, 0, (sizeof(TX_EVENT_FLAGS_GROUP))); + + /* Setup the basic event flags group fields. */ + group_ptr -> tx_event_flags_group_name = name_ptr; + + /* Disable interrupts to put the event flags group on the created list. */ + TX_DISABLE + + /* Setup the event flags ID to make it valid. */ + group_ptr -> tx_event_flags_group_id = TX_EVENT_FLAGS_ID; + + /* Place the group on the list of created event flag groups. First, + check for an empty list. */ + if (_tx_event_flags_created_count == TX_EMPTY) + { + + /* The created event flags list is empty. Add event flag group to empty list. */ + _tx_event_flags_created_ptr = group_ptr; + group_ptr -> tx_event_flags_group_created_next = group_ptr; + group_ptr -> tx_event_flags_group_created_previous = group_ptr; + } + else + { + + /* This list is not NULL, add to the end of the list. */ + next_group = _tx_event_flags_created_ptr; + previous_group = next_group -> tx_event_flags_group_created_previous; + + /* Place the new event flag group in the list. */ + next_group -> tx_event_flags_group_created_previous = group_ptr; + previous_group -> tx_event_flags_group_created_next = group_ptr; + + /* Setup this group's created links. */ + group_ptr -> tx_event_flags_group_created_previous = previous_group; + group_ptr -> tx_event_flags_group_created_next = next_group; + } + + /* Increment the number of created event flag groups. */ + _tx_event_flags_created_count++; + + /* Optional event flag group create extended processing. */ + TX_EVENT_FLAGS_GROUP_CREATE_EXTENSION(group_ptr) + + /* If trace is enabled, register this object. */ + TX_TRACE_OBJECT_REGISTER(TX_TRACE_OBJECT_TYPE_EVENT_FLAGS, group_ptr, name_ptr, 0, 0) + + /* If trace is enabled, insert this event into the trace buffer. */ + TX_TRACE_IN_LINE_INSERT(TX_TRACE_EVENT_FLAGS_CREATE, group_ptr, TX_POINTER_TO_ULONG_CONVERT(&next_group), 0, 0, TX_TRACE_EVENT_FLAGS_EVENTS) + + /* Log this kernel call. */ + TX_EL_EVENT_FLAGS_CREATE_INSERT + + /* Restore interrupts. */ + TX_RESTORE + + /* Return TX_SUCCESS. */ + return(TX_SUCCESS); +} + + +/****** IO inp?/outp? *****************/ +static ULONG *_ux_test_sim_inp_seq = UX_NULL; +static ULONG _ux_test_sim_inp_seq_len = 0; +static ULONG _ux_test_sim_inp_seq_i = 0; +static ULONG _ux_test_sim_inp_seq_value(VOID) +{ + if (_ux_test_sim_inp_seq && _ux_test_sim_inp_seq_len) + { + if (_ux_test_sim_inp_seq_i >= _ux_test_sim_inp_seq_len) + return _ux_test_sim_inp_seq[_ux_test_sim_inp_seq_len - 1]; + + return _ux_test_sim_inp_seq[_ux_test_sim_inp_seq_i]; + } + else + { + return 0; + } + +} +static VOID _ux_test_sim_inp_seq_inc(VOID) +{ + if (_ux_test_sim_inp_seq_i < _ux_test_sim_inp_seq_len) + _ux_test_sim_inp_seq_i ++; +} +VOID ux_test_sim_inp_sequence_set(ULONG* seq, ULONG len) +{ + _ux_test_sim_inp_seq = seq; + _ux_test_sim_inp_seq_len = len; + _ux_test_sim_inp_seq_i = 0; +} +UCHAR inpb(ULONG addr) +{ + UCHAR value = (UCHAR)_ux_test_sim_inp_seq_value(); + (void)addr; + _ux_test_sim_inp_seq_inc(); + return value; +} +#ifndef _MSC_BUILD +USHORT inpw(ULONG addr) +#else +USHORT inpw_mok(ULONG addr) +#endif +{ + USHORT value = (USHORT)_ux_test_sim_inp_seq_value(); + (void)addr; + _ux_test_sim_inp_seq_inc(); + return value; +} +ULONG inpl(ULONG addr) +{ + ULONG value = (ULONG)_ux_test_sim_inp_seq_value(); + (void)addr; + _ux_test_sim_inp_seq_inc(); + return value; +} + + +static ULONG* _ux_test_sim_outp_logbuf = UX_NULL; +static ULONG _ux_test_sim_outp_logbuf_size = 0; +static ULONG _ux_test_sim_outp_logbuf_i = 0; +static VOID _ux_test_sim_outp_log_save(ULONG addr, ULONG value) +{ + if (!_ux_test_sim_outp_logbuf || !_ux_test_sim_outp_logbuf_size) + return; + + if (_ux_test_sim_outp_logbuf_i < _ux_test_sim_outp_logbuf_size - 1) + { + _ux_test_sim_outp_logbuf[_ux_test_sim_outp_logbuf_i ++] = addr; + _ux_test_sim_outp_logbuf[_ux_test_sim_outp_logbuf_i ++] = value; + } +} +ULONG ux_test_sim_outp_log_count(VOID) +{ + return (_ux_test_sim_outp_logbuf_i >> 1); +} +VOID ux_test_sim_outp_log_reset(VOID) +{ + _ux_test_sim_outp_logbuf_i = 0; +} +VOID ux_test_sim_outp_logbuf_set(ULONG* buf, ULONG size) +{ + _ux_test_sim_outp_logbuf = buf; + _ux_test_sim_outp_logbuf_size = size; + _ux_test_sim_outp_logbuf_i = 0; +} +ULONG ux_test_sim_outp_log_get(ULONG seq, ULONG *addr, ULONG *value) +{ + seq = seq << 1; + if (seq >= _ux_test_sim_outp_logbuf_i) + return 0; + if (addr) + *addr = _ux_test_sim_outp_logbuf[seq]; + if (value) + *value = _ux_test_sim_outp_logbuf[seq + 1]; + return 1; +} +UCHAR outpb(ULONG addr, UCHAR b) +{ + _ux_test_sim_outp_log_save(addr, b); + return b; +} +#ifndef _MSC_BUILD +USHORT outpw(ULONG addr, USHORT w) +#else +USHORT outpw_mok(ULONG addr, USHORT w) +#endif +{ + _ux_test_sim_outp_log_save(addr, w); + return w; +} +ULONG outpl(ULONG addr, ULONG l) +{ + _ux_test_sim_outp_log_save(addr, l); +#ifdef _MSC_BUILD + return l; +#endif +} diff --git a/test/regression/ux_test_utility_sim.h b/test/regression/ux_test_utility_sim.h new file mode 100644 index 00000000..e08edf2d --- /dev/null +++ b/test/regression/ux_test_utility_sim.h @@ -0,0 +1,71 @@ +/* This test simulator is designed to simulate ux_utility_ APIs for test. */ + +#ifndef _UX_TEST_UTILITY_SIM_H +#define _UX_TEST_UTILITY_SIM_H + +VOID ux_test_sim_inp_sequence_set(ULONG* seq, ULONG size); +VOID ux_test_sim_outp_logbuf_set(ULONG* buf, ULONG size); +ULONG ux_test_sim_outp_log_get(ULONG seq, ULONG *addr, ULONG *value); +ULONG ux_test_sim_outp_log_count(VOID); +VOID ux_test_sim_outp_log_reset(VOID); + +VOID ux_test_utility_sim_sem_create_count_reset (VOID); +ULONG ux_test_utility_sim_sem_create_count (VOID); + +VOID ux_test_utility_sim_sem_error_generation_start(ULONG fail_after); +VOID ux_test_utility_sim_sem_error_generation_stop (VOID); + +VOID ux_test_utility_sim_sem_get_count_reset (VOID); +ULONG ux_test_utility_sim_sem_get_count (VOID); + +VOID ux_test_utility_sim_sem_get_error_exception_reset(VOID); +VOID ux_test_utility_sim_sem_get_error_exception_add(TX_SEMAPHORE *semaphore, ULONG semaphore_signal); +VOID ux_test_utility_sim_sem_get_error_generation_start(ULONG fail_after); +VOID ux_test_utility_sim_sem_get_error_generation_stop (VOID); + +VOID ux_test_utility_sim_mutex_create_count_reset (VOID); +ULONG ux_test_utility_sim_mutex_create_count (VOID); + +VOID ux_test_utility_sim_mutex_error_generation_start(ULONG fail_after); +VOID ux_test_utility_sim_mutex_error_generation_stop (VOID); + +#if 0 /* Current Mutex ON/OFF has no return code. */ +VOID ux_test_utility_sim_mutex_on_count_reset (VOID); +ULONG ux_test_utility_sim_mutex_on_count (VOID); +VOID ux_test_utility_sim_mutex_on_error_generation_start(ULONG fail_after); +VOID ux_test_utility_sim_mutex_on_error_generation_stop (VOID); +#endif + +VOID ux_test_utility_sim_event_create_count_reset (VOID); +ULONG ux_test_utility_sim_event_create_count (VOID); +VOID ux_test_utility_sim_event_error_generation_start(ULONG fail_after); +VOID ux_test_utility_sim_event_error_generation_stop (VOID); + +VOID ux_test_utility_sim_thread_create_count_reset (VOID); +ULONG ux_test_utility_sim_thread_create_count (VOID); +VOID ux_test_utility_sim_thread_error_generation_start(ULONG fail_after); +VOID ux_test_utility_sim_thread_error_generation_stop (VOID); + +VOID ux_test_utility_sim_mem_allocate_until_align_flagged(ULONG target_fail_level, ULONG memory_alignment, ULONG memory_cache_flag); + +#define ux_test_utility_sim_mem_allocate_until_flagged(fail_level, cache_flag) ux_test_utility_sim_mem_allocate_until_align_flagged(fail_level, UX_NO_ALIGN, cache_flag) + +VOID ux_test_utility_sim_mem_free_all_flagged (ULONG memory_cache_flag); + +#define ux_test_utility_sim_mem_allocate_until(l) ux_test_utility_sim_mem_allocate_until_flagged((l), UX_REGULAR_MEMORY) +#define ux_test_utility_sim_mem_free_all() ux_test_utility_sim_mem_free_all_flagged(UX_REGULAR_MEMORY) + +VOID ux_test_utility_sim_mem_alloc_log_enable(UCHAR enable_disable); +VOID ux_test_utility_sim_mem_alloc_log_lock(VOID); +ULONG ux_test_utility_sim_mem_alloc_count(VOID); +VOID ux_test_utility_sim_mem_alloc_count_reset(VOID); +VOID ux_test_utility_sim_mem_alloc_error_generation_start(ULONG fail_after); +VOID ux_test_utility_sim_mem_alloc_error_generation_stop(VOID); +UINT ux_test_utility_sim_mem_alloc_error_generation_active(VOID); + +VOID ux_test_utility_sim_mem_alloc_fail_all_start(VOID); +VOID ux_test_utility_sim_mem_alloc_fail_all_stop(VOID); + +VOID ux_test_utility_sim_cleanup(VOID); + +#endif /* _UX_TEST_UTILITY_SIM_H */ diff --git a/test/regression/ux_test_utility_sim_no_overriding.c b/test/regression/ux_test_utility_sim_no_overriding.c new file mode 100644 index 00000000..47da1567 --- /dev/null +++ b/test/regression/ux_test_utility_sim_no_overriding.c @@ -0,0 +1,373 @@ +/* This test simulator is designed to simulate ux_utility_ APIs for test. */ + +#include + +#include "tx_api.h" +#include "ux_test.h" + +#include "ux_api.h" +#include "ux_system.h" +#include "ux_utility.h" + +#include "ux_test_utility_sim.h" + +#define FAIL_DISABLE (~0x00ul) + +extern void test_control_return(UINT status); + + static UX_MEMORY_BLOCK fail_memory_block_first = + { + .ux_memory_block_next = UX_NULL, + .ux_memory_byte_pool = UX_NULL, + }; + +static UX_MEMORY_BLOCK *original_regular_memory_block; +static UX_MEMORY_BLOCK *original_cache_safe_memory_block; + +#define MAX_FLAGGED_MEMORY_ALLOCATION_POINTERS 8*1024 +static VOID *flagged_memory_allocation_pointers[2][MAX_FLAGGED_MEMORY_ALLOCATION_POINTERS]; +static ULONG num_flagged_memory_allocation_pointers[2]; + +VOID ux_test_utility_sim_no_overriding_cleanup(VOID) +{ + + num_flagged_memory_allocation_pointers[0] = 0; + num_flagged_memory_allocation_pointers[1] = 0; +} + +/* Memory allocation simulator*/ + +VOID ux_test_utility_sim_mem_alloc_fail_all_start(VOID) +{ + original_regular_memory_block = (UX_MEMORY_BLOCK *)_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start; + original_cache_safe_memory_block = (UX_MEMORY_BLOCK *)_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_start; + + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start = (UCHAR*)&fail_memory_block_first; + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_start = (UCHAR*)&fail_memory_block_first; +} + +VOID ux_test_utility_sim_mem_alloc_fail_all_stop(VOID) +{ + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start = (UCHAR*)original_regular_memory_block; + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_start = (UCHAR*)original_cache_safe_memory_block; +} + + +/* When the memory allocator tries to find a block of memory for the requested size, it will add extra stuff to + accomodate things like having to align the memory. See the allocator for what it adds. We don't take the requested + size alignment into account - we leave it up to the caller. */ +static ULONG get_amount_added_by_memory_allocator(ULONG memory_alignment, ULONG memory_size_requested) +{ + +ULONG added; + + if (memory_alignment == UX_SAFE_ALIGN) + memory_alignment = UX_NO_ALIGN; + + if (memory_alignment <= UX_ALIGN_MIN) + { + added = sizeof(UX_MEMORY_BLOCK) + + /* This is the amount of memory required to ensure the next memory block buffer is properly align. */ + (((sizeof(UX_MEMORY_BLOCK) + UX_ALIGN_MIN) & (~(ULONG)UX_ALIGN_MIN)) - sizeof(UX_MEMORY_BLOCK)); + } + else + { + added = memory_alignment + sizeof(UX_MEMORY_BLOCK) + + /* This is the amount of memory required to ensure the next memory block buffer is properly align. */ + (((sizeof(UX_MEMORY_BLOCK) + UX_ALIGN_MIN) & (~(ULONG)UX_ALIGN_MIN)) - sizeof(UX_MEMORY_BLOCK)); + } + + return added; +} + +/* Returns the amount of memory that should be passed to ux_utility_memory_allocate + to allocate a specific memory block of the given size. */ +static ULONG memory_requested_size_for_block(ULONG memory_alignment, ULONG block_size) +{ + +ULONG result; +ULONG added; + + added = get_amount_added_by_memory_allocator(memory_alignment, block_size); + if (added > block_size) + { + return 0; + } + + /* Now subtract everything we added. */ + result = block_size - added; + + /* The allocator will align the requested size to 16 bytes, so if we don't do any alignment now, the allocator + might add to the size. We can avoid this by just aligning to 16 bytes now. */ + result &= ~(UX_ALIGN_MIN); + + // /* _ux_utility_memory_free_block_best_get does a '>' check, not '>='. */ + // result--; + + return(result); +} + +static void add_memory_allocation_pointer(ULONG memory_cache_flag, VOID *allocation_ptr) +{ + UX_TEST_ASSERT(num_flagged_memory_allocation_pointers[memory_cache_flag] < MAX_FLAGGED_MEMORY_ALLOCATION_POINTERS); + flagged_memory_allocation_pointers[memory_cache_flag][num_flagged_memory_allocation_pointers[memory_cache_flag]++] = allocation_ptr; +} + +/* This function simply allocates everything. */ +VOID allocate_everything(ULONG memory_cache_flag) +{ + +// UX_MEMORY_BLOCK *first_memory_block; +UX_MEMORY_BLOCK *memory_block; +ULONG memory_block_size; +ULONG memory_block_requested_size; +VOID *tmp_allocation_ptr; +UX_MEMORY_BYTE_POOL *pool_ptr; + + if (memory_cache_flag == UX_REGULAR_MEMORY) + { + pool_ptr = (UX_MEMORY_BYTE_POOL *)_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR]; + } + else + { + pool_ptr = (UX_MEMORY_BYTE_POOL *)_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE]; + } + + /* Try to allocate all the blocks according to their size - this is faster than repeatedly allocating 1 byte. */ + memory_block = (UX_MEMORY_BLOCK *)pool_ptr -> ux_byte_pool_start; + while (memory_block -> ux_memory_block_next > memory_block) + { + if ((ULONG)memory_block->ux_memory_byte_pool == UX_BYTE_BLOCK_FREE) + { + memory_block_size = (UCHAR *)memory_block->ux_memory_block_next - (UCHAR*)memory_block; + memory_block_requested_size = memory_requested_size_for_block(UX_NO_ALIGN, memory_block_size); + if (memory_block_requested_size > 0) + { + tmp_allocation_ptr = ux_utility_memory_allocate(UX_NO_ALIGN, memory_cache_flag, memory_block_requested_size); + UX_TEST_ASSERT(tmp_allocation_ptr != UX_NULL); + add_memory_allocation_pointer(memory_cache_flag, tmp_allocation_ptr); + + /* memory_block is now the block we just allocated. */ + memory_block = (UX_MEMORY_BLOCK *)UX_UCHAR_POINTER_SUB(tmp_allocation_ptr, sizeof(UX_MEMORY_BLOCK)); + } + } + memory_block = memory_block->ux_memory_block_next; + } + + /* Now allocate everything else. */ + while (1) + { + tmp_allocation_ptr = ux_utility_memory_allocate(UX_NO_ALIGN, memory_cache_flag, 1); + if (tmp_allocation_ptr == NULL) + { + break; + } + add_memory_allocation_pointer(memory_cache_flag, tmp_allocation_ptr); + } +} + +/* The goal of this function is to ensure that allocating 'target_fail_level' amount of memory fails, and to ensure + any allocations below 'target_fail_level' succeeds. An example usage is trying to get some allocation to fail in USBX + where the allocation follows other allocations i.e. you want allocations X and Y to succeed, but Z to fail; by passing + the sum of the sizes of X, Y, and Z to this function, it ensures X and Y will success and Z to fail. + + The gist of how we do this is to allocate memory for 'target_fail_level - 1', then allocate all other memory, then free + the 'target_fail_level - 1' allocation. While that's the gist, it's quite oversimplified and there are nuances in the + allocator that makes this a little more difficult, as is explained throughout. */ +VOID ux_test_utility_sim_mem_allocate_until_align_flagged(ULONG target_fail_level, ULONG memory_alignment, ULONG memory_cache_flag) +{ + +ULONG amount_added_by_allocator; +ULONG amount_added_by_alignment; +ULONG total_allocation_size; +ULONG memory_used; +UX_MEMORY_BLOCK *cur_memory_block; +UX_MEMORY_BLOCK *next_memory_block; +VOID *next_memory_block_buffer; +VOID *main_allocation_ptr; +UX_MEMORY_BYTE_POOL *pool_ptr; + + // printf("alloc_until(%ld, %ld, %ld)\n", target_fail_level, memory_alignment, memory_cache_flag); + if (memory_cache_flag == UX_REGULAR_MEMORY) + { + pool_ptr = (UX_MEMORY_BYTE_POOL *)_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR]; + } + else + { + pool_ptr = (UX_MEMORY_BYTE_POOL *)_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE]; + } + /* Since we're going to generate at least one error, we need to ignore it. */ + ux_test_ignore_all_errors(); + + /* Adjust level if invalid. */ + if (target_fail_level == 0) + target_fail_level++; + + /* The allocator will align the requested size to a 16-byte boundary. This means that, instead of allocating 'target_fail_level - 1', + we instead allocate 'target_fail_level - 16'. If the target_fail_level is less than 16, then we simply allocate everything. */ + if (target_fail_level <= (UX_ALIGN_MIN + 1)) + { + allocate_everything(memory_cache_flag); + } + else + { + + /* As previously said, we subtract 16 since the allocator aligns sizes to 16-bytes. */ + target_fail_level -= (UX_ALIGN_MIN + 1); + + /* As The header and the alignment is considered in ux_utility_memory_allocate function, we just need to allocate the request size here */ +#if 0 + /* We have to figure out the size we need to allocate for the 'target_fail_level - 1' block. This is tricky because the allocator will + find a memory block that fits the requested size plus some extra stuff. If the extra stuff isn't used, the allocator will create another + memory block for it, so when we try to allocate the 'target_fail_level - 1 ' again, the memory block won't be big enough (remember, we allocate + everything after doing this allocate, so the block of extra stuff will be allocated). So, we need to allocate 'target_fail_level - 1' plus + the extra stuff so that when it's freed, the memory block will be big enough for 'target_fail_level - 1' to be allocated. */ + amount_added_by_allocator = get_amount_added_by_memory_allocator(memory_alignment, target_fail_level); + amount_added_by_alignment = ((target_fail_level + UX_ALIGN_MIN) & (~(ULONG)UX_ALIGN_MIN)) - target_fail_level; /* The allocator aligns the requested size i.e. it adds some stuff. Take that into account now. */ + total_allocation_size = (target_fail_level) + amount_added_by_allocator + amount_added_by_alignment; +#else + total_allocation_size = target_fail_level; +#endif + main_allocation_ptr = ux_utility_memory_allocate(memory_alignment, memory_cache_flag, total_allocation_size); + if (main_allocation_ptr != NULL) + { + allocate_everything(memory_cache_flag); + + /* The next memory block _must_ be USED so that we don't merge with it, since it will cause the 'target_fail_level - 1' block to become + larger. The next memory block can be UNUSED if it's too small to be allocated by even a requested size of 1. */ + cur_memory_block = (UX_MEMORY_BLOCK *) main_allocation_ptr - 1; + next_memory_block = cur_memory_block->ux_memory_block_next; + if ((ULONG)next_memory_block->ux_memory_byte_pool == UX_BYTE_BLOCK_FREE) + { + next_memory_block->ux_memory_byte_pool = pool_ptr; + next_memory_block_buffer = (VOID *) (next_memory_block + 1); + add_memory_allocation_pointer(memory_cache_flag, next_memory_block_buffer); + + memory_used = (UCHAR *)next_memory_block->ux_memory_block_next - (UCHAR*)next_memory_block; + if (_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_start == _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start) + { + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available -= memory_used; + } + else + { + switch (memory_cache_flag) + { + case UX_CACHE_SAFE_MEMORY: + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available -= memory_used; + break; + default: + _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available -= memory_used; + break; + } + } + } + + /* Now free the 'target_fail_level - 1' block. */ + ux_utility_memory_free(main_allocation_ptr); + } + } + + ux_test_unignore_all_errors(); +} + +VOID ux_test_utility_sim_mem_free_all_flagged(ULONG memory_cache_flag) +{ + +ULONG i; + + for (i = 0; i < num_flagged_memory_allocation_pointers[memory_cache_flag]; i++) + { + ux_utility_memory_free(flagged_memory_allocation_pointers[memory_cache_flag][i]); + } + num_flagged_memory_allocation_pointers[memory_cache_flag] = 0; +} + +VOID ux_test_utility_sim_mem_test(VOID) +{ +ULONG mem_level = 400; +ULONG alloc_size; +VOID* tmp_alloc; + + printf("Test memory level: %ld\n", mem_level); + ux_test_utility_sim_mem_allocate_until(mem_level); + + alloc_size = mem_level; + tmp_alloc = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, alloc_size); + printf("Allocate size %ld: %p\n", alloc_size, tmp_alloc); + if (tmp_alloc) ux_utility_memory_free(tmp_alloc); + + alloc_size = mem_level >> 1; + tmp_alloc = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, alloc_size); + printf("Allocate size %ld: %p\n", alloc_size, tmp_alloc); + if (tmp_alloc) ux_utility_memory_free(tmp_alloc); + + alloc_size = mem_level - 4; + tmp_alloc = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, alloc_size); + printf("Allocate size -%ld(%ld): %p\n", mem_level - alloc_size, alloc_size, tmp_alloc); + if (tmp_alloc) ux_utility_memory_free(tmp_alloc); + + alloc_size = mem_level - 8; + tmp_alloc = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, alloc_size); + printf("Allocate size -%ld(%ld): %p\n", mem_level - alloc_size, alloc_size, tmp_alloc); + if (tmp_alloc) ux_utility_memory_free(tmp_alloc); + + alloc_size = mem_level - 16; + tmp_alloc = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, alloc_size); + printf("Allocate size -%ld(%ld): %p\n", mem_level - alloc_size, alloc_size, tmp_alloc); + if (tmp_alloc) ux_utility_memory_free(tmp_alloc); + + alloc_size = mem_level - 32; + tmp_alloc = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, alloc_size); + printf("Allocate size -%ld(%ld): %p\n", mem_level - alloc_size, alloc_size, tmp_alloc); + if (tmp_alloc) ux_utility_memory_free(tmp_alloc); + + alloc_size = mem_level - 64; + tmp_alloc = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, alloc_size); + printf("Allocate size -%ld(%ld): %p\n", mem_level - alloc_size, alloc_size, tmp_alloc); + if (tmp_alloc) ux_utility_memory_free(tmp_alloc); + + alloc_size = mem_level - 128; + tmp_alloc = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, alloc_size); + printf("Allocate size -%ld(%ld): %p\n", mem_level - alloc_size, alloc_size, tmp_alloc); + if (tmp_alloc) ux_utility_memory_free(tmp_alloc); + + alloc_size = mem_level - 256; + tmp_alloc = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, alloc_size); + printf("Allocate size -%ld(%ld): %p\n", mem_level - alloc_size, alloc_size, tmp_alloc); + if (tmp_alloc) ux_utility_memory_free(tmp_alloc); + + ux_test_utility_sim_mem_free_all(); + + printf("alloc resolution:\n"); + mem_level = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + tmp_alloc = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, 4); + printf("alloc 4 bytes: %ld -> %ld (%ld)\n", mem_level, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available, mem_level - _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + ux_utility_memory_free(tmp_alloc); + + mem_level = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + tmp_alloc = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, 16); + printf("alloc 16 bytes: %ld -> %ld (%ld)\n", mem_level, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available, mem_level - _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + ux_utility_memory_free(tmp_alloc); + + mem_level = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + tmp_alloc = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, 64); + printf("alloc 64 bytes: %ld -> %ld (%ld)\n", mem_level, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available, mem_level - _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + ux_utility_memory_free(tmp_alloc); + + mem_level = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + tmp_alloc = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, 100); + printf("alloc 100 bytes: %ld -> %ld (%ld)\n", mem_level, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available, mem_level - _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + ux_utility_memory_free(tmp_alloc); + + mem_level = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available; + tmp_alloc = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, 200); + printf("alloc 200 bytes: %ld -> %ld (%ld)\n", mem_level, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available, mem_level - _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available); + ux_utility_memory_free(tmp_alloc); + + printf("Halt this thread!\n"); + while(1) + { + + tx_thread_sleep(10); + } +}