Jelajahi Sumber

Merge branch 'master' into feature/github-7365-second

Zim Kalinowski 4 tahun lalu
induk
melakukan
ea7122e3fb
100 mengubah file dengan 5320 tambahan dan 494 penghapusan
  1. 4 0
      .flake8
  2. 1 1
      .github/workflows/python_lint.yml
  3. 3 0
      .gitignore
  4. 3 2
      .gitlab-ci.yml
  5. 4 0
      .gitlab/CODEOWNERS
  6. 10 0
      .gitlab/ci/build.yml
  7. 9 16
      .gitlab/ci/docs.yml
  8. 38 23
      .gitlab/ci/host-test.yml
  9. 9 0
      .gitlab/ci/pre_check.yml
  10. 4 0
      .gitlab/ci/rules.yml
  11. 55 59
      .gitlab/ci/static-code-analysis.yml
  12. 46 40
      .gitlab/ci/target-test.yml
  13. 19 6
      .pre-commit-config.yaml
  14. 57 3
      CMakeLists.txt
  15. 0 1
      CONTRIBUTING.rst
  16. 0 1
      Kconfig
  17. 18 6
      README.md
  18. 19 7
      README_CN.md
  19. 160 0
      components/README.md
  20. 1 1
      components/app_trace/CMakeLists.txt
  21. 67 80
      components/app_trace/gcov/gcov_rtio.c
  22. 5 4
      components/app_trace/sys_view/Sample/Config/SEGGER_SYSVIEW_Config_FreeRTOS.c
  23. 5 5
      components/app_trace/sys_view/Sample/OS/SEGGER_SYSVIEW_FreeRTOS.h
  24. 1 0
      components/app_update/CMakeLists.txt
  25. 26 6
      components/bootloader/Kconfig.projbuild
  26. 1 0
      components/bootloader/subproject/main/ld/esp32/bootloader.ld
  27. 1 0
      components/bootloader/subproject/main/ld/esp32c3/bootloader.ld
  28. 1 0
      components/bootloader/subproject/main/ld/esp32h2/bootloader.ld
  29. 1 0
      components/bootloader/subproject/main/ld/esp32s2/bootloader.ld
  30. 1 0
      components/bootloader/subproject/main/ld/esp32s3/bootloader.ld
  31. 1 0
      components/bootloader_support/CMakeLists.txt
  32. 9 0
      components/bootloader_support/include/bootloader_common.h
  33. 15 0
      components/bootloader_support/include/bootloader_flash.h
  34. 10 0
      components/bootloader_support/include_bootloader/bootloader_flash_priv.h
  35. 27 0
      components/bootloader_support/include_bootloader/bootloader_soc.h
  36. 13 1
      components/bootloader_support/src/bootloader_common.c
  37. 2 2
      components/bootloader_support/src/bootloader_console.c
  38. 3 3
      components/bootloader_support/src/bootloader_efuse_esp32.c
  39. 1 1
      components/bootloader_support/src/bootloader_efuse_esp32s2.c
  40. 179 22
      components/bootloader_support/src/bootloader_flash.c
  41. 8 8
      components/bootloader_support/src/bootloader_flash_config_esp32s3.c
  42. 7 0
      components/bootloader_support/src/bootloader_utility.c
  43. 5 0
      components/bootloader_support/src/esp32/bootloader_esp32.c
  44. 21 0
      components/bootloader_support/src/esp32/bootloader_soc.c
  45. 29 6
      components/bootloader_support/src/esp32c3/bootloader_esp32c3.c
  46. 41 0
      components/bootloader_support/src/esp32c3/bootloader_soc.c
  47. 6 0
      components/bootloader_support/src/esp32c3/flash_encryption_secure_features.c
  48. 15 0
      components/bootloader_support/src/esp32c3/secure_boot_secure_features.c
  49. 13 19
      components/bootloader_support/src/esp32h2/bootloader_esp32h2.c
  50. 41 0
      components/bootloader_support/src/esp32h2/bootloader_soc.c
  51. 5 0
      components/bootloader_support/src/esp32s2/bootloader_esp32s2.c
  52. 21 0
      components/bootloader_support/src/esp32s2/bootloader_soc.c
  53. 6 0
      components/bootloader_support/src/esp32s2/flash_encryption_secure_features.c
  54. 15 0
      components/bootloader_support/src/esp32s2/secure_boot_secure_features.c
  55. 16 1
      components/bootloader_support/src/esp32s3/bootloader_esp32s3.c
  56. 41 0
      components/bootloader_support/src/esp32s3/bootloader_soc.c
  57. 6 0
      components/bootloader_support/src/esp32s3/flash_encryption_secure_features.c
  58. 16 0
      components/bootloader_support/src/esp32s3/secure_boot_secure_features.c
  59. 0 8
      components/bootloader_support/src/flash_qio_mode.c
  60. 19 4
      components/bt/CMakeLists.txt
  61. 5 31
      components/bt/Kconfig
  62. 12 0
      components/bt/common/btc/core/btc_task.c
  63. 10 0
      components/bt/common/btc/include/btc/btc_task.h
  64. 11 0
      components/bt/common/osi/alarm.c
  65. 4 0
      components/bt/common/osi/include/osi/alarm.h
  66. 5 0
      components/bt/component.mk
  67. 14 6
      components/bt/controller/esp32/Kconfig.in
  68. 281 25
      components/bt/controller/esp32/bt.c
  69. 306 0
      components/bt/controller/esp32/hli_api.c
  70. 176 0
      components/bt/controller/esp32/hli_api.h
  71. 275 0
      components/bt/controller/esp32/hli_vectors.S
  72. 2 1
      components/bt/controller/esp32c3/Kconfig.in
  73. 11 13
      components/bt/controller/esp32c3/bt.c
  74. 0 0
      components/bt/controller/esp32h2/Kconfig.in
  75. 0 0
      components/bt/controller/esp32s2/Kconfig.in
  76. 3 2
      components/bt/controller/esp32s3/Kconfig.in
  77. 11 13
      components/bt/controller/esp32s3/bt.c
  78. 1 1
      components/bt/controller/lib_esp32
  79. 1 1
      components/bt/controller/lib_esp32c3_family
  80. 4 4
      components/bt/esp_ble_mesh/Kconfig.in
  81. 18 0
      components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_provisioning_api.h
  82. 12 2
      components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h
  83. 23 12
      components/bt/esp_ble_mesh/mesh_core/provisioner_prov.c
  84. 17 8
      components/bt/host/bluedroid/Kconfig.in
  85. 176 0
      components/bt/host/bluedroid/api/esp_hidd_api.c
  86. 254 0
      components/bt/host/bluedroid/api/esp_hidh_api.c
  87. 6 6
      components/bt/host/bluedroid/api/include/api/esp_gap_ble_api.h
  88. 1 1
      components/bt/host/bluedroid/api/include/api/esp_gattc_api.h
  89. 379 0
      components/bt/host/bluedroid/api/include/api/esp_hidd_api.h
  90. 465 0
      components/bt/host/bluedroid/api/include/api/esp_hidh_api.h
  91. 29 9
      components/bt/host/bluedroid/bta/dm/bta_dm_act.c
  92. 49 9
      components/bt/host/bluedroid/bta/dm/bta_dm_cfg.c
  93. 6 0
      components/bt/host/bluedroid/bta/dm/include/bta_dm_int.h
  94. 5 1
      components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c
  95. 774 0
      components/bt/host/bluedroid/bta/hd/bta_hd_act.c
  96. 287 0
      components/bt/host/bluedroid/bta/hd/bta_hd_api.c
  97. 320 0
      components/bt/host/bluedroid/bta/hd/bta_hd_main.c
  98. 168 0
      components/bt/host/bluedroid/bta/hd/include/bta_hd_int.h
  99. 1 1
      components/bt/host/bluedroid/bta/hf_client/bta_hf_client_main.c
  100. 38 12
      components/bt/host/bluedroid/bta/hh/bta_hh_act.c

+ 4 - 0
.flake8

@@ -164,3 +164,7 @@ exclude =
         components/wifi_provisioning/python/wifi_constants_pb2.py,
         components/esp_local_ctrl/python/esp_local_ctrl_pb2.py,
         examples/provisioning/legacy/custom_config/components/custom_provisioning/python/custom_config_pb2.py,
+
+per-file-ignores =
+    # Sphinx conf.py files use star imports to setup config variables
+        docs/conf_common.py: F405

+ 1 - 1
.github/workflows/python_lint.yml

@@ -13,7 +13,7 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        python-version: [2.7, 3.5, 3.6, 3.7, 3.8]
+        python-version: [3.6, 3.7, 3.8]
 
     steps:
       - name: Checkout

+ 3 - 0
.gitignore

@@ -88,3 +88,6 @@ build
 
 # lock files for examples and components
 dependencies.lock
+
+# managed_components for examples
+managed_components

+ 3 - 2
.gitlab-ci.yml

@@ -48,10 +48,11 @@ variables:
 
   # Docker images
   BOT_DOCKER_IMAGE_TAG: ":latest"
-  ESP_IDF_DOC_ENV_IMAGE: "$CI_DOCKER_REGISTRY/esp-idf-doc-env:v4.4-1-v2"
+  ESP_IDF_DOC_ENV_IMAGE: "$CI_DOCKER_REGISTRY/esp-idf-doc-env:v4.4-1-v4"
   ESP_ENV_IMAGE: "$CI_DOCKER_REGISTRY/esp-env:v4.4-1"
   AFL_FUZZER_TEST_IMAGE: "$CI_DOCKER_REGISTRY/afl-fuzzer-test:v4.4-1-1"
-  CLANG_STATIC_ANALYSIS_IMAGE: "${CI_DOCKER_REGISTRY}/clang-static-analysis:v4.4-1-1"
+  CLANG_STATIC_ANALYSIS_IMAGE: "${CI_DOCKER_REGISTRY}/clang-static-analysis:v4.4-1-2"
+  SONARQUBE_SCANNER_IMAGE: "${CI_DOCKER_REGISTRY}/sonarqube-scanner:3"
 
   # target test config file, used by assign test job
   CI_TARGET_TEST_CONFIG_FILE: "$CI_PROJECT_DIR/.gitlab/ci/target-test.yml"

+ 4 - 0
.gitlab/CODEOWNERS

@@ -57,6 +57,7 @@
 /export.*                             @esp-idf-codeowners/tools
 /install.*                            @esp-idf-codeowners/tools
 /sdkconfig.rename                     @esp-idf-codeowners/build-config
+/sonar-project.properties             @esp-idf-codeowners/ci
 
 # sort-order-reset
 
@@ -66,6 +67,7 @@
 /components/bootloader*/              @esp-idf-codeowners/system @esp-idf-codeowners/security
 /components/bt/                       @esp-idf-codeowners/bluetooth
 /components/cbor/                     @esp-idf-codeowners/app-utilities
+/components/cmock/                    @esp-idf-codeowners/system
 /components/coap/                     @esp-idf-codeowners/app-utilities
 /components/console/                  @esp-idf-codeowners/system @esp-idf-codeowners/app-utilities
 /components/cxx/                      @esp-idf-codeowners/system
@@ -159,6 +161,7 @@
 /examples/ethernet/           @esp-idf-codeowners/network
 /examples/get-started/        @esp-idf-codeowners/system
 /examples/mesh/               @esp-idf-codeowners/wifi
+/examples/network/            @esp-idf-codeowners/network @esp-idf-codeowners/wifi
 /examples/openthread/         @esp-idf-codeowners/ieee802154
 /examples/peripherals/        @esp-idf-codeowners/peripherals
 /examples/protocols/          @esp-idf-codeowners/network @esp-idf-codeowners/app-utilities
@@ -183,6 +186,7 @@
 /tools/kconfig*/              @esp-idf-codeowners/build-config
 /tools/ldgen/                 @esp-idf-codeowners/build-config
 /tools/mass_mfg/              @esp-idf-codeowners/app-utilities
+/tools/mocks/                 @esp-idf-codeowners/system
 
 ## Note: owners here should be the same as the owners for the same example subdir, above
 /tools/test_apps/build_system/       @esp-idf-codeowners/build-config

+ 10 - 0
.gitlab/ci/build.yml

@@ -221,6 +221,14 @@ build_examples_cmake_esp32s2:
   variables:
     IDF_TARGET: esp32s2
 
+build_examples_cmake_esp32s3:
+  extends:
+    - .build_examples_cmake_template
+    - .rules:build:example_test-esp32s3
+  parallel: 8
+  variables:
+    IDF_TARGET: esp32s3
+
 build_examples_cmake_esp32c3:
   extends:
     - .build_examples_cmake_template
@@ -344,6 +352,7 @@ build_docker:
     - .before_script_minimal
     - .rules:build:docker
   stage: host_test
+  needs: []
   image: espressif/docker-builder:1
   tags:
     - build_docker_amd64_brno
@@ -366,6 +375,7 @@ build_docker:
     - .before_script_minimal
     - .rules:build:windows
   stage: host_test
+  needs: []
   image: $CI_DOCKER_REGISTRY/esp32-toolchain-win-cross
   tags:
     - build

+ 9 - 16
.gitlab/ci/docs.yml

@@ -39,7 +39,6 @@
 check_readme_links:
   extends:
     - .pre_check_job_template
-    - .doc-rules:build:docs
   tags: ["build", "amd64", "internet"]
   allow_failure: true
   script:
@@ -62,12 +61,12 @@ check_docs_lang_sync:
   dependencies: []
   script:
     - cd docs
-    - python -m pip install -r requirements.txt
-    - python ./build_docs.py -bs $DOC_BUILDERS -l $DOCLANG -t $DOCTGT build
+    - pip install -r requirements.txt
+    - build-docs -t $DOCTGT -bs $DOC_BUILDERS -l $DOCLANG build
   parallel:
     matrix:
       - DOCLANG: ["en", "zh_CN"]
-        DOCTGT: ["esp32", "esp32s2", "esp32c3"]
+        DOCTGT: ["esp32", "esp32s2", "esp32s3", "esp32c3"]
 
 check_docs_gh_links:
   image: $ESP_IDF_DOC_ENV_IMAGE
@@ -78,8 +77,8 @@ check_docs_gh_links:
     - .doc-rules:build:docs
   script:
     - cd docs
-    - python -m pip install -r requirements.txt
-    - python ./build_docs.py gh-linkcheck
+    - pip install -r requirements.txt
+    - build-docs gh-linkcheck
 
 # stage: build_doc
 # Add this stage to let the build_docs job run in parallel with build
@@ -129,13 +128,6 @@ build_docs_html_fast:
   variables:
     DOC_BUILDERS: "html"
     DOCS_FAST_BUILD: "yes"
-  # matrix is redefined to include esp32s3 here
-  # that we can build for S3 MRs during bringup phase without
-  # anything being built and published from master branch
-  parallel:
-    matrix:
-      - DOCLANG: ["en", "zh_CN"]
-        DOCTGT: ["esp32", "esp32s2", "esp32s3", "esp32c3"]
 
 build_docs_pdf:
   extends:
@@ -168,7 +160,8 @@ build_docs_pdf:
   script:
     - add_doc_server_ssh_keys $DOCS_DEPLOY_PRIVATEKEY $DOCS_DEPLOY_SERVER $DOCS_DEPLOY_SERVER_USER
     - export GIT_VER=$(git describe --always)
-    - python ${IDF_PATH}/tools/ci/deploy_docs.py
+    - pip install -r docs/requirements.txt
+    - deploy-docs
 
 # stage: test_deploy
 deploy_docs_preview:
@@ -227,6 +220,6 @@ check_doc_links:
   allow_failure: true
   script:
     - cd docs
-    - python -m pip install -r requirements.txt
+    - pip install -r requirements.txt
     # At the moment this check will always fail due to multiple known limitations, ignore result
-    - python ./build_docs.py -l $DOCLANG -t $DOCTGT linkcheck || { echo "THERE ARE ISSUES DUE TO KNOWN LIMITATIONS, PLEASE FIX THEM. Nowadays we're ignored them to pass pipeline."; true; }
+    - build-docs -t $DOCTGT -l $DOCLANG linkcheck || { echo "THERE ARE ISSUES DUE TO KNOWN LIMITATIONS, PLEASE FIX THEM. Nowadays we're ignored them to pass pipeline."; true; }

+ 38 - 23
.gitlab/ci/host-test.yml

@@ -220,11 +220,6 @@ test_efuse_table_on_host_esp32s2:
   variables:
     IDF_TARGET: esp32s2
 
-test_efuse_table_on_host_esp32s2:
-  extends: .test_efuse_table_on_host_template
-  variables:
-    IDF_TARGET: esp32s2
-
 test_efuse_table_on_host_esp32s3:
   extends: .test_efuse_table_on_host_template
   variables:
@@ -250,10 +245,11 @@ test_espcoredump:
     expire_in: 1 week
   variables:
     IDF_COREDUMP_ELF_REPO: "https://gitlab-ci-token:${BOT_TOKEN}@${CI_SERVER_HOST}:${CI_SERVER_PORT}/idf/idf-coredump-elf.git"
+    IDF_COREDUMP_ELF_TAG: idf-20210910-00
     # install CMake version specified in tools.json
     SETUP_TOOLS_LIST: "all"
   script:
-    - retry_failed git clone ${IDF_COREDUMP_ELF_REPO} -b master
+    - retry_failed git clone ${IDF_COREDUMP_ELF_REPO} -b $IDF_COREDUMP_ELF_TAG
     - cd ${IDF_PATH}/components/espcoredump/test/
     - ./test_espcoredump.sh ${CI_PROJECT_DIR}/idf-coredump-elf
 
@@ -295,22 +291,6 @@ test_mkuf2:
     - cd ${IDF_PATH}/tools/test_mkuf2
     - ./test_mkuf2.py
 
-test_docs:
-  extends: .host_test_template
-  image: $ESP_IDF_DOC_ENV_IMAGE
-  variables:
-    PYTHON_VER: 3.6.13
-  artifacts:
-    when: on_failure
-    paths:
-      - docs/test/_build/*/*/*/html/*
-    expire_in: 1 week
-  script:
-    - cd ${IDF_PATH}/docs/test
-    - python -m pip install -r ${IDF_PATH}/docs/requirements.txt
-    - ./test_docs.py
-    - ./test_sphinx_idf_extensions.py
-
 test_autocomplete:
   extends: .host_test_template
   image: $CI_DOCKER_REGISTRY/linux-shells:1
@@ -340,7 +320,7 @@ test_nvs_page:
   script:
     - cd ${IDF_PATH}/components/nvs_flash/host_test/nvs_page_test
     - idf.py build
-    - build/host_nvs_page_test.elf
+    - build/test_nvs_page_host.elf
 
 test_log:
   extends: .host_test_template
@@ -349,9 +329,44 @@ test_log:
     - idf.py build
     - build/test_log_host.elf
 
+test_esp_event:
+  extends: .host_test_template
+  script:
+    - cd ${IDF_PATH}/components/esp_event/host_test/esp_event_unit_test
+    - idf.py build
+    - build/test_esp_event_host.elf
+
+test_esp_timer_cxx:
+  extends: .host_test_template
+  script:
+    - cd ${IDF_PATH}/examples/cxx/experimental/experimental_cpp_component/host_test/esp_timer
+    - idf.py build
+    - build/test_esp_timer_cxx_host.elf
+
 test_eh_frame_parser:
   extends: .host_test_template
   script:
     - cd ${IDF_PATH}/components/esp_system/test_eh_frame_parser
     - make
     - ./eh_frame_test
+
+test_rom_on_linux_works:
+  extends: .host_test_template
+  script:
+    - cd ${IDF_PATH}/components/esp_rom/host_test/rom_test
+    - idf.py build
+    - build/test_rom_host.elf
+
+test_cxx_gpio:
+  extends: .host_test_template
+  script:
+    - cd ${IDF_PATH}/examples/cxx/experimental/experimental_cpp_component/host_test/gpio
+    - idf.py build
+    - build/test_gpio_cxx_host.elf
+
+test_linux_example:
+  extends: .host_test_template
+  script:
+    - cd ${IDF_PATH}/examples/build_system/cmake/linux_host_app
+    - idf.py build
+    - build/linux_host_app.elf

+ 9 - 0
.gitlab/ci/pre_check.yml

@@ -113,6 +113,15 @@ check_public_headers:
   script:
     - python tools/ci/check_public_headers.py --jobs 4 --prefix xtensa-esp32-elf-
 
+check_soc_struct_headers:
+  extends:
+    - .pre_check_base_template
+    - .rules:build
+  tags:
+    - build
+  script:
+    - find ${IDF_PATH}/components/soc/*/include/soc/ -name "*_struct.h" -print0 | xargs -0 -n1 ./tools/ci/check_soc_struct_headers.py
+
 check_esp_err_to_name:
   extends:
     - .pre_check_base_template

+ 4 - 0
.gitlab/ci/rules.yml

@@ -3,7 +3,10 @@
 ############
 .patterns-c-files: &patterns-c-files
   - ".gitlab/ci/static-code-analysis.yml"
+
   - "tools/ci/static-analysis-rules.yml"
+  - "tools/ci/clang_tidy_dirs.txt"
+
   - "**/*.{c,C}"
   - "**/*.{h,H}"
   - "components/**/Kconfig"
@@ -37,6 +40,7 @@
 
 .patterns-build_components: &patterns-build_components
   - "components/**/*"
+  - "examples/cxx/experimental/experimental_cpp_component/*"
 
 .patterns-build_system: &patterns-build_system
   - "tools/cmake/**/*"

+ 55 - 59
.gitlab/ci/static-code-analysis.yml

@@ -5,17 +5,46 @@ clang_tidy_check:
     - .rules:patterns:clang_tidy
   image: ${CLANG_STATIC_ANALYSIS_IMAGE}
   artifacts:
-    reports:
-      junit: $IDF_PATH/output.xml
-    when: always
     paths:
-      - $IDF_PATH/examples/get-started/hello_world/tidybuild/report/*
+      - $OUTPUT_DIR
+    when: always
     expire_in: 1 day
+  variables:
+    CLANG_TIDY_RUNNER_PROJ: 2107  # idf/clang-tidy-runner
+    CLANG_TIDY_DIRS_TXT: ${CI_PROJECT_DIR}/tools/ci/clang_tidy_dirs.txt
+    RULES_FILE: ${CI_PROJECT_DIR}/tools/ci/static-analysis-rules.yml
+    OUTPUT_DIR: ${CI_PROJECT_DIR}/clang_tidy_reports
   script:
-    - retry_failed git clone $IDF_ANALYSIS_UTILS static_analysis_utils && cd static_analysis_utils
-    # Setup parameters of triggered/regular job
-    - export TARGET_BRANCH=${BOT_CUSTOMIZED_REVISION-}
-    - ./analyze.sh $IDF_PATH/examples/get-started/hello_world/ $IDF_PATH/tools/ci/static-analysis-rules.yml $IDF_PATH/output.xml
+    - python -m pip install -U pip
+    - internal_pip_install $CLANG_TIDY_RUNNER_PROJ pyclang
+    - export PATH=$PATH:$(python -c "import sys; print(sys.executable.rsplit('/', 1)[0])")
+    - dirs=$(cat ${CLANG_TIDY_DIRS_TXT} | while read line; do echo ${CI_PROJECT_DIR}/${line}; done | xargs)
+    - run_cmd idf_clang ${dirs}
+      --output-path ${OUTPUT_DIR}
+      --limit-file ${RULES_FILE}
+      --xtensa-include-dir
+      --run-clang-tidy-py ${RUN_CLANG_TIDY_PY}
+
+check_pylint:
+  extends:
+    - .pre_check_base_template
+    - .rules:patterns:python-files
+    - .before_script_minimal
+  image: $SONARQUBE_SCANNER_IMAGE
+  artifacts:
+    when: always
+    paths:
+      - pylint-report.txt
+    expire_in: 1 week
+  script:
+    - export PYTHONPATH="$IDF_PATH/tools:$IDF_PATH/tools/ci/python_packages:$PYTHONPATH"
+    - |
+      if [ -n "$CI_MERGE_REQUEST_IID" ]; then
+        export files=$(python ${CI_PROJECT_DIR}/tools/ci/ci_get_mr_info.py files ${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME} | grep ".py");
+      else
+        export files=$(find . -iname "*.py" -print);
+      fi
+    - pylint --rcfile=.pylintrc $files -r n --output-format=parseable > pylint-report.txt || exit 0
 
 # build stage
 # Sonarqube related jobs put here for this reason:
@@ -33,26 +62,31 @@ clang_tidy_check:
 .sonar_scan_template:
   stage: build
   image:
-    name: $CI_DOCKER_REGISTRY/sonarqube-scanner:2
+    name: $SONARQUBE_SCANNER_IMAGE
   before_script:
     - source tools/ci/utils.sh
     - export PYTHONPATH="$CI_PROJECT_DIR/tools:$CI_PROJECT_DIR/tools/ci/python_packages:$PYTHONPATH"
     - fetch_submodules
     # Exclude the submodules, all paths ends with /**
-    - export SUBMODULES=$(get_all_submodules)
+    - submodules=$(get_all_submodules)
     # get all exclude paths specified in tools/ci/sonar_exclude_list.txt | ignore lines start with # | xargs | replace all <space> to <comma>
-    - export CUSTOM_EXCLUDES=$(cat $CI_PROJECT_DIR/tools/ci/sonar_exclude_list.txt | grep -v '^#' | xargs | sed -e 's/ /,/g')
+    - custom_excludes=$(cat $CI_PROJECT_DIR/tools/ci/sonar_exclude_list.txt | grep -v '^#' | xargs | sed -e 's/ /,/g')
     # Exclude the report dir as well
-    - export EXCLUSIONS="$CUSTOM_EXCLUDES,$SUBMODULES,$REPORT_DIR/**,docs/_static/**,**/*.png,**/*.jpg"
-    - python $NORMALIZE_CLANGTIDY_PY $CI_PROJECT_DIR/$REPORT_DIR/warnings.txt $CI_PROJECT_DIR/$REPORT_DIR/clang_tidy_report.txt $CI_PROJECT_DIR
+    - export EXCLUSIONS="$custom_excludes,$submodules"
+    - export SONAR_SCANNER_OPTS="-Xmx2048m"
+
   variables:
     GIT_DEPTH: 0
-    NORMALIZE_CLANGTIDY_PY: $CI_PROJECT_DIR/tools/ci/normalize_clangtidy_path.py
-    REPORT_DIR: examples/get-started/hello_world/tidybuild/report
+    REPORT_PATTERN: clang_tidy_reports/*.txt
+  artifacts:
+    when: always
+    paths:
+      - $REPORT_PATTERN
   tags:
     - host_test
   dependencies:  # Here is not a hard dependency relationship, could be skipped when only python files changed. so we do not use "needs" here.
     - clang_tidy_check
+    - check_pylint
 
 code_quality_check:
   extends:
@@ -67,23 +101,16 @@ code_quality_check:
     - test -n "$CI_MERGE_REQUEST_COMMITS" || exit 0
     - sonar-scanner
       -Dsonar.analysis.mode=preview
-      -Dsonar.branch.name=$CI_COMMIT_REF_NAME
-      -Dsonar.cxx.clangtidy.reportPath=$REPORT_DIR/clang_tidy_report.txt
-      -Dsonar.cxx.includeDirectories=components,/usr/include
+      -Dsonar.branch.name=$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
+      -Dsonar.cxx.clangtidy.reportPath=$REPORT_PATTERN
       -Dsonar.exclusions=$EXCLUSIONS
       -Dsonar.gitlab.ci_merge_request_iid=$CI_MERGE_REQUEST_IID
       -Dsonar.gitlab.commit_sha=$CI_MERGE_REQUEST_COMMITS
-      -Dsonar.gitlab.failure_notification_mode=exit-code
       -Dsonar.gitlab.merge_request_discussion=true
-      -Dsonar.gitlab.project_id=$CI_PROJECT_ID
-      -Dsonar.gitlab.ref_name=$CI_COMMIT_REF_NAME
+      -Dsonar.gitlab.ref_name=$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
       -Dsonar.host.url=$SONAR_HOST_URL
       -Dsonar.login=$SONAR_LOGIN
-      -Dsonar.projectBaseDir=$CI_PROJECT_DIR
-      -Dsonar.projectKey=esp-idf
-      -Dsonar.python.pylint_config=.pylintrc
-      -Dsonar.sourceEncoding=UTF-8
-      -Dsonar.sources=$CI_PROJECT_DIR
+      -Dsonar.python.pylint.reportPath=pylint-report.txt
 
 code_quality_report:
   extends:
@@ -94,41 +121,10 @@ code_quality_report:
   script:
     - sonar-scanner
       -Dsonar.branch.name=$CI_COMMIT_REF_NAME
-      -Dsonar.cxx.clangtidy.reportPath=$REPORT_DIR/clang_tidy_report.txt
-      -Dsonar.cxx.includeDirectories=components,/usr/include
+      -Dsonar.cxx.clangtidy.reportPath=$REPORT_PATTERN
       -Dsonar.exclusions=$EXCLUSIONS
       -Dsonar.gitlab.commit_sha=$CI_COMMIT_SHA
-      -Dsonar.gitlab.failure_notification_mode=exit-code
-      -Dsonar.gitlab.project_id=$CI_PROJECT_ID
       -Dsonar.gitlab.ref_name=$CI_COMMIT_REF_NAME
       -Dsonar.host.url=$SONAR_HOST_URL
       -Dsonar.login=$SONAR_LOGIN
-      -Dsonar.projectBaseDir=$CI_PROJECT_DIR
-      -Dsonar.projectKey=esp-idf
-      -Dsonar.python.pylint_config=.pylintrc
-      -Dsonar.sourceEncoding=UTF-8
-      -Dsonar.sources=$CI_PROJECT_DIR
-
-# deploy stage
-clang_tidy_deploy:
-  extends:
-    - .deploy_job_template
-    - .rules:patterns:clang_tidy
-  needs:
-    - clang_tidy_check
-  tags:
-    - deploy
-    - shiny
-  script:
-    - add_doc_server_ssh_keys $DOCS_DEPLOY_KEY $DOCS_SERVER $DOCS_SERVER_USER
-    - export GIT_VER=$(git describe --always)
-    - cd $IDF_PATH/examples/get-started/hello_world/tidybuild
-    - mv report $GIT_VER
-    - tar czvf $GIT_VER.tar.gz $GIT_VER
-    - export STATIC_REPORT_PATH="web/static_analysis/esp-idf/"
-    - ssh $DOCS_SERVER -x "mkdir -p $STATIC_REPORT_PATH/clang-tidy"
-    - scp $GIT_VER.tar.gz $DOCS_SERVER:$STATIC_REPORT_PATH/clang-tidy
-    - ssh $DOCS_SERVER -x "cd $STATIC_REPORT_PATH/clang-tidy && tar xzvf $GIT_VER.tar.gz && rm -f latest && ln -s $GIT_VER latest"
-    # add link to view the report
-    - echo "[static analysis][clang tidy] $CI_DOCKER_REGISTRY/static_analysis/esp-idf/clang-tidy/${GIT_VER}/index.html"
-    - test ! -e ${GIT_VER}/FAILED_RULES || { echo 'Failed static analysis rules!'; cat ${GIT_VER}/FAILED_RULES; exit 1; }
+      -Dsonar.python.pylint.reportPath=pylint-report.txt

+ 46 - 40
.gitlab/ci/target-test.yml

@@ -46,7 +46,7 @@
   extends:
     - .example_test_template
     - .rules:test:example_test-esp32
-variables:
+  variables:
     SUBMODULES_TO_FETCH: "all"
 
 test_weekend_mqtt:
@@ -60,7 +60,7 @@ test_weekend_mqtt:
     - export MQTT_PUBLISH_TEST=1
     - export TEST_PATH=$CI_PROJECT_DIR/tools/test_apps/protocols/mqtt/publish_connect_test
     - cd $IDF_PATH/tools/ci/python_packages/tiny_test_fw/bin
-    - run_cmd python Runner.py $TEST_PATH -c $TEST_PATH/publish_connect_mqtt_.yml -e $TEST_PATH/env.yml
+    - run_cmd python Runner.py $TEST_PATH -c $TEST_PATH/publish_connect_mqtt_.yml
 
 .example_test_esp32_template:
   extends:
@@ -97,7 +97,7 @@ example_test_001B_V3:
 
 example_test_001C:
   extends: .example_test_esp32_template
-  parallel: 3
+  parallel: 4
   tags:
     - ESP32
     - Example_GENERIC
@@ -129,7 +129,7 @@ example_test_002:
     - ESP32
     - Example_ShieldBox_Basic
 
-example_test_enternet:
+example_test_ethernet:
   extends: .example_test_esp32_template
   tags:
     - ESP32
@@ -270,20 +270,17 @@ example_test_ESP32_SDSPI:
     - ESP32
     - UT_T1_SPIMODE
 
-# uncomment when ESP32S2 & ESP32C3 runners with external SD connected over SPI are available
-# ensure the runners have required tags created
-#
-#example_test_ESP32S2_SDSPI:
-#  extends: .example_test_esp32s2_template
-#  tags:
-#    - ESP32S2
-#    - UT_T1_SPIMODE
-#
-#example_test_ESP32C3_SDSPI:
-#  extends: .example_test_esp32c3_template
-#  tags:
-#    - ESP32C3
-#    - UT_T1_SPIMODE
+example_test_ESP32S2_SDSPI:
+  extends: .example_test_esp32s2_template
+  tags:
+    - ESP32S2
+    - UT_T1_SPIMODE
+
+example_test_ESP32C3_SDSPI:
+  extends: .example_test_esp32c3_template
+  tags:
+    - ESP32C3
+    - UT_T1_SPIMODE
 
 .test_app_template:
   extends: .target_test_job_template
@@ -447,7 +444,7 @@ UT_001:
 
 UT_002:
   extends: .unit_test_esp32_template
-  parallel: 16
+  parallel: 14
   tags:
     - ESP32_IDF
     - UT_T1_1
@@ -482,7 +479,7 @@ UT_006:
 
 UT_007:
   extends: .unit_test_esp32_template
-  parallel: 2
+  parallel: 4
   tags:
     - ESP32_IDF
     - UT_T1_1
@@ -508,19 +505,6 @@ UT_014:
     - UT_T2_RS485
     - psram
 
-UT_015:
-  extends: .unit_test_esp32_template
-  tags:
-    - ESP32_IDF
-    - UT_T1_RMT
-
-UT_016:
-  extends: .unit_test_esp32_template
-  tags:
-    - ESP32_IDF
-    - UT_T1_RMT
-    - psram
-
 UT_017:
   extends: .unit_test_esp32_template
   tags:
@@ -544,7 +528,6 @@ UT_020:
 
 UT_021:
   extends: .unit_test_esp32_template
-  parallel: 2
   tags:
     - ESP32_IDF
     - psram
@@ -579,7 +562,7 @@ UT_033:
 
 UT_034:
   extends: .unit_test_esp32_template
-  parallel: 3
+  parallel: 2
   tags:
     - ESP32_IDF
     - UT_T1_ESP_FLASH
@@ -607,7 +590,7 @@ UT_036:
 
 UT_038:
   extends: .unit_test_esp32s2_template
-  parallel: 3
+  parallel: 2
   tags:
     - ESP32S2_IDF
     - UT_T1_ESP_FLASH
@@ -647,7 +630,7 @@ UT_046:
 
 UT_047:
   extends: .unit_test_esp32s2_template
-  parallel: 3
+  parallel: 5
   tags:
     - ESP32S2_IDF
     - UT_T1_1
@@ -658,9 +641,15 @@ UT_S2_SPI_DUAL:
     - ESP32S2_IDF
     - Example_SPI_Multi_device
 
+UT_S2_SDSPI:
+  extends: .unit_test_esp32s2_template
+  tags:
+    - ESP32S2_IDF
+    - UT_T1_SPIMODE
+
 UT_C3:
   extends: .unit_test_esp32c3_template
-  parallel: 33
+  parallel: 32
   tags:
     - ESP32C3_IDF
     - UT_T1_1
@@ -674,7 +663,6 @@ UT_C3_FLASH:
 
 UT_C3_SPI_DUAL:
   extends: .unit_test_esp32c3_template
-  parallel: 2
   tags:
     - ESP32C3_IDF
     - Example_SPI_Multi_device
@@ -697,9 +685,15 @@ UT_C3_FLASH_SUSPEND:
     - ESP32C3_IDF
     - UT_T1_Flash_Suspend
 
+UT_C3_SDSPI:
+  extends: .unit_test_esp32c3_template
+  tags:
+    - ESP32C3_IDF
+    - UT_T1_SPIMODE
+
 UT_S3:
   extends: .unit_test_esp32s3_template
-  parallel: 27
+  parallel: 29
   tags:
     - ESP32S3_IDF
     - UT_T1_1
@@ -717,6 +711,18 @@ UT_S3_FLASH:
     - ESP32S3_IDF
     - UT_T1_ESP_FLASH
 
+component_ut_test_ip101:
+  extends: .component_ut_esp32_template
+  tags:
+    - ESP32
+    - COMPONENT_UT_IP101
+
+component_ut_test_lan8720:
+  extends: .component_ut_esp32_template
+  tags:
+    - ESP32
+    - COMPONENT_UT_LAN8720
+
 .integration_test_template:
   extends:
     - .target_test_job_template

+ 19 - 6
.pre-commit-config.yaml

@@ -3,7 +3,7 @@
 
 repos:
   - repo: https://github.com/pre-commit/pre-commit-hooks
-    rev: v3.4.0
+    rev: v4.0.1
     hooks:
       - id: trailing-whitespace
         # note: whitespace exclusions use multiline regex, see https://pre-commit.com/#regular-expressions
@@ -26,12 +26,12 @@ repos:
         args: ['-f=lf']
       - id: double-quote-string-fixer
   - repo: https://gitlab.com/pycqa/flake8
-    rev: 3.8.4
+    rev: 3.9.2
     hooks:
       - id: flake8
         args: ['--config=.flake8', '--tee', '--benchmark']
   - repo: https://github.com/pycqa/isort
-    rev: 5.6.4
+    rev: 5.9.3
     hooks:
       - id: isort
         name: isort (python)
@@ -92,11 +92,24 @@ repos:
       - id: mypy-check
         name: Check type annotations in python files
         entry: tools/ci/check_type_comments.py
-        additional_dependencies: ['mypy==0.800', 'mypy-extensions==0.4.3']
+        additional_dependencies:
+          - 'mypy==0.800'
+          - 'mypy-extensions==0.4.3'
         language: python
         types: [python]
+      - id: check-copyright
+        name: Check copyright notices
+        entry: tools/ci/check_copyright.py --verbose --replace
+        additional_dependencies:
+          - 'comment_parser == 1.2.3'
+          - 'thefuzz == 0.19.0'
+          - 'thefuzz[speedup] == 0.19.0; sys_platform != "win32"'
+          # don't depend on python-Levenshtein on Windows, as it requires Microsoft C++ Build Tools to install
+        language: python
+        files: \.(py|c|h|cpp|hpp|ld)$
+        require_serial: true
   - repo: https://github.com/pre-commit/pre-commit-hooks
-    rev: v3.4.0
+    rev: v4.0.1
     hooks:
       - id: file-contents-sorter
-        files: '(tools\/ci\/executable-list\.txt|tools\/ci\/mypy_ignore_list\.txt)'
+        files: 'tools\/ci\/(executable-list\.txt|mypy_ignore_list\.txt|check_copyright_ignore\.txt)'

+ 57 - 3
CMakeLists.txt

@@ -20,7 +20,9 @@ if(NOT BOOTLOADER_BUILD)
 
     if(CONFIG_COMPILER_OPTIMIZATION_SIZE)
         list(APPEND compile_options "-Os")
-        list(APPEND compile_options "-freorder-blocks")
+        if(CMAKE_C_COMPILER_ID MATCHES "GNU")
+            list(APPEND compile_options "-freorder-blocks")
+        endif()
     elseif(CONFIG_COMPILER_OPTIMIZATION_DEFAULT)
         list(APPEND compile_options "-Og")
     elseif(CONFIG_COMPILER_OPTIMIZATION_NONE)
@@ -33,7 +35,9 @@ else()  # BOOTLOADER_BUILD
 
     if(CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE)
         list(APPEND compile_options "-Os")
-        list(APPEND compile_options "-freorder-blocks")
+        if(CMAKE_C_COMPILER_ID MATCHES "GNU")
+            list(APPEND compile_options "-freorder-blocks")
+        endif()
     elseif(CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG)
         list(APPEND compile_options "-Og")
     elseif(CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE)
@@ -74,6 +78,48 @@ if(CONFIG_COMPILER_DISABLE_GCC8_WARNINGS)
                                 "-Wno-int-in-bool-context")
 endif()
 
+if(CMAKE_C_COMPILER_ID MATCHES "GNU")
+    list(APPEND c_compile_options "-Wno-old-style-declaration")
+endif()
+
+# Clang finds some warnings in IDF code which GCC doesn't.
+# All these warnings should be fixed before Clang is presented
+# as a toolchain choice for users.
+if(CMAKE_C_COMPILER_ID MATCHES "Clang")
+    # Clang checks Doxygen comments for being in sync with function prototype.
+    # There are some inconsistencies, especially in ROM headers.
+    list(APPEND compile_options "-Wno-documentation")
+    # GCC allows repeated typedefs when the source and target types are the same.
+    # Clang doesn't allow this. This occurs in many components due to forward
+    # declarations.
+    list(APPEND compile_options "-Wno-typedef-redefinition")
+    # This issue is seemingly related to newlib's char type functions.
+    # Fix is not clear yet.
+    list(APPEND compile_options "-Wno-char-subscripts")
+    # Clang seems to notice format string issues which GCC doesn't.
+    list(APPEND compile_options "-Wno-format-security")
+    # Logic bug in essl component
+    list(APPEND compile_options "-Wno-tautological-overlap-compare")
+    # Some pointer checks in mDNS component check addresses which can't be NULL
+    list(APPEND compile_options "-Wno-tautological-pointer-compare")
+    # Similar to the above, in tcp_transport
+    list(APPEND compile_options "-Wno-pointer-bool-conversion")
+    # mbedTLS md5.c triggers this warning in md5_test_buf (false positive)
+    list(APPEND compile_options "-Wno-string-concatenation")
+    # multiple cases of implict convertions between unrelated enum types
+    list(APPEND compile_options "-Wno-enum-conversion")
+    # When IRAM_ATTR is specified both in function declaration and definition,
+    # it produces different section names, since section names include __COUNTER__.
+    # Occurs in multiple places.
+    list(APPEND compile_options "-Wno-section")
+    # Multiple cases of attributes unknown to clang, for example
+    # __attribute__((optimize("-O3")))
+    list(APPEND compile_options "-Wno-unknown-attributes")
+    # Clang also produces many -Wunused-function warnings which GCC doesn't.
+    # However these aren't treated as errors.
+endif()
+# More warnings may exist in unit tests and example projects.
+
 if(CONFIG_COMPILER_WARN_WRITE_STRINGS)
     list(APPEND compile_options "-Wwrite-strings")
 endif()
@@ -118,7 +164,15 @@ list(APPEND link_options "-fno-lto")
 # Placing jump tables in flash would cause issues with code that required
 # to be placed in IRAM
 list(APPEND compile_options "-fno-jump-tables")
-list(APPEND compile_options "-fno-tree-switch-conversion")
+if(CMAKE_C_COMPILER_ID MATCHES "GNU")
+    # This flag is GCC-specific.
+    # Not clear yet if some other flag should be used for Clang.
+    list(APPEND compile_options "-fno-tree-switch-conversion")
+endif()
+
+if(CMAKE_C_COMPILER_ID MATCHES "LLVM")
+    list(APPEND compile_options "-fno-use-cxa-atexit")
+endif()
 
 idf_build_set_property(COMPILE_OPTIONS "${compile_options}" APPEND)
 idf_build_set_property(C_COMPILE_OPTIONS "${c_compile_options}" APPEND)

+ 0 - 1
CONTRIBUTING.rst

@@ -56,7 +56,6 @@ Related Documents
     style-guide
     install-pre-commit-hook
     documenting-code
-    add-ons-reference
     creating-examples
     ../api-reference/template
     contributor-agreement

+ 0 - 1
Kconfig

@@ -11,7 +11,6 @@ mainmenu "Espressif IoT Development Framework Configuration"
     config IDF_ENV_FPGA
         # This option is for internal use only
         bool
-        default "y" if IDF_TARGET="esp32h2" # ESP32H2-TODO: IDF-3378
         option env="IDF_ENV_FPGA"
 
     config IDF_TARGET_ARCH_RISCV

+ 18 - 6
README.md

@@ -2,7 +2,24 @@
 
 * [中文版](./README_CN.md)
 
-ESP-IDF is the development framework for Espressif SoCs (released after 2016<sup>[1](#fn1)</sup>) provided for Windows, Linux and macOS.
+ESP-IDF is the development framework for Espressif SoCs supported on Windows, Linux and macOS.
+
+# ESP-IDF Release and SoC Compatibility
+
+The following table shows ESP-IDF support of Espressif SoCs where ![alt text][preview] and ![alt text][supported] denote preview status and support, respectively. In preview status the build is not yet enabled and some crucial parts could be missing (like documentation, datasheet). Please use an ESP-IDF release where the desired SoC is already supported.
+
+|Chip         |         v3.3           |          v4.0          |           v4.1         |          v4.2          |         v4.3           |          v4.4          |                                                            |
+|:----------- |:---------------------: | :---------------------:| :---------------------:| :---------------------:| :---------------------:| :---------------------:|:---------------------------------------------------------- |
+|ESP32        | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] |                                                            |
+|ESP32-S2     |                        |                        |                        | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] |                                                            |
+|ESP32-C3     |                        |                        |                        |                        | ![alt text][supported] | ![alt text][supported] |                                                            |
+|ESP32-S3     |                        |                        |                        |                        | ![alt text][preview]   | ![alt text][supported] | [Announcement](https://www.espressif.com/en/news/ESP32_S3) |
+|ESP32-H2     |                        |                        |                        |                        |                        | ![alt text][preview]   | [Announcement](https://www.espressif.com/en/news/ESP32_H2) |
+
+[supported]: https://img.shields.io/badge/-supported-green "supported"
+[preview]: https://img.shields.io/badge/-preview-orange "preview"
+
+Espressif SoCs released before 2016 (ESP8266 and ESP8285) are supported by [RTOS SDK](https://github.com/espressif/ESP8266_RTOS_SDK) instead.
 
 # Developing With ESP-IDF
 
@@ -99,8 +116,3 @@ This can be combined with other targets, ie `idf.py -p PORT erase_flash flash` w
 * [Check the Issues section on github](https://github.com/espressif/esp-idf/issues) if you find a bug or have a feature request. Please check existing Issues before opening a new one.
 
 * If you're interested in contributing to ESP-IDF, please check the [Contributions Guide](https://docs.espressif.com/projects/esp-idf/en/latest/contribute/index.html).
-
-
-________
-
-<a name="fn1">1</a>: ESP8266 and ESP8285 are not supported in ESP-IDF. See [RTOS SDK](https://github.com/espressif/ESP8266_RTOS_SDK) instead.

+ 19 - 7
README_CN.md

@@ -2,13 +2,30 @@
 
 * [English Version](./README.md)
 
-ESP-IDF 是由乐鑫官方针对乐鑫各系列芯片产品(发布于 2016 年后<sup>[1](#fn1)</sup>)推出的开发框架,支持 Windows、Linux 和 macOS 操作系统。
+ESP-IDF 是乐鑫官方推出的物联网开发框架,支持 Windows、Linux 和 macOS 操作系统。
+
+# ESP-IDF 与乐鑫芯片
+
+下表总结了乐鑫芯片在 ESP-IDF 各版本中的支持状态,其中 ![alt text][supported] 代表已支持,![alt text][preview] 代表目前处于预览支持状态。在预览支持阶段,因为新芯片尚未完全添加到构建系统目录,所以一些重要的内容(如文档和技术规格书等)可能会缺失。请确保使用与芯片相匹配的 ESP-IDF 版本。
+
+|    芯片     |         v3.3           |          v4.0          |           v4.1         |          v4.2          |         v4.3           |          v4.4          |                                                            |
+|:----------- |:---------------------: | :---------------------:| :---------------------:| :---------------------:| :---------------------:| :---------------------:|:---------------------------------------------------------- |
+|ESP32        | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] |                                                            |
+|ESP32-S2     |                        |                        |                        | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] |                                                            |
+|ESP32-C3     |                        |                        |                        |                        | ![alt text][supported] | ![alt text][supported] |                                                            |
+|ESP32-S3     |                        |                        |                        |                        | ![alt text][preview]   | ![alt text][supported] | [芯片发布公告](https://www.espressif.com/en/news/ESP32_S3) |
+|ESP32-H2     |                        |                        |                        |                        |                        | ![alt text][preview]   | [芯片发布公告](https://www.espressif.com/en/news/ESP32_H2) |
+
+[supported]: https://img.shields.io/badge/-%E6%94%AF%E6%8C%81-green "supported"
+[preview]: https://img.shields.io/badge/-%E9%A2%84%E8%A7%88-orange "preview"
+
+对于 2016 年之前发布的乐鑫芯片(包括 ESP8266 和 ESP8285),请参考 [RTOS SDK](https://github.com/espressif/ESP8266_RTOS_SDK)。
 
 # 使用 ESP-IDF 进行开发
 
 ## 搭建 ESP-IDF 开发环境
 
-关于不同芯片如何搭建 ESP-IDF 的开发环境,请参考 https://idf.espressif.com/。
+关于不同芯片如何搭建 ESP-IDF 的开发环境,请参考 https://idf.espressif.com/ 
 
 **注意:** 不同系列芯片和不同 ESP-IDF 版本都有其对应的文档。请参阅[版本](https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/versions.html)部分,获得关于如何查找文档以及如何检出 ESP-IDF 的特定发行版的详细信息。
 
@@ -99,8 +116,3 @@ ESP-IDF 中的子模块采用相对路径([详见 .gitmodules 文件](.gitmodu
 * 如果你在使用中发现了错误或者需要新的功能,请先[查看 GitHub Issues](https://github.com/espressif/esp-idf/issues),确保该问题没有重复提交。
 
 * 如果你有兴趣为 ESP-IDF 作贡献,请先阅读[贡献指南](https://docs.espressif.com/projects/esp-idf/en/latest/contribute/index.html)。
-
-
-__________
-
-<a name="fn1">1</a>: ESP-IDF 不支持 ESP8266 和 ESP8285。如有需要,请参考 [RTOS SDK](https://github.com/espressif/ESP8266_RTOS_SDK)。

+ 160 - 0
components/README.md

@@ -0,0 +1,160 @@
+# Core Components
+
+## Overview
+
+This document contains details about what the core components are, what they contain, and how they are organized.
+
+## Organization
+
+The core components are organized into two groups.
+
+The first group (referred to as `G0` from now on) contains `hal`, `xtensa` and `riscv` (referred to as `arch` components from now on), `esp_rom`, `esp_common`, and `soc`. This
+group contain information about and low-level access to underlying hardware; or in the case of `esp_common`, hardware-agnostic code and utilities.
+These components can depend on each other, but as much as possible have no dependencies outside the group. The reason for this is that, due to the
+nature of what these components contain, the likelihood is high that a lot of other components will require these. Ideally, then, the dependency
+relationship only goes one way. This makes it easier for these components, as a group, to be usable in another project. One can conceivably implement
+a competing SDK to ESP-IDF on top of these components.
+
+The second group (referred to as `G1` from now on) sits at a higher level than the first group. This group contains the components `esp_hw_support`, `esp_system`, `newlib`, `spi_flash`,
+`freertos`, `log`, and `heap`. Like the first group, circular dependencies within the group are allowed; and being at a higher level, dependency on the first group
+is allowed. These components represent software mechanisms essential to building other components.
+
+## Descriptions
+
+The following is a short description of the components mentioned above.
+
+### `G0` Components
+
+#### `hal`
+
+Contains the hardware abstraction layer and low-level operation implementations for the various peripherals. The low-level functions assign meaningful names to register-level manipulations; the hardware abstraction provide operations one level above this, grouping these low-level functions
+into routines that achieve a meaningful action or state of the peripheral.
+
+Example:
+
+- `spi_flash_ll_set_address` is a low-level function part of the hardware abstraction `spi_flash_hal_read_block`
+
+#### `arch`
+
+Contains low-level architecture operations and definitions, including those for customizations (can be thought of on the same level as the low-level functions of `hal`).
+This can also contain files provided by the architecture vendor.
+
+Example:
+
+- `xt_set_exception_handler`
+- `riscv_global_interrupts_enable`
+- `ERI_PERFMON_MAX`
+
+#### `esp_common`
+
+Contains hardware-agnostic definitions, constants, macros, utilities, 'pure' and/or algorithmic functions that is useable by all other components (that is, barring there being a more appropriate component to put them in).
+
+Example:
+
+- `BIT(nr)` and other bit manipulation utilities in the future
+- `IDF_DEPRECATED(REASON)`
+- `ESP_IDF_VERSION_MAJOR`
+
+#### `soc`
+
+Contains description of the underlying hardware: register structure, addresses, pins, capabilities, etc.
+
+Example:
+
+- `DR_REG_DPORT_BASE`
+- `SOC_MCPWM_SUPPORTED`
+- `uart_dev_s`
+
+#### `esp_rom`
+
+Contains headers, linker scripts, abstraction layer, patches, and other related files to ROM functions.
+
+Example:
+
+- `esp32.rom.eco3.ld`
+- `rom/aes.h`
+
+### `G1` Components
+
+#### `spi_flash`
+
+SPI flash device access implementation.
+
+#### `freertos`
+
+FreeRTOS port to targets supported by ESP-IDF.
+
+#### `log`
+
+Logging library.
+
+#### `heap`
+
+Heap implementation.
+
+#### `newlib`
+
+Some functions n the standard library are implemented here, especially those needing other `G1` components.
+
+Example:
+
+- `malloc` is implemented in terms of the component `heap`'s functions
+- `gettimeofday` is implemented in terms of system time in `esp_system`
+
+#### `esp_system`
+
+Contains implementation of system services and controls system behavior. The implementations
+here may take hardware resources and/or decide on a hardware state needed for support of a system service/feature/mechanism.
+Currently, this encompasses the following, but not limited to:
+
+- Startup and initialization
+- Panic and debug
+- Reset and reset reason
+- Task and interrupt watchdogs
+
+#### `esp_hw_support`
+
+Contains implementations that provide hardware operations, arbitration, or resource sharing, especially those that
+is used in the system. Unlike `esp_system`, implementations here do not decide on a hardware state or takes hardware resource, acting
+merely as facilitator to hardware access. Currently, this encompasses the following, but not limited to:
+
+- Interrupt allocation
+- Sleep functions
+- Memory functions (external SPIRAM, async memory, etc.)
+- Clock and clock control
+- Random generation
+- CPU utilities
+- MAC settings
+
+### `esp_hw_support` vs `esp_system`
+
+This section details list some implementations and the reason for placing it in either `esp_hw_support` or `esp_system`.
+
+#### `task_wdt.c` (`esp_system`) vs  `intr_alloc.c` (`esp_hw_support`)
+
+The task watchdog fits the definition of taking and configuring hardware resources (wdt, interrupt) for implementation of a system service/mechanism.
+
+This is in contrast with interrupt allocation that merely facilitates access to the underlying hardware for other implementations -
+drivers, user code, and even the task watchdog mentioned previously!
+
+#### `crosscore_int.c` (`esp_system`)
+
+The current implementation of crosscore interrupts is tightly coupled with a number of interrupt reasons
+associated with system services/mechanisms: REASON_YIELD (scheduler), REASON_FREQ_SWITCH (power management)
+REASON_PRINT_BACKTRACE (panic and debug).
+
+However, if an implementation exists that makes it possible to register an arbitrary interrupt reason - a
+lower level inter-processor call if you will, then this implementation is a good candidate for `esp_hw_support`.
+The current implementation in `esp_system` can then just register the interrupt reasons mentioned above.
+
+#### `esp_mac.h`, `esp_chip_info.h`, `esp_random.h` (`esp_hw_support`)
+
+The functions in these headers used to be in `esp_system.h`, but have been split-off.
+However, to maintain backward compatibility, `esp_system.h` includes these headers.
+
+The remaining functions in `esp_system.h` are those that deal with system behavior, such
+as `esp_register_shutdown_handler`, or are proxy for other system components's APIs such as
+`esp_get_free_heap_size`.
+
+The functions split-off from `esp_system.h` are much more hardware manipulation oriented such as:
+`esp_read_mac`, `esp_random` and `esp_chip_info`.

+ 1 - 1
components/app_trace/CMakeLists.txt

@@ -47,7 +47,7 @@ endif()
 idf_component_register(SRCS "${srcs}"
                        INCLUDE_DIRS "${include_dirs}"
                        PRIV_INCLUDE_DIRS "${priv_include_dirs}"
-                       PRIV_REQUIRES soc
+                       PRIV_REQUIRES soc esp_ipc
                        LDFRAGMENTS linker.lf)
 
 # disable --coverage for this component, as it is used as transport

+ 67 - 80
components/app_trace/gcov/gcov_rtio.c

@@ -14,7 +14,9 @@
 #include "soc/cpu.h"
 #include "soc/timer_periph.h"
 #include "esp_app_trace.h"
+#include "esp_freertos_hooks.h"
 #include "esp_private/dbg_stubs.h"
+#include "esp_ipc.h"
 #include "hal/wdt_hal.h"
 #if CONFIG_IDF_TARGET_ESP32
 #include "esp32/rom/libc_stubs.h"
@@ -28,128 +30,113 @@
 
 #include "esp_log.h"
 const static char *TAG = "esp_gcov_rtio";
+static volatile bool s_create_gcov_task = false;
+static volatile bool s_gcov_task_running = false;
 
 extern void __gcov_dump(void);
 extern void __gcov_reset(void);
 
-static struct syscall_stub_table s_gcov_stub_table;
-
-
-static int gcov_stub_lock_try_acquire_recursive(_lock_t *lock)
+void gcov_dump_task(void *pvParameter)
 {
-    if (*lock && uxSemaphoreGetCount((xSemaphoreHandle)(*lock)) == 0) {
-        // we can do nothing here, gcov dump is initiated with some resource locked
-        // which is also used by gcov functions
-        ESP_EARLY_LOGE(TAG, "Lock 0x%x is busy during GCOV dump! System state can be inconsistent after dump!", lock);
-    }
-    return pdTRUE;
-}
+    int dump_result = 0;
+    bool *running = (bool *)pvParameter;
 
-static void gcov_stub_lock_acquire_recursive(_lock_t *lock)
-{
-    gcov_stub_lock_try_acquire_recursive(lock);
-}
-
-static void gcov_stub_lock_release_recursive(_lock_t *lock)
-{
-}
+    ESP_EARLY_LOGV(TAG, "%s stack use in %d", __FUNCTION__, uxTaskGetStackHighWaterMark(NULL));
 
-static int esp_dbg_stub_gcov_dump_do(void)
-{
-    int ret = ESP_OK;
-    FILE* old_stderr = stderr;
-    FILE* old_stdout = stdout;
-    static struct syscall_stub_table *old_tables[portNUM_PROCESSORS];
-
-    old_tables[0] = syscall_table_ptr_pro;
-#if portNUM_PROCESSORS > 1
-    old_tables[1] = syscall_table_ptr_app;
-#endif
     ESP_EARLY_LOGV(TAG, "Alloc apptrace down buf %d bytes", ESP_GCOV_DOWN_BUF_SIZE);
     void *down_buf = malloc(ESP_GCOV_DOWN_BUF_SIZE);
     if (down_buf == NULL) {
         ESP_EARLY_LOGE(TAG, "Could not allocate memory for the buffer");
-        return ESP_ERR_NO_MEM;
+        dump_result = ESP_ERR_NO_MEM;
+        goto gcov_exit;
     }
     ESP_EARLY_LOGV(TAG, "Config apptrace down buf");
     esp_apptrace_down_buffer_config(down_buf, ESP_GCOV_DOWN_BUF_SIZE);
+    /* we are directing the std outputs to the fake ones in order to reduce stack usage */
+    FILE *old_stderr = stderr;
+    FILE *old_stdout = stdout;
+    stderr = (FILE *) &__sf_fake_stderr;
+    stdout = (FILE *) &__sf_fake_stdout;
     ESP_EARLY_LOGV(TAG, "Dump data...");
-    // incase of dual-core chip APP and PRO CPUs share the same table, so it is safe to save only PRO's table
-    memcpy(&s_gcov_stub_table, syscall_table_ptr_pro, sizeof(s_gcov_stub_table));
-    s_gcov_stub_table._lock_acquire_recursive = &gcov_stub_lock_acquire_recursive;
-    s_gcov_stub_table._lock_release_recursive = &gcov_stub_lock_release_recursive;
-    s_gcov_stub_table._lock_try_acquire_recursive = &gcov_stub_lock_try_acquire_recursive,
-    syscall_table_ptr_pro = &s_gcov_stub_table;
-#if portNUM_PROCESSORS > 1
-    syscall_table_ptr_app = &s_gcov_stub_table;
-#endif
-    stderr = (FILE*) &__sf_fake_stderr;
-    stdout = (FILE*) &__sf_fake_stdout;
     __gcov_dump();
     // reset dump status to allow incremental data accumulation
     __gcov_reset();
-    stdout = old_stdout;
-    stderr = old_stderr;
-    syscall_table_ptr_pro = old_tables[0];
-#if portNUM_PROCESSORS > 1
-    syscall_table_ptr_app = old_tables[1];
-#endif
-    ESP_EARLY_LOGV(TAG, "Free apptrace down buf");
     free(down_buf);
+    stderr = old_stderr;
+    stdout = old_stdout;
     ESP_EARLY_LOGV(TAG, "Finish file transfer session");
-    ret = esp_apptrace_fstop(ESP_APPTRACE_DEST_TRAX);
-    if (ret != ESP_OK) {
-        ESP_EARLY_LOGE(TAG, "Failed to send files transfer stop cmd (%d)!", ret);
+    dump_result = esp_apptrace_fstop(ESP_APPTRACE_DEST_TRAX);
+    if (dump_result != ESP_OK) {
+        ESP_EARLY_LOGE(TAG, "Failed to send files transfer stop cmd (%d)!", dump_result);
+    }
+
+gcov_exit:
+    ESP_EARLY_LOGV(TAG, "dump_result %d", dump_result);
+    if (running) {
+        *running = false;
+    }
+
+    ESP_EARLY_LOGV(TAG, "%s stack use out %d", __FUNCTION__, uxTaskGetStackHighWaterMark(NULL));
+
+    vTaskDelete(NULL);
+}
+
+void gcov_create_task(void *arg)
+{
+    ESP_EARLY_LOGV(TAG, "%s", __FUNCTION__);
+    xTaskCreatePinnedToCore(&gcov_dump_task, "gcov_dump_task", 2048, (void *)&s_gcov_task_running, configMAX_PRIORITIES - 1, NULL, 0);
+}
+
+void gcov_create_task_tick_hook(void)
+{
+    extern esp_err_t esp_ipc_start_gcov_from_isr(uint32_t cpu_id, esp_ipc_func_t func, void* arg);
+    if (s_create_gcov_task) {
+        if (esp_ipc_start_gcov_from_isr(xPortGetCoreID(), &gcov_create_task, NULL) == ESP_OK) {
+            s_create_gcov_task = false;
+        }
     }
-    ESP_EARLY_LOGV(TAG, "exit %d", ret);
-    return ret;
 }
 
 /**
- * @brief Triggers gcov info dump.
+ * @brief Triggers gcov info dump task
  *        This function is to be called by OpenOCD, not by normal user code.
- * TODO: what about interrupted flash access (when cache disabled)???
+ * TODO: what about interrupted flash access (when cache disabled)
  *
  * @return ESP_OK on success, otherwise see esp_err_t
  */
 static int esp_dbg_stub_gcov_entry(void)
 {
-    return esp_dbg_stub_gcov_dump_do();
+    /* we are in isr context here */
+    s_create_gcov_task = true;
+    return ESP_OK;
 }
 
 int gcov_rtio_atexit(void (*function)(void) __attribute__ ((unused)))
 {
+    uint32_t capabilities = 0;
     ESP_EARLY_LOGV(TAG, "%s", __FUNCTION__);
     esp_dbg_stub_entry_set(ESP_DBG_STUB_ENTRY_GCOV, (uint32_t)&esp_dbg_stub_gcov_entry);
-    return 0;
+    if (esp_dbg_stub_entry_get(ESP_DBG_STUB_ENTRY_CAPABILITIES, &capabilities) == ESP_OK) {
+        esp_dbg_stub_entry_set(ESP_DBG_STUB_ENTRY_CAPABILITIES, capabilities | ESP_DBG_STUB_CAP_GCOV_TASK);
+    }
+    esp_register_freertos_tick_hook(gcov_create_task_tick_hook);
+    return ESP_OK;
 }
 
 void esp_gcov_dump(void)
 {
-    // disable IRQs on this CPU, other CPU is halted by OpenOCD
-    unsigned irq_state = portENTER_CRITICAL_NESTED();
-#if !CONFIG_FREERTOS_UNICORE
-    int other_core = cpu_hal_get_core_id() ? 0 : 1;
-    esp_cpu_stall(other_core);
-#endif
+    ESP_EARLY_LOGV(TAG, "%s", __FUNCTION__);
+
     while (!esp_apptrace_host_is_connected(ESP_APPTRACE_DEST_TRAX)) {
-        wdt_hal_context_t twdt = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0};
-        wdt_hal_context_t iwdt = {.inst = WDT_MWDT1, .mwdt_dev = &TIMERG1};
-        //Feed the Task Watchdog (TG0) to prevent it from timing out
-        wdt_hal_write_protect_disable(&twdt);
-        wdt_hal_feed(&twdt);
-        wdt_hal_write_protect_enable(&twdt);
-        //Likewise, feed the Interrupt Watchdog (TG1) to prevent a reboot
-        wdt_hal_write_protect_disable(&iwdt);
-        wdt_hal_feed(&iwdt);
-        wdt_hal_write_protect_enable(&iwdt);
+        vTaskDelay(pdMS_TO_TICKS(10));
     }
 
-    esp_dbg_stub_gcov_dump_do();
-#if !CONFIG_FREERTOS_UNICORE
-    esp_cpu_unstall(other_core);
-#endif
-    portEXIT_CRITICAL_NESTED(irq_state);
+    /* We are not in isr context here. Waiting for the completion is safe */
+    s_gcov_task_running = true;
+    s_create_gcov_task = true;
+    while (s_gcov_task_running) {
+        vTaskDelay(pdMS_TO_TICKS(10));
+    }
 }
 
 void *gcov_rtio_fopen(const char *path, const char *mode)
@@ -168,7 +155,7 @@ int gcov_rtio_fclose(void *stream)
 
 size_t gcov_rtio_fread(void *ptr, size_t size, size_t nmemb, void *stream)
 {
-    ESP_EARLY_LOGV(TAG, "%s read %u", __FUNCTION__, size*nmemb);
+    ESP_EARLY_LOGV(TAG, "%s read %u", __FUNCTION__, size * nmemb);
     size_t sz = esp_apptrace_fread(ESP_APPTRACE_DEST_TRAX, ptr, size, nmemb, stream);
     ESP_EARLY_LOGV(TAG, "%s actually read %u", __FUNCTION__, sz);
     return sz;

+ 5 - 4
components/app_trace/sys_view/Sample/Config/SEGGER_SYSVIEW_Config_FreeRTOS.c

@@ -151,16 +151,17 @@ extern const SEGGER_SYSVIEW_OS_API SYSVIEW_X_OS_TraceAPI;
 // The lowest RAM address used for IDs (pointers)
 #define SYSVIEW_RAM_BASE        (SOC_DROM_LOW)
 
-#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
+#ifdef CONFIG_FREERTOS_TICK_SUPPORT_CORETIMER
 #if CONFIG_FREERTOS_CORETIMER_0
     #define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER0_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF)
 #endif
 #if CONFIG_FREERTOS_CORETIMER_1
     #define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER1_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF)
 #endif
-#elif CONFIG_IDF_TARGET_ESP32C3
-    #define SYSTICK_INTR_ID (ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF)
-#endif
+
+#elif CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER
+    #define SYSTICK_INTR_ID (ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE)
+#endif // CONFIG_FREERTOS_TICK_SUPPORT_CORETIMER
 
 // SystemView is single core specific: it implies that SEGGER_SYSVIEW_LOCK()
 // disables IRQs (disables rescheduling globally). So we can not use finite timeouts for locks and return error

+ 5 - 5
components/app_trace/sys_view/Sample/OS/SEGGER_SYSVIEW_FreeRTOS.h

@@ -209,7 +209,7 @@ Notes:
 #define apiID_VEVENTGROUPDELETE                   (72u)
 #define apiID_UXEVENTGROUPGETNUMBER               (73u)
 
-#define traceTASK_NOTIFY_TAKE()                                       SEGGER_SYSVIEW_RecordU32x2(apiFastID_OFFSET + apiID_ULTASKNOTIFYTAKE, xClearCountOnExit, xTicksToWait)
+#define traceTASK_NOTIFY_TAKE( uxIndexToWait )                        SEGGER_SYSVIEW_RecordU32x2(apiFastID_OFFSET + apiID_ULTASKNOTIFYTAKE, xClearCountOnExit, xTicksToWait)
 #define traceTASK_DELAY()                                             SEGGER_SYSVIEW_RecordU32(apiFastID_OFFSET + apiID_VTASKDELAY, xTicksToDelay)
 #define traceTASK_DELAY_UNTIL()                                       SEGGER_SYSVIEW_RecordVoid(apiFastID_OFFSET + apiID_VTASKDELAYUNTIL)
 #define traceTASK_DELETE( pxTCB )                                     if (pxTCB != NULL) {                                              \
@@ -217,16 +217,16 @@ Notes:
 						                                                                      SEGGER_SYSVIEW_ShrinkId((U32)pxTCB)); 	\
 					                                                    SYSVIEW_DeleteTask((U32)pxTCB);                                 \
 					                                                  }
-#define traceTASK_NOTIFY_GIVE_FROM_ISR()                              SEGGER_SYSVIEW_RecordU32x2(apiFastID_OFFSET + apiID_VTASKNOTIFYGIVEFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB), (U32)pxHigherPriorityTaskWoken)
+#define traceTASK_NOTIFY_GIVE_FROM_ISR( uxIndexToNotify )             SEGGER_SYSVIEW_RecordU32x2(apiFastID_OFFSET + apiID_VTASKNOTIFYGIVEFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB), (U32)pxHigherPriorityTaskWoken)
 #define traceTASK_PRIORITY_INHERIT( pxTCB, uxPriority )               SEGGER_SYSVIEW_RecordU32(apiFastID_OFFSET + apiID_VTASKPRIORITYINHERIT, (U32)pxMutexHolder)
 #define traceTASK_RESUME( pxTCB )                                     SEGGER_SYSVIEW_RecordU32(apiFastID_OFFSET + apiID_VTASKRESUME, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB))
 #define traceINCREASE_TICK_COUNT( xTicksToJump )                      SEGGER_SYSVIEW_RecordU32(apiFastID_OFFSET + apiID_VTASKSTEPTICK, xTicksToJump)
 #define traceTASK_SUSPEND( pxTCB )                                    SEGGER_SYSVIEW_RecordU32(apiFastID_OFFSET + apiID_VTASKSUSPEND, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB))
 #define traceTASK_PRIORITY_DISINHERIT( pxTCB, uxBasePriority )        SEGGER_SYSVIEW_RecordU32(apiFastID_OFFSET + apiID_XTASKPRIORITYDISINHERIT, (U32)pxMutexHolder)
 #define traceTASK_RESUME_FROM_ISR( pxTCB )                            SEGGER_SYSVIEW_RecordU32(apiFastID_OFFSET + apiID_XTASKRESUMEFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB))
-#define traceTASK_NOTIFY()                                            SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XTASKGENERICNOTIFY, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB), ulValue, eAction, (U32)pulPreviousNotificationValue)
-#define traceTASK_NOTIFY_FROM_ISR()                                   SYSVIEW_RecordU32x5(apiFastID_OFFSET + apiID_XTASKGENERICNOTIFYFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB), ulValue, eAction, (U32)pulPreviousNotificationValue, (U32)pxHigherPriorityTaskWoken)
-#define traceTASK_NOTIFY_WAIT()                                       SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XTASKNOTIFYWAIT, ulBitsToClearOnEntry, ulBitsToClearOnExit, (U32)pulNotificationValue, xTicksToWait)
+#define traceTASK_NOTIFY( uxIndexToNotify )                           SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XTASKGENERICNOTIFY, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB), ulValue, eAction, (U32)pulPreviousNotificationValue)
+#define traceTASK_NOTIFY_FROM_ISR( uxIndexToNotify )                  SYSVIEW_RecordU32x5(apiFastID_OFFSET + apiID_XTASKGENERICNOTIFYFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB), ulValue, eAction, (U32)pulPreviousNotificationValue, (U32)pxHigherPriorityTaskWoken)
+#define traceTASK_NOTIFY_WAIT( uxIndexToWait )                        SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XTASKNOTIFYWAIT, ulBitsToClearOnEntry, ulBitsToClearOnExit, (U32)pulNotificationValue, xTicksToWait)
 
 #define traceQUEUE_CREATE( pxNewQueue )                               SEGGER_SYSVIEW_RecordU32x3(apiFastID_OFFSET + apiID_XQUEUEGENERICCREATE, uxQueueLength, uxItemSize, ucQueueType)
 #define traceQUEUE_DELETE( pxQueue )                                  SEGGER_SYSVIEW_RecordU32(apiFastID_OFFSET + apiID_VQUEUEDELETE, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue))

+ 1 - 0
components/app_update/CMakeLists.txt

@@ -46,6 +46,7 @@ if(NOT BOOTLOADER_BUILD)
 
         add_custom_target(blank_ota_data ALL DEPENDS ${blank_otadata_file})
         add_dependencies(flash blank_ota_data)
+        add_dependencies(encrypted-flash blank_ota_data)
 
         set(otatool_py ${python} ${COMPONENT_DIR}/otatool.py)
 

+ 26 - 6
components/bootloader/Kconfig.projbuild

@@ -386,6 +386,15 @@ menu "Bootloader config"
             in this area of memory, you can increase it. It must be a multiple of 4 bytes.
             This area (rtc_retain_mem_t) is reserved and has access from the bootloader and an application.
 
+    config BOOTLOADER_FLASH_XMC_SUPPORT
+        bool "Enable the support for flash chips of XMC (READ HELP FIRST)"
+        default y
+        help
+            Perform the startup flow recommended by XMC. Please consult XMC for the details of this flow.
+            XMC chips will be forbidden to be used, when this option is disabled.
+
+            DON'T DISABLE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.
+
 endmenu  # Bootloader
 
 
@@ -415,12 +424,12 @@ menu "Security features"
     config SECURE_BOOT_SUPPORTS_RSA
         bool
         default y
-        depends on ESP32_REV_MIN_3 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3
+        depends on ESP32_REV_MIN_3 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3
 
     config SECURE_TARGET_HAS_SECURE_ROM_DL_MODE
         bool
         default y
-        depends on IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3
+        depends on IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3
 
 
     config SECURE_SIGNED_APPS_NO_SECURE_BOOT
@@ -492,7 +501,8 @@ menu "Security features"
     config SECURE_BOOT
         bool "Enable hardware Secure Boot in bootloader (READ DOCS FIRST)"
         default n
-        depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || ESP32C3_REV_MIN_3
+        depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || ESP32C3_REV_MIN_3 || IDF_TARGET_ESP32S3
+        select ESPTOOLPY_NO_STUB if !IDF_TARGET_ESP32 && !IDF_TARGET_ESP32S2
         help
             Build a bootloader which enables Secure Boot on first boot.
 
@@ -755,9 +765,17 @@ menu "Security features"
                 efuse when Secure Boot is enabled. This prevents any more efuses from being read protected.
 
                 If this option is set, it will remain possible to write the EFUSE_RD_DIS efuse field after Secure
-                Boot is enabled. This may allow an attacker to read-protect the BLK2 efuse holding the public
-                key digest, causing an immediate denial of service and possibly allowing an additional fault
-                injection attack to bypass the signature protection.
+                Boot is enabled. This may allow an attacker to read-protect the BLK2 efuse (for ESP32) and
+                BLOCK4-BLOCK10 (i.e. BLOCK_KEY0-BLOCK_KEY5)(for other chips) holding the public key digest, causing an
+                immediate denial of service and possibly allowing an additional fault injection attack to
+                bypass the signature protection.
+
+                NOTE: Once a BLOCK is read-protected, the application will read all zeros from that block
+
+                NOTE: If "UART ROM download mode (Permanently disabled (recommended))" or
+                "UART ROM download mode (Permanently switch to Secure mode (recommended))" is set,
+                then it is __NOT__ possible to read/write efuses using espefuse.py utility.
+                However, efuse can be read/written from the application
 
         config SECURE_BOOT_ALLOW_UNUSED_DIGEST_SLOTS
             bool "Leave unused digest slots available (not revoke)"
@@ -875,6 +893,8 @@ menu "Security features"
                 It is also possible to enable secure download mode at runtime by calling
                 esp_efuse_enable_rom_secure_download_mode()
 
+                Note: Secure Download mode is not available for ESP32 (includes revisions till ECO3).
+
         config SECURE_INSECURE_ALLOW_DL_MODE
             bool "UART ROM download mode (Enabled (not recommended))"
             help

+ 1 - 0
components/bootloader/subproject/main/ld/esp32/bootloader.ld

@@ -49,6 +49,7 @@ SECTIONS
     *libbootloader_support.a:bootloader_sha.*(.literal .text .literal.* .text.*)
     *libbootloader_support.a:bootloader_console_loader.*(.literal .text .literal.* .text.*)
     *libbootloader_support.a:bootloader_panic.*(.literal .text .literal.* .text.*)
+    *libbootloader_support.a:bootloader_soc.*(.literal .text .literal.* .text.*)
     *libbootloader_support.a:esp_image_format.*(.literal .text .literal.* .text.*)
     *libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*)
     *libbootloader_support.a:flash_encryption_secure_features.*(.literal .text .literal.* .text.*)

+ 1 - 0
components/bootloader/subproject/main/ld/esp32c3/bootloader.ld

@@ -36,6 +36,7 @@ SECTIONS
     *libbootloader_support.a:bootloader_sha.*(.literal .text .literal.* .text.*)
     *libbootloader_support.a:bootloader_console_loader.*(.literal .text .literal.* .text.*)
     *libbootloader_support.a:bootloader_panic.*(.literal .text .literal.* .text.*)
+    *libbootloader_support.a:bootloader_soc.*(.literal .text .literal.* .text.*)
     *libbootloader_support.a:esp_image_format.*(.literal .text .literal.* .text.*)
     *libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*)
     *libbootloader_support.a:flash_encryption_secure_features.*(.literal .text .literal.* .text.*)

+ 1 - 0
components/bootloader/subproject/main/ld/esp32h2/bootloader.ld

@@ -36,6 +36,7 @@ SECTIONS
     *libbootloader_support.a:bootloader_sha.*(.literal .text .literal.* .text.*)
     *libbootloader_support.a:bootloader_console_loader.*(.literal .text .literal.* .text.*)
     *libbootloader_support.a:bootloader_panic.*(.literal .text .literal.* .text.*)
+    *libbootloader_support.a:bootloader_soc.*(.literal .text .literal.* .text.*)
     *libbootloader_support.a:esp_image_format.*(.literal .text .literal.* .text.*)
     *libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*)
     *libbootloader_support.a:flash_partitions.*(.literal .text .literal.* .text.*)

+ 1 - 0
components/bootloader/subproject/main/ld/esp32s2/bootloader.ld

@@ -36,6 +36,7 @@ SECTIONS
     *libbootloader_support.a:bootloader_sha.*(.literal .text .literal.* .text.*)
     *libbootloader_support.a:bootloader_console_loader.*(.literal .text .literal.* .text.*)
     *libbootloader_support.a:bootloader_panic.*(.literal .text .literal.* .text.*)
+    *libbootloader_support.a:bootloader_soc.*(.literal .text .literal.* .text.*)
     *libbootloader_support.a:esp_image_format.*(.literal .text .literal.* .text.*)
     *libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*)
     *libbootloader_support.a:flash_encryption_secure_features.*(.literal .text .literal.* .text.*)

+ 1 - 0
components/bootloader/subproject/main/ld/esp32s3/bootloader.ld

@@ -37,6 +37,7 @@ SECTIONS
     *libbootloader_support.a:bootloader_sha.*(.literal .text .literal.* .text.*)
     *libbootloader_support.a:bootloader_console_loader.*(.literal .text .literal.* .text.*)
     *libbootloader_support.a:bootloader_panic.*(.literal .text .literal.* .text.*)
+    *libbootloader_support.a:bootloader_soc.*(.literal .text .literal.* .text.*)
     *libbootloader_support.a:esp_image_format.*(.literal .text .literal.* .text.*)
     *libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*)
     *libbootloader_support.a:flash_encryption_secure_features.*(.literal .text .literal.* .text.*)

+ 1 - 0
components/bootloader_support/CMakeLists.txt

@@ -26,6 +26,7 @@ if(BOOTLOADER_BUILD)
     "src/bootloader_console_loader.c"
     "src/bootloader_panic.c"
     "src/${IDF_TARGET}/bootloader_sha.c"
+    "src/${IDF_TARGET}/bootloader_soc.c"
     "src/${IDF_TARGET}/bootloader_${IDF_TARGET}.c"
     )
     list(APPEND priv_requires hal)

+ 9 - 0
components/bootloader_support/include/bootloader_common.h

@@ -119,6 +119,15 @@ bool bootloader_common_label_search(const char *list, char *label);
  */
 void bootloader_configure_spi_pins(int drv);
 
+/**
+ * @brief Get flash CS IO
+ *
+ * Can be determined by eFuse values, or the default value
+ *
+ * @return Flash CS IO
+ */
+uint8_t bootloader_flash_get_cs_io(void);
+
 /**
  * @brief Calculates a sha-256 for a given partition or returns a appended digest.
  *

+ 15 - 0
components/bootloader_support/include/bootloader_flash.h

@@ -14,6 +14,14 @@
 extern "C" {
 #endif
 
+/**
+ * @brief Read flash ID by sending RDID command (0x9F)
+ * @return flash raw ID
+ *     mfg_id = (ID >> 16) & 0xFF;
+       flash_id = ID & 0xffff;
+ */
+uint32_t bootloader_read_flash_id(void);
+
 #if SOC_CACHE_SUPPORT_WRAP
 /**
  * @brief Set the burst mode setting command for specified wrap mode.
@@ -32,6 +40,13 @@ esp_err_t bootloader_flash_wrap_set(spi_flash_wrap_mode_t mode);
   */
 esp_err_t bootloader_flash_unlock(void);
 
+/**
+ * @brief Startup flow recommended by XMC. Call at startup before any erase/write operation.
+ *
+ * @return ESP_OK When startup successfully, otherwise ESP_FAIL (indiciating you should reboot before erase/write).
+ */
+esp_err_t bootloader_flash_xmc_startup(void);
+
 #ifdef __cplusplus
 }
 #endif

+ 10 - 0
components/bootloader_support/include_bootloader/bootloader_flash_priv.h

@@ -29,6 +29,7 @@
 #define CMD_RDSR       0x05
 #define CMD_RDSR2      0x35 /* Not all SPI flash uses this command */
 #define CMD_OTPEN      0x3A /* Enable OTP mode, not all SPI flash uses this command */
+#define CMD_RDSFDP     0x5A /* Read the SFDP of the flash */
 #define CMD_WRAP       0x77 /* Set burst with wrap command */
 #define CMD_RESUME     0x7A /* Resume command to clear flash suspend bit */
 
@@ -156,6 +157,15 @@ static inline uint32_t bootloader_cache_pages_to_map(uint32_t size, uint32_t vad
  */
 uint32_t bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len);
 
+/**
+ * @brief Read the SFDP of the flash
+ *
+ * @param sfdp_addr Address of the parameter to read
+ * @param miso_byte_num Bytes to read
+ * @return The read SFDP, little endian, 4 bytes at most
+ */
+uint32_t bootloader_flash_read_sfdp(uint32_t sfdp_addr, unsigned int miso_byte_num);
+
 /**
  * @brief Enable the flash write protect (WEL bit).
  */

+ 27 - 0
components/bootloader_support/include_bootloader/bootloader_soc.h

@@ -0,0 +1,27 @@
+/*
+ * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#pragma once
+
+/**
+ * @brief Configure analog super WDT reset
+ *
+ * @param enable Boolean to enable or disable super WDT reset
+ */
+void bootloader_ana_super_wdt_reset_config(bool enable);
+
+/**
+ * @brief Configure analog brownout reset
+ *
+ * @param enable Boolean to enable or disable brownout reset
+ */
+void bootloader_ana_bod_reset_config(bool enable);
+
+/**
+ * @brief Configure analog clock glitch reset
+ *
+ * @param enable Boolean to enable or disable clock glitch reset
+ */
+void bootloader_ana_clock_glitch_reset_config(bool enable);

+ 13 - 1
components/bootloader_support/src/bootloader_common.c

@@ -23,6 +23,7 @@
 #include "esp_rom_crc.h"
 #include "esp_rom_gpio.h"
 #include "esp_rom_sys.h"
+#include "esp_rom_efuse.h"
 #include "esp_flash_partitions.h"
 #include "bootloader_flash_priv.h"
 #include "bootloader_common.h"
@@ -191,8 +192,19 @@ void bootloader_common_vddsdio_configure(void)
 #endif // CONFIG_BOOTLOADER_VDDSDIO_BOOST
 }
 
-
 RESET_REASON bootloader_common_get_reset_reason(int cpu_no)
 {
     return (RESET_REASON)esp_rom_get_reset_reason(cpu_no);
 }
+
+uint8_t bootloader_flash_get_cs_io(void)
+{
+    uint8_t cs_io;
+    const uint32_t spiconfig = esp_rom_efuse_get_flash_gpio_info();
+    if (spiconfig == ESP_ROM_EFUSE_FLASH_DEFAULT_SPI) {
+        cs_io = SPI_CS0_GPIO_NUM;
+    } else {
+        cs_io = (spiconfig >> 18) & 0x3f;
+    }
+    return cs_io;
+}

+ 2 - 2
components/bootloader_support/src/bootloader_console.c

@@ -71,8 +71,8 @@ void bootloader_console_init(void)
         gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_U0RXD_U, PIN_FUNC_GPIO);
         gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_U0TXD_U, PIN_FUNC_GPIO);
         // Route GPIO signals to/from pins
-        const uint32_t tx_idx = uart_periph_signal[uart_num].tx_sig;
-        const uint32_t rx_idx = uart_periph_signal[uart_num].rx_sig;
+        const uint32_t tx_idx = UART_PERIPH_SIGNAL(uart_num, SOC_UART_TX_PIN_IDX);
+        const uint32_t rx_idx = UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX);
         PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[uart_rx_gpio]);
         esp_rom_gpio_pad_pullup_only(uart_rx_gpio);
         esp_rom_gpio_connect_out_signal(uart_tx_gpio, tx_idx, 0, 0);

+ 3 - 3
components/bootloader_support/src/bootloader_efuse_esp32.c

@@ -7,14 +7,14 @@
 #include "bootloader_common.h"
 #include "bootloader_clock.h"
 #include "soc/efuse_reg.h"
-#include "soc/apb_ctrl_reg.h"
+#include "soc/syscon_reg.h"
 
 uint8_t bootloader_common_get_chip_revision(void)
 {
     uint8_t eco_bit0, eco_bit1, eco_bit2;
     eco_bit0 = (REG_READ(EFUSE_BLK0_RDATA3_REG) & 0xF000) >> 15;
     eco_bit1 = (REG_READ(EFUSE_BLK0_RDATA5_REG) & 0x100000) >> 20;
-    eco_bit2 = (REG_READ(APB_CTRL_DATE_REG) & 0x80000000) >> 31;
+    eco_bit2 = (REG_READ(SYSCON_DATE_REG) & 0x80000000) >> 31;
     uint32_t combine_value = (eco_bit2 << 2) | (eco_bit1 << 1) | eco_bit0;
     uint8_t chip_ver = 0;
     switch (combine_value) {
@@ -28,7 +28,7 @@ uint8_t bootloader_common_get_chip_revision(void)
         chip_ver = 2;
         break;
 #if CONFIG_IDF_ENV_FPGA
-    case 4: /* Empty efuses, but APB_CTRL_DATE_REG bit is set */
+    case 4: /* Empty efuses, but SYSCON_DATE_REG bit is set */
         chip_ver = 3;
         break;
 #endif

+ 1 - 1
components/bootloader_support/src/bootloader_efuse_esp32s2.c

@@ -19,5 +19,5 @@ uint8_t bootloader_common_get_chip_revision(void)
 uint32_t bootloader_common_get_chip_ver_pkg(void)
 {
     // should return the same value as esp_efuse_get_pkg_ver()
-    return REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_3_REG, EFUSE_PKG_VERSION);
+    return REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_4_REG, EFUSE_PKG_VERSION);
 }

+ 179 - 22
components/bootloader_support/src/bootloader_flash.c

@@ -122,7 +122,7 @@ esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size)
     return spi_flash_erase_range(start_addr, size);
 }
 
-#else
+#else //BOOTLOADER_BUILD
 /* Bootloader version, uses ROM functions only */
 #if CONFIG_IDF_TARGET_ESP32
 #include "esp32/rom/spi_flash.h"
@@ -481,7 +481,8 @@ esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size)
     return spi_to_esp_err(rc);
 }
 
-#endif
+#endif // BOOTLOADER_BUILD
+
 
 FORCE_INLINE_ATTR bool is_issi_chip(const esp_rom_spiflash_chip_t* chip)
 {
@@ -563,29 +564,49 @@ esp_err_t IRAM_ATTR __attribute__((weak)) bootloader_flash_unlock(void)
     return err;
 }
 
+/* dummy_len_plus values defined in ROM for SPI flash configuration */
 #ifndef g_rom_spiflash_dummy_len_plus // ESP32-C3 uses a macro to access ROM data here
 extern uint8_t g_rom_spiflash_dummy_len_plus[];
 #endif
-uint32_t IRAM_ATTR bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len)
+IRAM_ATTR static uint32_t bootloader_flash_execute_command_common(
+    uint8_t command,
+    uint32_t addr_len, uint32_t address,
+    uint8_t dummy_len,
+    uint8_t mosi_len, uint32_t mosi_data,
+    uint8_t miso_len)
 {
+    assert(mosi_len <= 32);
+    assert(miso_len <= 32);
     uint32_t old_ctrl_reg = SPIFLASH.ctrl.val;
+    uint32_t old_user_reg = SPIFLASH.user.val;
+    uint32_t old_user1_reg = SPIFLASH.user1.val;
 #if CONFIG_IDF_TARGET_ESP32
     SPIFLASH.ctrl.val = SPI_WP_REG_M; // keep WP high while idle, otherwise leave DIO mode
 #else
     SPIFLASH.ctrl.val = SPI_MEM_WP_REG_M; // keep WP high while idle, otherwise leave DIO mode
 #endif
-    SPIFLASH.user.usr_dummy = 0;
-    SPIFLASH.user.usr_addr = 0;
+    //command phase
     SPIFLASH.user.usr_command = 1;
     SPIFLASH.user2.usr_command_bitlen = 7;
-
     SPIFLASH.user2.usr_command_value = command;
-    SPIFLASH.user.usr_miso = miso_len > 0;
+    //addr phase
+    SPIFLASH.user.usr_addr = addr_len > 0;
+    SPIFLASH.user1.usr_addr_bitlen = addr_len - 1;
 #if CONFIG_IDF_TARGET_ESP32
-    SPIFLASH.miso_dlen.usr_miso_dbitlen = miso_len ? (miso_len - 1) : 0;
+    SPIFLASH.addr = (addr_len > 0)? (address << (32-addr_len)) : 0;
 #else
-    SPIFLASH.miso_dlen.usr_miso_bit_len = miso_len ? (miso_len - 1) : 0;
+    SPIFLASH.addr = address;
 #endif
+    //dummy phase
+    if (miso_len > 0) {
+        uint32_t total_dummy = dummy_len + g_rom_spiflash_dummy_len_plus[1];
+        SPIFLASH.user.usr_dummy = total_dummy > 0;
+        SPIFLASH.user1.usr_dummy_cyclelen = total_dummy - 1;
+    } else {
+        SPIFLASH.user.usr_dummy = 0;
+        SPIFLASH.user1.usr_dummy_cyclelen = 0;
+    }
+    //output data
     SPIFLASH.user.usr_mosi = mosi_len > 0;
 #if CONFIG_IDF_TARGET_ESP32
     SPIFLASH.mosi_dlen.usr_mosi_dbitlen = mosi_len ? (mosi_len - 1) : 0;
@@ -593,24 +614,52 @@ uint32_t IRAM_ATTR bootloader_execute_flash_command(uint8_t command, uint32_t mo
     SPIFLASH.mosi_dlen.usr_mosi_bit_len = mosi_len ? (mosi_len - 1) : 0;
 #endif
     SPIFLASH.data_buf[0] = mosi_data;
-
-    if (g_rom_spiflash_dummy_len_plus[1]) {
-        /* When flash pins are mapped via GPIO matrix, need a dummy cycle before reading via MISO */
-        if (miso_len > 0) {
-            SPIFLASH.user.usr_dummy = 1;
-            SPIFLASH.user1.usr_dummy_cyclelen = g_rom_spiflash_dummy_len_plus[1] - 1;
-        } else {
-            SPIFLASH.user.usr_dummy = 0;
-            SPIFLASH.user1.usr_dummy_cyclelen = 0;
-        }
-    }
+    //input data
+    SPIFLASH.user.usr_miso = miso_len > 0;
+#if CONFIG_IDF_TARGET_ESP32
+    SPIFLASH.miso_dlen.usr_miso_dbitlen = miso_len ? (miso_len - 1) : 0;
+#else
+    SPIFLASH.miso_dlen.usr_miso_bit_len = miso_len ? (miso_len - 1) : 0;
+#endif
 
     SPIFLASH.cmd.usr = 1;
     while (SPIFLASH.cmd.usr != 0) {
     }
-
     SPIFLASH.ctrl.val = old_ctrl_reg;
-    return SPIFLASH.data_buf[0];
+    SPIFLASH.user.val = old_user_reg;
+    SPIFLASH.user1.val = old_user1_reg;
+
+    uint32_t ret = SPIFLASH.data_buf[0];
+    if (miso_len < 32) {
+        //set unused bits to 0
+        ret &= ~(UINT32_MAX << miso_len);
+    }
+    return ret;
+}
+
+uint32_t IRAM_ATTR bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len)
+{
+    const uint8_t addr_len = 0;
+    const uint8_t address = 0;
+    const uint8_t dummy_len = 0;
+
+    return bootloader_flash_execute_command_common(command, addr_len, address,
+            dummy_len, mosi_len, mosi_data, miso_len);
+}
+
+// cmd(0x5A) + 24bit address + 8 cycles dummy
+uint32_t IRAM_ATTR bootloader_flash_read_sfdp(uint32_t sfdp_addr, unsigned int miso_byte_num)
+{
+    assert(miso_byte_num <= 4);
+    const uint8_t command = CMD_RDSFDP;
+    const uint8_t addr_len = 24;
+    const uint8_t dummy_len = 8;
+    const uint8_t mosi_len = 0;
+    const uint32_t mosi_data = 0;
+    const uint8_t miso_len = miso_byte_num * 8;
+
+    return bootloader_flash_execute_command_common(command, addr_len, sfdp_addr,
+            dummy_len, mosi_len, mosi_data, miso_len);
 }
 
 void bootloader_enable_wp(void)
@@ -618,6 +667,13 @@ void bootloader_enable_wp(void)
     bootloader_execute_flash_command(CMD_WRDI, 0, 0, 0);   /* Exit OTP mode */
 }
 
+uint32_t IRAM_ATTR bootloader_read_flash_id(void)
+{
+    uint32_t id = bootloader_execute_flash_command(CMD_RDID, 0, 0, 24);
+    id = ((id & 0xff) << 16) | ((id >> 16) & 0xff) | (id & 0xff00);
+    return id;
+}
+
 #if SOC_CACHE_SUPPORT_WRAP
 esp_err_t bootloader_flash_wrap_set(spi_flash_wrap_mode_t mode)
 {
@@ -649,3 +705,104 @@ esp_err_t bootloader_flash_wrap_set(spi_flash_wrap_mode_t mode)
     return ESP_OK;
 }
 #endif //SOC_CACHE_SUPPORT_WRAP
+
+/*******************************************************************************
+ * XMC startup flow
+ ******************************************************************************/
+
+#define XMC_SUPPORT CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT
+#define XMC_VENDOR_ID 0x20
+
+#if BOOTLOADER_BUILD
+#define BOOTLOADER_FLASH_LOG(level, ...)    ESP_LOG##level(TAG, ##__VA_ARGS__)
+#else
+static DRAM_ATTR char bootloader_flash_tag[] = "bootloader_flash";
+#define BOOTLOADER_FLASH_LOG(level, ...)    ESP_DRAM_LOG##level(bootloader_flash_tag, ##__VA_ARGS__)
+#endif
+
+#if XMC_SUPPORT
+//strictly check the model
+static IRAM_ATTR bool is_xmc_chip_strict(uint32_t rdid)
+{
+    uint32_t vendor_id = BYTESHIFT(rdid, 2);
+    uint32_t mfid = BYTESHIFT(rdid, 1);
+    uint32_t cpid = BYTESHIFT(rdid, 0);
+
+    if (vendor_id != XMC_VENDOR_ID) {
+        return false;
+    }
+
+    bool matched = false;
+    if (mfid == 0x40) {
+        if (cpid >= 0x13 && cpid <= 0x20) {
+            matched = true;
+        }
+    } else if (mfid == 0x41) {
+        if (cpid >= 0x17 && cpid <= 0x20) {
+            matched = true;
+        }
+    } else if (mfid == 0x50) {
+        if (cpid >= 0x15 && cpid <= 0x16) {
+            matched =  true;
+        }
+    }
+    return matched;
+}
+
+esp_err_t IRAM_ATTR bootloader_flash_xmc_startup(void)
+{
+    // If the RDID value is a valid XMC one, may skip the flow
+    const bool fast_check = true;
+    if (fast_check && is_xmc_chip_strict(g_rom_flashchip.device_id)) {
+        BOOTLOADER_FLASH_LOG(D, "XMC chip detected by RDID (%08X), skip.", g_rom_flashchip.device_id);
+        return ESP_OK;
+    }
+
+    // Check the Manufacturer ID in SFDP registers (JEDEC standard). If not XMC chip, no need to run the flow
+    const int sfdp_mfid_addr = 0x10;
+    uint8_t mf_id = (bootloader_flash_read_sfdp(sfdp_mfid_addr, 1) & 0xff);
+    if (mf_id != XMC_VENDOR_ID) {
+        BOOTLOADER_FLASH_LOG(D, "non-XMC chip detected by SFDP Read (%02X), skip.", mf_id);
+        return ESP_OK;
+    }
+
+    BOOTLOADER_FLASH_LOG(I, "XM25QHxxC startup flow");
+    // Enter DPD
+    bootloader_execute_flash_command(0xB9, 0, 0, 0);
+    // Enter UDPD
+    bootloader_execute_flash_command(0x79, 0, 0, 0);
+    // Exit UDPD
+    bootloader_execute_flash_command(0xFF, 0, 0, 0);
+    // Delay tXUDPD
+    esp_rom_delay_us(2000);
+    // Release Power-down
+    bootloader_execute_flash_command(0xAB, 0, 0, 0);
+    esp_rom_delay_us(20);
+    // Read flash ID and check again
+    g_rom_flashchip.device_id = bootloader_read_flash_id();
+    if (!is_xmc_chip_strict(g_rom_flashchip.device_id)) {
+        BOOTLOADER_FLASH_LOG(E, "XMC flash startup fail");
+        return ESP_FAIL;
+    }
+
+    return ESP_OK;
+}
+
+#else
+//only compare the vendor id
+static IRAM_ATTR bool is_xmc_chip(uint32_t rdid)
+{
+    uint32_t vendor_id = (rdid >> 16) & 0xFF;
+    return (vendor_id == XMC_VENDOR_ID);
+}
+
+esp_err_t IRAM_ATTR bootloader_flash_xmc_startup(void)
+{
+    if (is_xmc_chip(g_rom_flashchip.device_id)) {
+        BOOTLOADER_FLASH_LOG(E, "XMC chip detected (%08X) while support disabled.", g_rom_flashchip.device_id);
+        return ESP_FAIL;
+    }
+    return ESP_OK;
+}
+
+#endif //XMC_SUPPORT

+ 8 - 8
components/bootloader_support/src/bootloader_flash_config_esp32s3.c

@@ -33,18 +33,18 @@ void bootloader_flash_update_id()
 
 void IRAM_ATTR bootloader_flash_cs_timing_config()
 {
-    // SPI0/1 share the cs_hold / cs_setup, cd_hold_time / cd_setup_time, cs_hold_delay registers for FLASH/PSRAM, so we only need to set SPI0 related registers here
+    //SPI0/1 share the cs_hold / cs_setup, cd_hold_time / cd_setup_time, cs_hold_delay registers for FLASH, so we only need to set SPI0 related registers here
+#if CONFIG_ESPTOOLPY_OCT_FLASH
     SET_PERI_REG_MASK(SPI_MEM_USER_REG(0), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M);
     SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_HOLD_TIME_V, FLASH_CS_HOLD_TIME, SPI_MEM_CS_HOLD_TIME_S);
     SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_SETUP_TIME_V, FLASH_CS_SETUP_TIME, SPI_MEM_CS_SETUP_TIME_S);
-
-    SET_PERI_REG_MASK(SPI_MEM_SPI_SMEM_AC_REG(0), SPI_MEM_SPI_SMEM_CS_HOLD_M | SPI_MEM_SPI_SMEM_CS_SETUP_M);
-    SET_PERI_REG_BITS(SPI_MEM_SPI_SMEM_AC_REG(0), SPI_MEM_SPI_SMEM_CS_HOLD_TIME_V, FLASH_CS_HOLD_TIME, SPI_MEM_SPI_SMEM_CS_HOLD_TIME_S);
-    SET_PERI_REG_BITS(SPI_MEM_SPI_SMEM_AC_REG(0), SPI_MEM_SPI_SMEM_CS_SETUP_TIME_V, FLASH_CS_SETUP_TIME, SPI_MEM_SPI_SMEM_CS_SETUP_TIME_S);
-
-    // cs high time
+    //CS high time
     SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_HOLD_DELAY_V, FLASH_CS_HOLD_DELAY, SPI_MEM_CS_HOLD_DELAY_S);
-    SET_PERI_REG_BITS(SPI_MEM_SPI_SMEM_AC_REG(0), SPI_MEM_SPI_SMEM_CS_HOLD_DELAY_V, FLASH_CS_HOLD_DELAY, SPI_MEM_SPI_SMEM_CS_HOLD_DELAY_S);
+#else
+    SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_HOLD_TIME_V, 0, SPI_MEM_CS_HOLD_TIME_S);
+    SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_SETUP_TIME_V, 0, SPI_MEM_CS_SETUP_TIME_S);
+    SET_PERI_REG_MASK(SPI_MEM_USER_REG(0), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M);
+#endif
 }
 
 void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t *pfhdr)

+ 7 - 0
components/bootloader_support/src/bootloader_utility.c

@@ -76,6 +76,7 @@
 #include "bootloader_utility.h"
 #include "bootloader_sha.h"
 #include "bootloader_console.h"
+#include "bootloader_soc.h"
 #include "esp_efuse.h"
 
 static const char *TAG = "boot";
@@ -636,6 +637,12 @@ static void load_image(const esp_image_metadata_t *image_data)
     ESP_LOGI(TAG, "Disabling RNG early entropy source...");
     bootloader_random_disable();
 
+    /* Disable glitch reset after all the security checks are completed.
+     * Glitch detection can be falsely triggered by EMI interference (high RF TX power, etc)
+     * and to avoid such false alarms, disable it.
+     */
+    bootloader_ana_clock_glitch_reset_config(false);
+
     // copy loaded segments to RAM, set up caches for mapped segments, and start application
     unpack_load_app(image_data);
 }

+ 5 - 0
components/bootloader_support/src/esp32/bootloader_esp32.c

@@ -387,6 +387,11 @@ esp_err_t bootloader_init(void)
     bootloader_print_banner();
     // update flash ID
     bootloader_flash_update_id();
+    // Check and run XMC startup flow
+    if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
+        ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
+        goto err;
+    }
     // read bootloader header
     if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
         goto err;

+ 21 - 0
components/bootloader_support/src/esp32/bootloader_soc.c

@@ -0,0 +1,21 @@
+/*
+ * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include <stdbool.h>
+
+void bootloader_ana_super_wdt_reset_config(bool enable)
+{
+    (void)enable;
+}
+
+void bootloader_ana_bod_reset_config(bool enable)
+{
+    (void)enable;
+}
+
+void bootloader_ana_clock_glitch_reset_config(bool enable)
+{
+    (void)enable;
+}

+ 29 - 6
components/bootloader_support/src/esp32c3/bootloader_esp32c3.c

@@ -36,6 +36,7 @@
 #include "regi2c_ctrl.h"
 #include "bootloader_console.h"
 #include "bootloader_flash_priv.h"
+#include "bootloader_soc.h"
 #include "esp_efuse.h"
 
 static const char *TAG = "boot.esp32c3";
@@ -263,7 +264,7 @@ static inline void bootloader_hardware_init(void)
     }
 }
 
-static inline void bootloader_glitch_reset_disable(void)
+static inline void bootloader_ana_reset_config(void)
 {
     /*
       For origin chip & ECO1: only support swt reset;
@@ -271,10 +272,27 @@ static inline void bootloader_glitch_reset_disable(void)
       For ECO3: fix clock glitch reset bug, support all reset, include: swt & brownout & clock glitch reset.
     */
     uint8_t chip_version = bootloader_common_get_chip_revision();
-    if (chip_version < 2) {
-        REG_SET_FIELD(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_SEL, RTC_CNTL_FIB_SUPER_WDT_RST);
-    } else if (chip_version == 2) {
-        REG_SET_FIELD(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_SEL, RTC_CNTL_FIB_SUPER_WDT_RST | RTC_CNTL_FIB_BOR_RST);
+    switch (chip_version) {
+        case 0:
+        case 1:
+            //Enable WDT reset. Disable BOR and GLITCH reset
+            bootloader_ana_super_wdt_reset_config(true);
+            bootloader_ana_bod_reset_config(false);
+            bootloader_ana_clock_glitch_reset_config(false);
+            break;
+        case 2:
+            //Enable WDT and BOR reset. Disable GLITCH reset
+            bootloader_ana_super_wdt_reset_config(true);
+            bootloader_ana_bod_reset_config(true);
+            bootloader_ana_clock_glitch_reset_config(false);
+            break;
+        case 3:
+        default:
+            //Enable WDT, BOR, and GLITCH reset
+            bootloader_ana_super_wdt_reset_config(true);
+            bootloader_ana_bod_reset_config(true);
+            bootloader_ana_clock_glitch_reset_config(true);
+            break;
     }
 }
 
@@ -283,7 +301,7 @@ esp_err_t bootloader_init(void)
     esp_err_t ret = ESP_OK;
 
     bootloader_hardware_init();
-    bootloader_glitch_reset_disable();
+    bootloader_ana_reset_config();
     bootloader_super_wdt_auto_feed();
     // protect memory region
     bootloader_init_mem();
@@ -309,6 +327,11 @@ esp_err_t bootloader_init(void)
     bootloader_print_banner();
     // update flash ID
     bootloader_flash_update_id();
+    // Check and run XMC startup flow
+    if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
+        ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
+        goto err;
+    }
     // read bootloader header
     if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
         goto err;

+ 41 - 0
components/bootloader_support/src/esp32c3/bootloader_soc.c

@@ -0,0 +1,41 @@
+/*
+ * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include <stdbool.h>
+#include "soc/soc.h"
+#include "soc/rtc_cntl_reg.h"
+
+void bootloader_ana_super_wdt_reset_config(bool enable)
+{
+    REG_CLR_BIT(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_SUPER_WDT_RST);
+
+    if (enable) {
+        REG_SET_BIT(RTC_CNTL_SWD_CONF_REG, RTC_CNTL_SWD_BYPASS_RST);
+    } else {
+        REG_CLR_BIT(RTC_CNTL_SWD_CONF_REG, RTC_CNTL_SWD_BYPASS_RST);
+    }
+}
+
+void bootloader_ana_bod_reset_config(bool enable)
+{
+    REG_CLR_BIT(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_BOR_RST);
+
+    if (enable) {
+        REG_SET_BIT(RTC_CNTL_BROWN_OUT_REG, RTC_CNTL_BROWN_OUT_ANA_RST_EN);
+    } else {
+        REG_CLR_BIT(RTC_CNTL_BROWN_OUT_REG, RTC_CNTL_BROWN_OUT_ANA_RST_EN);
+    }
+}
+
+void bootloader_ana_clock_glitch_reset_config(bool enable)
+{
+    REG_CLR_BIT(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_GLITCH_RST);
+
+    if (enable) {
+        REG_SET_BIT(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_GLITCH_RST_EN);
+    } else {
+        REG_CLR_BIT(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_GLITCH_RST_EN);
+    }
+}

+ 6 - 0
components/bootloader_support/src/esp32c3/flash_encryption_secure_features.c

@@ -40,5 +40,11 @@ esp_err_t esp_flash_encryption_enable_secure_features(void)
 
     esp_efuse_write_field_bit(ESP_EFUSE_DIS_LEGACY_SPI_BOOT);
 
+#if defined(CONFIG_SECURE_BOOT_V2_ENABLED) && !defined(CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS)
+    // This bit is set when enabling Secure Boot V2, but we can't enable it until this later point in the first boot
+    // otherwise the Flash Encryption key cannot be read protected
+    esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
+#endif
+
     return ESP_OK;
 }

+ 15 - 0
components/bootloader_support/src/esp32c3/secure_boot_secure_features.c

@@ -40,5 +40,20 @@ esp_err_t esp_secure_boot_enable_secure_features(void)
 
     esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
 
+#ifndef CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS
+    bool rd_dis_now = true;
+#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
+    /* If flash encryption is not enabled yet then don't read-disable efuses yet, do it later in the boot
+       when Flash Encryption is being enabled */
+    rd_dis_now = esp_flash_encryption_enabled();
+#endif
+    if (rd_dis_now) {
+        ESP_LOGI(TAG, "Prevent read disabling of additional efuses...");
+        esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
+    }
+#else
+    ESP_LOGW(TAG, "Allowing read disabling of additional efuses - SECURITY COMPROMISED");
+#endif
+
     return ESP_OK;
 }

+ 13 - 19
components/bootloader_support/src/esp32h2/bootloader_esp32h2.c

@@ -36,6 +36,7 @@
 #include "regi2c_ctrl.h"
 #include "bootloader_console.h"
 #include "bootloader_flash_priv.h"
+#include "bootloader_soc.h"
 
 static const char *TAG = "boot.esp32h2";
 
@@ -254,27 +255,15 @@ static void bootloader_super_wdt_auto_feed(void)
 
 static inline void bootloader_hardware_init(void)
 {
-    // This check is always included in the bootloader so it can
-    // print the minimum revision error message later in the boot
-    if (bootloader_common_get_chip_revision() < 3) {
-        REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_FORCE_XPD_IPH, 1);
-        REGI2C_WRITE_MASK(I2C_BIAS, I2C_BIAS_DREG_1P1_PVT, 12);
-    }
+
 }
 
-static inline void bootloader_glitch_reset_disable(void)
+static inline void bootloader_ana_reset_config(void)
 {
-    /*
-      For origin chip & ECO1: only support swt reset;
-      For ECO2: fix brownout reset bug, support swt & brownout reset;
-      For ECO3: fix clock glitch reset bug, support all reset, include: swt & brownout & clock glitch reset.
-    */
-    uint8_t chip_version = bootloader_common_get_chip_revision();
-    if (chip_version < 2) {
-        REG_SET_FIELD(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_SEL, RTC_CNTL_FIB_SUPER_WDT_RST);
-    } else if (chip_version == 2) {
-        REG_SET_FIELD(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_SEL, RTC_CNTL_FIB_SUPER_WDT_RST | RTC_CNTL_FIB_BOR_RST);
-    }
+    //Enable WDT, BOR, and GLITCH reset
+    bootloader_ana_super_wdt_reset_config(true);
+    bootloader_ana_bod_reset_config(true);
+    bootloader_ana_clock_glitch_reset_config(true);
 }
 
 esp_err_t bootloader_init(void)
@@ -282,7 +271,7 @@ esp_err_t bootloader_init(void)
     esp_err_t ret = ESP_OK;
 
     bootloader_hardware_init();
-    bootloader_glitch_reset_disable();
+    bootloader_ana_reset_config();
     bootloader_super_wdt_auto_feed();
     // protect memory region
     bootloader_init_mem();
@@ -301,6 +290,11 @@ esp_err_t bootloader_init(void)
     bootloader_print_banner();
     // update flash ID
     bootloader_flash_update_id();
+    // Check and run XMC startup flow
+    if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
+        ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
+        goto err;
+    }
     // read bootloader header
     if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
         goto err;

+ 41 - 0
components/bootloader_support/src/esp32h2/bootloader_soc.c

@@ -0,0 +1,41 @@
+/*
+ * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include <stdbool.h>
+#include "soc/soc.h"
+#include "soc/rtc_cntl_reg.h"
+
+void bootloader_ana_super_wdt_reset_config(bool enable)
+{
+    REG_CLR_BIT(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_SUPER_WDT_RST);
+
+    if (enable) {
+        REG_SET_BIT(RTC_CNTL_SWD_CONF_REG, RTC_CNTL_SWD_BYPASS_RST);
+    } else {
+        REG_CLR_BIT(RTC_CNTL_SWD_CONF_REG, RTC_CNTL_SWD_BYPASS_RST);
+    }
+}
+
+void bootloader_ana_bod_reset_config(bool enable)
+{
+    REG_CLR_BIT(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_BOR_RST);
+
+    if (enable) {
+        REG_SET_BIT(RTC_CNTL_BROWN_OUT_REG, RTC_CNTL_BROWN_OUT_ANA_RST_EN);
+    } else {
+        REG_CLR_BIT(RTC_CNTL_BROWN_OUT_REG, RTC_CNTL_BROWN_OUT_ANA_RST_EN);
+    }
+}
+
+void bootloader_ana_clock_glitch_reset_config(bool enable)
+{
+    REG_CLR_BIT(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_GLITCH_RST);
+
+    if (enable) {
+        REG_SET_BIT(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_GLITCH_RST_EN);
+    } else {
+        REG_CLR_BIT(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_GLITCH_RST_EN);
+    }
+}

+ 5 - 0
components/bootloader_support/src/esp32s2/bootloader_esp32s2.c

@@ -307,6 +307,11 @@ esp_err_t bootloader_init(void)
     bootloader_print_banner();
     // update flash ID
     bootloader_flash_update_id();
+    // Check and run XMC startup flow
+    if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
+        ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
+        goto err;
+    }
     // read bootloader header
     if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
         goto err;

+ 21 - 0
components/bootloader_support/src/esp32s2/bootloader_soc.c

@@ -0,0 +1,21 @@
+/*
+ * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include <stdbool.h>
+
+void bootloader_ana_super_wdt_reset_config(bool enable)
+{
+    (void)enable;
+}
+
+void bootloader_ana_bod_reset_config(bool enable)
+{
+    (void)enable;
+}
+
+void bootloader_ana_clock_glitch_reset_config(bool enable)
+{
+    (void)enable;
+}

+ 6 - 0
components/bootloader_support/src/esp32s2/flash_encryption_secure_features.c

@@ -41,5 +41,11 @@ esp_err_t esp_flash_encryption_enable_secure_features(void)
     esp_efuse_write_field_bit(ESP_EFUSE_DIS_BOOT_REMAP);
     esp_efuse_write_field_bit(ESP_EFUSE_DIS_LEGACY_SPI_BOOT);
 
+#if defined(CONFIG_SECURE_BOOT_V2_ENABLED) && !defined(CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS)
+    // This bit is set when enabling Secure Boot V2, but we can't enable it until this later point in the first boot
+    // otherwise the Flash Encryption key cannot be read protected
+    esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
+#endif
+
     return ESP_OK;
 }

+ 15 - 0
components/bootloader_support/src/esp32s2/secure_boot_secure_features.c

@@ -40,5 +40,20 @@ esp_err_t esp_secure_boot_enable_secure_features(void)
 
     esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
 
+#ifndef CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS
+    bool rd_dis_now = true;
+#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
+    /* If flash encryption is not enabled yet then don't read-disable efuses yet, do it later in the boot
+       when Flash Encryption is being enabled */
+    rd_dis_now = esp_flash_encryption_enabled();
+#endif
+    if (rd_dis_now) {
+        ESP_LOGI(TAG, "Prevent read disabling of additional efuses...");
+        esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
+    }
+#else
+    ESP_LOGW(TAG, "Allowing read disabling of additional efuses - SECURITY COMPROMISED");
+#endif
+
     return ESP_OK;
 }

+ 16 - 1
components/bootloader_support/src/esp32s3/bootloader_esp32s3.c

@@ -34,6 +34,7 @@
 #include "bootloader_mem.h"
 #include "bootloader_console.h"
 #include "bootloader_flash_priv.h"
+#include "bootloader_soc.h"
 #include "esp_efuse.h"
 
 
@@ -139,7 +140,7 @@ static void print_flash_info(const esp_image_header_t *bootloader_hdr)
         str = "20MHz";
         break;
     }
-    ESP_LOGI(TAG, "SPI Speed      : %s", str);
+    ESP_LOGI(TAG, "Boot SPI Speed : %s", str);
 
     /* SPI mode could have been set to QIO during boot already,
        so test the SPI registers not the flash header */
@@ -296,9 +297,18 @@ static void bootloader_super_wdt_auto_feed(void)
     REG_WRITE(RTC_CNTL_SWD_WPROTECT_REG, 0);
 }
 
+static inline void bootloader_ana_reset_config(void)
+{
+    //Enable WDT, BOR, and GLITCH reset
+    bootloader_ana_super_wdt_reset_config(true);
+    bootloader_ana_bod_reset_config(true);
+    bootloader_ana_clock_glitch_reset_config(true);
+}
+
 esp_err_t bootloader_init(void)
 {
     esp_err_t ret = ESP_OK;
+    bootloader_ana_reset_config();
     bootloader_super_wdt_auto_feed();
     // protect memory region
     bootloader_init_mem();
@@ -328,6 +338,11 @@ esp_err_t bootloader_init(void)
     bootloader_print_banner();
     // update flash ID
     bootloader_flash_update_id();
+    // Check and run XMC startup flow
+    if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
+        ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
+        goto err;
+    }
     // read bootloader header
     if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
         goto err;

+ 41 - 0
components/bootloader_support/src/esp32s3/bootloader_soc.c

@@ -0,0 +1,41 @@
+/*
+ * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include <stdbool.h>
+#include "soc/soc.h"
+#include "soc/rtc_cntl_reg.h"
+
+void bootloader_ana_super_wdt_reset_config(bool enable)
+{
+    REG_CLR_BIT(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_SUPER_WDT_RST);
+
+    if (enable) {
+        REG_SET_BIT(RTC_CNTL_SWD_CONF_REG, RTC_CNTL_SWD_BYPASS_RST);
+    } else {
+        REG_CLR_BIT(RTC_CNTL_SWD_CONF_REG, RTC_CNTL_SWD_BYPASS_RST);
+    }
+}
+
+void bootloader_ana_bod_reset_config(bool enable)
+{
+    REG_CLR_BIT(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_BOR_RST);
+
+    if (enable) {
+        REG_SET_BIT(RTC_CNTL_BROWN_OUT_REG, RTC_CNTL_BROWN_OUT_ANA_RST_EN);
+    } else {
+        REG_CLR_BIT(RTC_CNTL_BROWN_OUT_REG, RTC_CNTL_BROWN_OUT_ANA_RST_EN);
+    }
+}
+
+void bootloader_ana_clock_glitch_reset_config(bool enable)
+{
+    REG_CLR_BIT(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_GLITCH_RST);
+
+    if (enable) {
+        REG_SET_BIT(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_GLITCH_RST_EN);
+    } else {
+        REG_CLR_BIT(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_GLITCH_RST_EN);
+    }
+}

+ 6 - 0
components/bootloader_support/src/esp32s3/flash_encryption_secure_features.c

@@ -41,5 +41,11 @@ esp_err_t esp_flash_encryption_enable_secure_features(void)
 
     esp_efuse_write_field_bit(ESP_EFUSE_DIS_LEGACY_SPI_BOOT);
 
+#if defined(CONFIG_SECURE_BOOT_V2_ENABLED) && !defined(CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS)
+    // This bit is set when enabling Secure Boot V2, but we can't enable it until this later point in the first boot
+    // otherwise the Flash Encryption key cannot be read protected
+    esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
+#endif
+
     return ESP_OK;
 }

+ 16 - 0
components/bootloader_support/src/esp32s3/secure_boot_secure_features.c

@@ -27,6 +27,7 @@ esp_err_t esp_secure_boot_enable_secure_features(void)
 
 #ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
     ESP_LOGI(TAG, "Disable hardware & software JTAG...");
+    esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
     esp_efuse_write_field_bit(ESP_EFUSE_HARD_DIS_JTAG);
     esp_efuse_write_field_cnt(ESP_EFUSE_SOFT_DIS_JTAG, ESP_EFUSE_SOFT_DIS_JTAG[0]->bit_count);
 #else
@@ -39,5 +40,20 @@ esp_err_t esp_secure_boot_enable_secure_features(void)
 
     esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
 
+#ifndef CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS
+    bool rd_dis_now = true;
+#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
+    /* If flash encryption is not enabled yet then don't read-disable efuses yet, do it later in the boot
+       when Flash Encryption is being enabled */
+    rd_dis_now = esp_flash_encryption_enabled();
+#endif
+    if (rd_dis_now) {
+        ESP_LOGI(TAG, "Prevent read disabling of additional efuses...");
+        esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
+    }
+#else
+    ESP_LOGW(TAG, "Allowing read disabling of additional efuses - SECURITY COMPROMISED");
+#endif
+
     return ESP_OK;
 }

+ 0 - 8
components/bootloader_support/src/flash_qio_mode.c

@@ -105,14 +105,6 @@ static esp_err_t enable_qio_mode(read_status_fn_t read_status_fn,
    The command passed here is always the on-the-wire command given to the SPI flash unit.
 */
 
-/* dummy_len_plus values defined in ROM for SPI flash configuration */
-uint32_t bootloader_read_flash_id(void)
-{
-    uint32_t id = bootloader_execute_flash_command(CMD_RDID, 0, 0, 24);
-    id = ((id & 0xff) << 16) | ((id >> 16) & 0xff) | (id & 0xff00);
-    return id;
-}
-
 void bootloader_enable_qio_mode(void)
 {
     uint32_t raw_flash_id;

+ 19 - 4
components/bt/CMakeLists.txt

@@ -1,6 +1,8 @@
 if(CONFIG_BT_ENABLED)
     if(CONFIG_IDF_TARGET_ESP32)
-        set(srcs "controller/esp32/bt.c")
+        set(srcs "controller/esp32/bt.c"
+                 "controller/esp32/hli_api.c"
+                 "controller/esp32/hli_vectors.S")
     elseif(CONFIG_IDF_TARGET_ESP32C3)
         set(srcs "controller/esp32c3/bt.c")
     elseif(CONFIG_IDF_TARGET_ESP32S3)
@@ -55,6 +57,7 @@ if(CONFIG_BT_ENABLED)
             host/bluedroid/bta/gatt/include
             host/bluedroid/bta/hf_ag/include
             host/bluedroid/bta/hf_client/include
+            host/bluedroid/bta/hd/include
             host/bluedroid/bta/hh/include
             host/bluedroid/bta/jv/include
             host/bluedroid/bta/sdp/include
@@ -66,12 +69,12 @@ if(CONFIG_BT_ENABLED)
             host/bluedroid/external/sbc/plc/include
             host/bluedroid/btc/profile/esp/include
             host/bluedroid/btc/profile/std/a2dp/include
-            host/bluedroid/btc/profile/std/hid/include
             host/bluedroid/btc/profile/std/include
             host/bluedroid/btc/include
             host/bluedroid/stack/btm/include
             host/bluedroid/stack/gap/include
             host/bluedroid/stack/gatt/include
+            host/bluedroid/stack/hid/include
             host/bluedroid/stack/l2cap/include
             host/bluedroid/stack/sdp/include
             host/bluedroid/stack/smp/include
@@ -94,6 +97,8 @@ if(CONFIG_BT_ENABLED)
                    "host/bluedroid/api/esp_gatt_common_api.c"
                    "host/bluedroid/api/esp_gattc_api.c"
                    "host/bluedroid/api/esp_gatts_api.c"
+                   "host/bluedroid/api/esp_hidd_api.c"
+                   "host/bluedroid/api/esp_hidh_api.c"
                    "host/bluedroid/api/esp_hf_ag_api.c"
                    "host/bluedroid/api/esp_hf_client_api.c"
                    "host/bluedroid/api/esp_spp_api.c"
@@ -128,6 +133,9 @@ if(CONFIG_BT_ENABLED)
                    "host/bluedroid/bta/gatt/bta_gatts_co.c"
                    "host/bluedroid/bta/gatt/bta_gatts_main.c"
                    "host/bluedroid/bta/gatt/bta_gatts_utils.c"
+                   "host/bluedroid/bta/hd/bta_hd_api.c"
+                   "host/bluedroid/bta/hd/bta_hd_act.c"
+                   "host/bluedroid/bta/hd/bta_hd_main.c"
                    "host/bluedroid/bta/hh/bta_hh_act.c"
                    "host/bluedroid/bta/hh/bta_hh_api.c"
                    "host/bluedroid/bta/hh/bta_hh_cfg.c"
@@ -184,8 +192,9 @@ if(CONFIG_BT_ENABLED)
                    "host/bluedroid/btc/profile/std/hf_ag/btc_hf_ag.c"
                    "host/bluedroid/btc/profile/std/hf_client/btc_hf_client.c"
                    "host/bluedroid/btc/profile/std/hf_client/bta_hf_client_co.c"
-                   "host/bluedroid/btc/profile/std/hid/hidh_api.c"
-                   "host/bluedroid/btc/profile/std/hid/hidh_conn.c"
+                   "host/bluedroid/btc/profile/std/hid/btc_hd.c"
+                   "host/bluedroid/btc/profile/std/hid/btc_hh.c"
+                   "host/bluedroid/btc/profile/std/hid/bta_hh_co.c"
                    "host/bluedroid/btc/profile/std/gap/btc_gap_ble.c"
                    "host/bluedroid/btc/profile/std/gap/btc_gap_bt.c"
                    "host/bluedroid/btc/profile/std/gap/bta_gap_bt_co.c"
@@ -251,6 +260,10 @@ if(CONFIG_BT_ENABLED)
                    "host/bluedroid/stack/avrc/avrc_pars_tg.c"
                    "host/bluedroid/stack/avrc/avrc_sdp.c"
                    "host/bluedroid/stack/avrc/avrc_utils.c"
+                   "host/bluedroid/stack/hid/hidd_api.c"
+                   "host/bluedroid/stack/hid/hidd_conn.c"
+                   "host/bluedroid/stack/hid/hidh_api.c"
+                   "host/bluedroid/stack/hid/hidh_conn.c"
                    "host/bluedroid/stack/btm/btm_acl.c"
                    "host/bluedroid/stack/btm/btm_ble.c"
                    "host/bluedroid/stack/btm/btm_ble_addr.c"
@@ -597,6 +610,8 @@ if(CONFIG_BT_ENABLED)
     if(CONFIG_IDF_TARGET_ESP32)
         target_link_libraries(${COMPONENT_LIB} INTERFACE "-L${CMAKE_CURRENT_LIST_DIR}/controller/lib_esp32/esp32")
         target_link_libraries(${COMPONENT_LIB} PUBLIC btdm_app)
+
+        target_link_libraries(${COMPONENT_LIB} INTERFACE "-u ld_include_hli_vectors_bt")
     elseif(CONFIG_IDF_TARGET_ESP32C3)
         target_link_libraries(${COMPONENT_LIB} INTERFACE
                 "-L${CMAKE_CURRENT_LIST_DIR}/controller/lib_esp32c3_family/esp32c3")

+ 5 - 31
components/bt/Kconfig

@@ -7,42 +7,16 @@ menu "Bluetooth"
         help
             Select this option to enable Bluetooth and show the submenu with Bluetooth configuration choices.
 
-    config BT_CTRL_ESP32
-        bool
-        depends on BT_ENABLED && IDF_TARGET_ESP32
-        default y
-
-    config BT_CTRL_ESP32C3
-        bool
-        depends on BT_ENABLED && IDF_TARGET_ESP32C3
-        default y
-    config BT_CTRL_ESP32S3
-        bool
-        depends on BT_ENABLED && IDF_TARGET_ESP32S3
-        default y
-
     config BT_SOC_SUPPORT_5_0
         bool
         depends on BT_ENABLED && (IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3)
         default y if BT_ENABLED && (IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3)
         default n
 
-    menu "Bluetooth controller(ESP32 Dual Mode Bluetooth)"
-        visible if BT_CTRL_ESP32
-
-        source "$IDF_PATH/components/bt/controller/esp32/Kconfig.in"
-    endmenu
-
-    menu "Bluetooth controller(ESP32C3 Bluetooth Low Energy)"
-        visible if BT_CTRL_ESP32C3
-
-        source "$IDF_PATH/components/bt/controller/esp32c3/Kconfig.in"
-    endmenu
-
-    menu "Bluetooth controller(ESP32S3 Bluetooth Low Energy)"
-        visible if BT_CTRL_ESP32S3
+    menu "Bluetooth controller"
+        depends on BT_ENABLED
 
-        source "$IDF_PATH/components/bt/controller/esp32s3/Kconfig.in"
+        source "$IDF_PATH/components/bt/controller/$IDF_TARGET/Kconfig.in"
     endmenu
 
     choice BT_HOST
@@ -73,12 +47,12 @@ menu "Bluetooth"
     endchoice
 
     menu "Bluedroid Options"
-        visible if BT_BLUEDROID_ENABLED
+        depends on BT_BLUEDROID_ENABLED
 
         source "$IDF_PATH/components/bt/host/bluedroid/Kconfig.in"
     endmenu
     menu "NimBLE Options"
-        visible if BT_NIMBLE_ENABLED
+        depends on BT_NIMBLE_ENABLED
 
         source "$IDF_PATH/components/bt/host/nimble/Kconfig.in"
     endmenu

+ 12 - 0
components/bt/common/btc/core/btc_task.c

@@ -53,6 +53,12 @@
 #if BTC_HF_CLIENT_INCLUDED
 #include "btc_hf_client.h"
 #endif  /* #if BTC_HF_CLIENT_INCLUDED */
+#if BTC_HD_INCLUDED == TRUE
+#include "btc_hd.h"
+#endif /* BTC_HD_INCLUDED */
+#if BTC_HH_INCLUDED == TRUE
+#include "btc_hh.h"
+#endif /* BTC_HH_INCLUDED */
 #endif /* #if CLASSIC_BT_INCLUDED */
 #endif
 
@@ -120,6 +126,12 @@ static const btc_func_t profile_tab[BTC_PID_NUM] = {
 #if BTC_HF_CLIENT_INCLUDED
     [BTC_PID_HF_CLIENT]   = {btc_hf_client_call_handler,  btc_hf_client_cb_handler},
 #endif  /* #if BTC_HF_CLIENT_INCLUDED */
+#if BTC_HD_INCLUDED
+    [BTC_PID_HD]          = {btc_hd_call_handler,          btc_hd_cb_handler      },
+#endif
+#if BTC_HH_INCLUDED
+    [BTC_PID_HH]          = {btc_hh_call_handler,          btc_hh_cb_handler      },
+#endif
 #endif /* #if CLASSIC_BT_INCLUDED */
 #endif
 #if CONFIG_BLE_MESH

+ 10 - 0
components/bt/common/btc/include/btc/btc_task.h

@@ -65,6 +65,8 @@ typedef enum {
     BTC_PID_AVRC_CT,
     BTC_PID_AVRC_TG,
     BTC_PID_SPP,
+    BTC_PID_HD,
+    BTC_PID_HH,
 #if (BTC_HF_INCLUDED == TRUE)
     BTC_PID_HF,
 #endif /* BTC_HF_INCLUDED */
@@ -99,6 +101,10 @@ typedef struct {
 
 typedef void (* btc_arg_deep_copy_t)(btc_msg_t *msg, void *dst, void *src);
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /**
  * transfer an message to another module in the different task.
  * @param  msg       message
@@ -124,4 +130,8 @@ void btc_deinit(void);
 bool btc_check_queue_is_congest(void);
 int get_btc_work_queue_size(void);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* __BTC_TASK_H__ */

+ 11 - 0
components/bt/common/osi/alarm.c

@@ -318,3 +318,14 @@ uint32_t osi_time_get_os_boottime_ms(void)
 {
     return (uint32_t)(esp_timer_get_time() / 1000);
 }
+
+bool osi_alarm_is_active(osi_alarm_t *alarm)
+{
+    assert(alarm != NULL);
+
+    if (alarm->alarm_hdl != NULL) {
+        return esp_timer_is_active(alarm->alarm_hdl);
+    }
+
+    return false;
+}

+ 4 - 0
components/bt/common/osi/include/osi/alarm.h

@@ -77,4 +77,8 @@ period_ms_t osi_alarm_get_remaining_ms(const osi_alarm_t *alarm);
 
 uint32_t osi_time_get_os_boottime_ms(void);
 
+// This function returns whether the given |alarm| is active or not.
+// Return true if active, false otherwise.
+bool osi_alarm_is_active(osi_alarm_t *alarm);
+
 #endif /*_ALARM_H_*/

+ 5 - 0
components/bt/component.mk

@@ -10,6 +10,7 @@ COMPONENT_ADD_INCLUDEDIRS := include
 LIBS := btdm_app
 
 COMPONENT_ADD_LDFLAGS     := -lbt -L $(COMPONENT_PATH)/controller/lib_esp32/esp32 \
+                          -u ld_include_hli_vectors_bt \
                            $(addprefix -l,$(LIBS))
 
 # re-link program if BT binary libs change
@@ -46,6 +47,7 @@ COMPONENT_PRIV_INCLUDEDIRS +=   host/bluedroid/bta/include                   \
                                 host/bluedroid/bta/hf_client/include         \
                                 host/bluedroid/bta/dm/include                \
                                 host/bluedroid/bta/gatt/include              \
+                                host/bluedroid/bta/hd/include                \
                                 host/bluedroid/bta/hh/include                \
                                 host/bluedroid/bta/jv/include                \
                                 host/bluedroid/bta/sdp/include               \
@@ -70,6 +72,7 @@ COMPONENT_PRIV_INCLUDEDIRS +=   host/bluedroid/bta/include                   \
                                 host/bluedroid/stack/gap/include             \
                                 host/bluedroid/stack/gatt/include            \
                                 host/bluedroid/stack/hcic/include            \
+                                host/bluedroid/stack/hid/include             \
                                 host/bluedroid/stack/l2cap/include           \
                                 host/bluedroid/stack/sdp/include             \
                                 host/bluedroid/stack/smp/include             \
@@ -86,6 +89,7 @@ COMPONENT_ADD_INCLUDEDIRS +=    host/bluedroid/api/include/api       \
 
 COMPONENT_SRCDIRS +=    host/bluedroid/bta/dm                      \
                         host/bluedroid/bta/gatt                    \
+                        host/bluedroid/bta/hd                      \
                         host/bluedroid/bta/hh                      \
                         host/bluedroid/bta/sdp                     \
                         host/bluedroid/bta/av                      \
@@ -118,6 +122,7 @@ COMPONENT_SRCDIRS +=    host/bluedroid/bta/dm                      \
                         host/bluedroid/stack/gap                   \
                         host/bluedroid/stack/gatt                  \
                         host/bluedroid/stack/hcic                  \
+                        host/bluedroid/stack/hid                   \
                         host/bluedroid/stack/include               \
                         host/bluedroid/stack/l2cap                 \
                         host/bluedroid/stack/sdp                   \

+ 14 - 6
components/bt/controller/esp32/Kconfig.in

@@ -1,6 +1,5 @@
 choice BTDM_CTRL_MODE
     prompt "Bluetooth controller mode (BR/EDR/BLE/DUALMODE)"
-    depends on BT_CTRL_ESP32
     help
         Specify the bluetooth controller mode (BR/EDR, BLE or dual mode).
 
@@ -152,7 +151,7 @@ config BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF
 
 choice BTDM_CTRL_PINNED_TO_CORE_CHOICE
     prompt "The cpu core which bluetooth controller run"
-    depends on BT_CTRL_ESP32 && !FREERTOS_UNICORE
+    depends on !FREERTOS_UNICORE
     help
         Specify the cpu core to run bluetooth controller.
         Can not specify no-affinity.
@@ -172,7 +171,6 @@ config BTDM_CTRL_PINNED_TO_CORE
 
 choice BTDM_CTRL_HCI_MODE_CHOICE
     prompt "HCI mode"
-    depends on BT_CTRL_ESP32
     help
         Speicify HCI mode as VHCI or UART(H4)
 
@@ -210,11 +208,8 @@ menu "HCI UART(H4) Options"
 endmenu
 
 menu "MODEM SLEEP Options"
-    visible if BT_CTRL_ESP32
-
     config BTDM_CTRL_MODEM_SLEEP
         bool "Bluetooth modem sleep"
-        depends on BT_CTRL_ESP32
         default y
         help
             Enable/disable bluetooth controller low power mode.
@@ -415,3 +410,16 @@ config BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD
         of ADV packets lost in the controller reaches this threshold. It is better to set a larger value.
         If you set `BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD` to a small value or printf every adv lost event, it
         may cause adv packets lost more.
+
+
+config BTDM_RESERVE_DRAM
+    hex
+    default 0xdb5c if BT_ENABLED
+    default 0
+
+config BTDM_CTRL_HLI
+    bool "High level interrupt"
+    depends on BT_ENABLED
+    default y
+    help
+        Using Level 4 interrupt for Bluetooth.

+ 281 - 25
components/bt/controller/esp32/bt.c

@@ -40,6 +40,7 @@
 #include "driver/periph_ctrl.h"
 #include "soc/rtc.h"
 #include "soc/soc_memory_layout.h"
+#include "soc/dport_reg.h"
 #include "esp32/clk.h"
 #include "esp_coexist_internal.h"
 #if !CONFIG_FREERTOS_UNICORE
@@ -47,6 +48,7 @@
 #endif
 
 #include "esp_rom_sys.h"
+#include "hli_api.h"
 
 #if CONFIG_BT_ENABLED
 
@@ -54,6 +56,7 @@
  ************************************************************************
  */
 
+#define UNUSED(x)                           (void)(x)
 #define BTDM_LOG_TAG                        "BTDM_INIT"
 
 #define BTDM_INIT_PERIOD                    (5000)    /* ms */
@@ -92,12 +95,12 @@ do{\
 } while(0)
 
 #define OSI_FUNCS_TIME_BLOCKING  0xffffffff
-#define OSI_VERSION              0x00010002
+#define OSI_VERSION              0x00010003
 #define OSI_MAGIC_VALUE          0xFADEBEAD
 
 /* SPIRAM Configuration */
 #if CONFIG_SPIRAM_USE_MALLOC
-#define BTDM_MAX_QUEUE_NUM       (5)
+#define BTDM_MAX_QUEUE_NUM       (6)
 #endif
 
 /* Types definition
@@ -184,6 +187,10 @@ struct osi_funcs_t {
     void *(* _coex_schm_curr_phase_get)(void);
     int (* _coex_wifi_channel_get)(uint8_t *primary, uint8_t *secondary);
     int (* _coex_register_wifi_channel_change_callback)(void *cb);
+    xt_handler (*_set_isr_l3)(int n, xt_handler f, void *arg);
+    void (*_interrupt_l3_disable)(void);
+    void (*_interrupt_l3_restore)(void);
+    void *(* _customer_queue_create)(uint32_t queue_len, uint32_t item_size);
     uint32_t _magic;
 };
 
@@ -268,8 +275,13 @@ extern uint32_t _btdm_data_end;
 static bool btdm_queue_generic_register(const btdm_queue_item_t *queue);
 static bool btdm_queue_generic_deregister(btdm_queue_item_t *queue);
 #endif /* CONFIG_SPIRAM_USE_MALLOC */
-static void IRAM_ATTR interrupt_disable(void);
-static void IRAM_ATTR interrupt_restore(void);
+
+#if CONFIG_BTDM_CTRL_HLI
+static xt_handler set_isr_hlevel_wrapper(int n, xt_handler f, void *arg);
+static void IRAM_ATTR interrupt_hlevel_disable(void);
+static void IRAM_ATTR interrupt_hlevel_restore(void);
+#endif /* CONFIG_BTDM_CTRL_HLI */
+static void IRAM_ATTR task_yield(void);
 static void IRAM_ATTR task_yield_from_isr(void);
 static void *semphr_create_wrapper(uint32_t max, uint32_t init);
 static void semphr_delete_wrapper(void *semphr);
@@ -281,12 +293,21 @@ static void *mutex_create_wrapper(void);
 static void mutex_delete_wrapper(void *mutex);
 static int32_t mutex_lock_wrapper(void *mutex);
 static int32_t mutex_unlock_wrapper(void *mutex);
+#if CONFIG_BTDM_CTRL_HLI
+static void *queue_create_hlevel_wrapper(uint32_t queue_len, uint32_t item_size);
+static void queue_delete_hlevel_wrapper(void *queue);
+static int32_t IRAM_ATTR queue_send_hlevel_wrapper(void *queue, void *item, uint32_t block_time_ms);
+static int32_t IRAM_ATTR queue_send_from_isr_hlevel_wrapper(void *queue, void *item, void *hptw);
+static int32_t IRAM_ATTR queue_recv_hlevel_wrapper(void *queue, void *item, uint32_t block_time_ms);
+static int32_t IRAM_ATTR queue_recv_from_isr_hlevel_wrapper(void *queue, void *item, void *hptw);
+#else
 static void *queue_create_wrapper(uint32_t queue_len, uint32_t item_size);
 static void queue_delete_wrapper(void *queue);
-static int32_t queue_send_wrapper(void *queue, void *item, uint32_t block_time_ms);
+static int32_t IRAM_ATTR queue_send_wrapper(void *queue, void *item, uint32_t block_time_ms);
 static int32_t IRAM_ATTR queue_send_from_isr_wrapper(void *queue, void *item, void *hptw);
-static int32_t queue_recv_wrapper(void *queue, void *item, uint32_t block_time_ms);
+static int32_t IRAM_ATTR queue_recv_wrapper(void *queue, void *item, uint32_t block_time_ms);
 static int32_t IRAM_ATTR queue_recv_from_isr_wrapper(void *queue, void *item, void *hptw);
+#endif /* CONFIG_BTDM_CTRL_HLI */
 static int32_t task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id);
 static void task_delete_wrapper(void *task_handle);
 static bool IRAM_ATTR is_in_isr_wrapper(void);
@@ -317,17 +338,30 @@ static uint8_t coex_schm_curr_period_get_wrapper(void);
 static void * coex_schm_curr_phase_get_wrapper(void);
 static int coex_wifi_channel_get_wrapper(uint8_t *primary, uint8_t *secondary);
 static int coex_register_wifi_channel_change_callback_wrapper(void *cb);
+#if CONFIG_BTDM_CTRL_HLI
+static void *customer_queue_create_hlevel_wrapper(uint32_t queue_len, uint32_t item_size);
+#endif /* CONFIG_BTDM_CTRL_HLI */
+static void IRAM_ATTR interrupt_l3_disable(void);
+static void IRAM_ATTR interrupt_l3_restore(void);
+
 /* Local variable definition
  ***************************************************************************
  */
 /* OSI funcs */
 static const struct osi_funcs_t osi_funcs_ro = {
     ._version = OSI_VERSION,
+#if CONFIG_BTDM_CTRL_HLI
+    ._set_isr = set_isr_hlevel_wrapper,
+    ._ints_on = xt_ints_on,
+    ._interrupt_disable = interrupt_hlevel_disable,
+    ._interrupt_restore = interrupt_hlevel_restore,
+#else
     ._set_isr = xt_set_interrupt_handler,
     ._ints_on = xt_ints_on,
-    ._interrupt_disable = interrupt_disable,
-    ._interrupt_restore = interrupt_restore,
-    ._task_yield = vPortYield,
+    ._interrupt_disable = interrupt_l3_disable,
+    ._interrupt_restore = interrupt_l3_restore,
+#endif /* CONFIG_BTDM_CTRL_HLI */
+    ._task_yield = task_yield,
     ._task_yield_from_isr = task_yield_from_isr,
     ._semphr_create = semphr_create_wrapper,
     ._semphr_delete = semphr_delete_wrapper,
@@ -339,12 +373,21 @@ static const struct osi_funcs_t osi_funcs_ro = {
     ._mutex_delete = mutex_delete_wrapper,
     ._mutex_lock = mutex_lock_wrapper,
     ._mutex_unlock = mutex_unlock_wrapper,
+#if CONFIG_BTDM_CTRL_HLI
+    ._queue_create = queue_create_hlevel_wrapper,
+    ._queue_delete = queue_delete_hlevel_wrapper,
+    ._queue_send = queue_send_hlevel_wrapper,
+    ._queue_send_from_isr = queue_send_from_isr_hlevel_wrapper,
+    ._queue_recv = queue_recv_hlevel_wrapper,
+    ._queue_recv_from_isr = queue_recv_from_isr_hlevel_wrapper,
+#else
     ._queue_create = queue_create_wrapper,
     ._queue_delete = queue_delete_wrapper,
     ._queue_send = queue_send_wrapper,
     ._queue_send_from_isr = queue_send_from_isr_wrapper,
     ._queue_recv = queue_recv_wrapper,
     ._queue_recv_from_isr = queue_recv_from_isr_wrapper,
+#endif /* CONFIG_BTDM_CTRL_HLI */
     ._task_create = task_create_wrapper,
     ._task_delete = task_delete_wrapper,
     ._is_in_isr = is_in_isr_wrapper,
@@ -378,6 +421,14 @@ static const struct osi_funcs_t osi_funcs_ro = {
     ._coex_schm_curr_phase_get = coex_schm_curr_phase_get_wrapper,
     ._coex_wifi_channel_get = coex_wifi_channel_get_wrapper,
     ._coex_register_wifi_channel_change_callback = coex_register_wifi_channel_change_callback_wrapper,
+    ._set_isr_l3 = xt_set_interrupt_handler,
+    ._interrupt_l3_disable = interrupt_l3_disable,
+    ._interrupt_l3_restore = interrupt_l3_restore,
+#if CONFIG_BTDM_CTRL_HLI
+    ._customer_queue_create = customer_queue_create_hlevel_wrapper,
+#else
+    ._customer_queue_create = NULL,
+#endif /* CONFIG_BTDM_CTRL_HLI */
     ._magic = OSI_MAGIC_VALUE,
 };
 
@@ -494,7 +545,48 @@ static bool btdm_queue_generic_deregister(btdm_queue_item_t *queue)
 
 #endif /* CONFIG_SPIRAM_USE_MALLOC */
 
-static void IRAM_ATTR interrupt_disable(void)
+#if CONFIG_BTDM_CTRL_HLI
+struct interrupt_hlevel_cb{
+    uint32_t status;
+    uint8_t nested;
+};
+
+static DRAM_ATTR struct interrupt_hlevel_cb hli_cb = {
+    .status = 0,
+    .nested = 0,
+};
+
+static xt_handler set_isr_hlevel_wrapper(int mask, xt_handler f, void *arg)
+{
+    esp_err_t err = hli_intr_register((intr_handler_t) f, arg, DPORT_PRO_INTR_STATUS_0_REG, mask);
+    if (err == ESP_OK) {
+        return f;
+    } else {
+        return 0;
+    }
+ }
+
+static void IRAM_ATTR interrupt_hlevel_disable(void)
+{
+    assert(xPortGetCoreID() == CONFIG_BTDM_CTRL_PINNED_TO_CORE);
+    assert(hli_cb.nested != ~0);
+    uint32_t status = hli_intr_disable();
+    if (hli_cb.nested++ == 0) {
+        hli_cb.status = status;
+    }
+}
+
+static void IRAM_ATTR interrupt_hlevel_restore(void)
+{
+    assert(xPortGetCoreID() == CONFIG_BTDM_CTRL_PINNED_TO_CORE);
+    assert(hli_cb.nested > 0);
+    if (--hli_cb.nested == 0) {
+        hli_intr_restore(hli_cb.status);
+    }
+}
+#endif /* CONFIG_BTDM_CTRL_HLI */
+
+static void IRAM_ATTR interrupt_l3_disable(void)
 {
     if (xPortInIsrContext()) {
         portENTER_CRITICAL_ISR(&global_int_mux);
@@ -503,7 +595,7 @@ static void IRAM_ATTR interrupt_disable(void)
     }
 }
 
-static void IRAM_ATTR interrupt_restore(void)
+static void IRAM_ATTR interrupt_l3_restore(void)
 {
     if (xPortInIsrContext()) {
         portEXIT_CRITICAL_ISR(&global_int_mux);
@@ -512,6 +604,12 @@ static void IRAM_ATTR interrupt_restore(void)
     }
 }
 
+static void IRAM_ATTR task_yield(void)
+{
+    vPortYield();
+}
+
+
 static void IRAM_ATTR task_yield_from_isr(void)
 {
     portYIELD_FROM_ISR();
@@ -519,18 +617,19 @@ static void IRAM_ATTR task_yield_from_isr(void)
 
 static void *semphr_create_wrapper(uint32_t max, uint32_t init)
 {
+    void *handle = NULL;
+
 #if !CONFIG_SPIRAM_USE_MALLOC
-    return (void *)xSemaphoreCreateCounting(max, init);
+    handle = (void *)xSemaphoreCreateCounting(max, init);
 #else
     StaticQueue_t *queue_buffer = NULL;
-    QueueHandle_t handle = NULL;
 
     queue_buffer = heap_caps_malloc(sizeof(StaticQueue_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
     if (!queue_buffer) {
         goto error;
     }
 
-    handle = xSemaphoreCreateCountingStatic(max, init, queue_buffer);
+    handle = (void *)xSemaphoreCreateCountingStatic(max, init, queue_buffer);
     if (!handle) {
         goto error;
     }
@@ -544,8 +643,19 @@ static void *semphr_create_wrapper(uint32_t max, uint32_t init)
     if (!btdm_queue_generic_register(&item)) {
         goto error;
     }
+#endif
+
+#if CONFIG_BTDM_CTRL_HLI
+    SemaphoreHandle_t downstream_semaphore = handle;
+    assert(downstream_semaphore);
+    hli_queue_handle_t s_semaphore = hli_semaphore_create(max, downstream_semaphore);
+    assert(downstream_semaphore);
+    return s_semaphore;
+#else
     return handle;
+#endif /* CONFIG_BTDM_CTRL_HLI */
 
+#if CONFIG_SPIRAM_USE_MALLOC
  error:
     if (handle) {
         vSemaphoreDelete(handle);
@@ -560,11 +670,22 @@ static void *semphr_create_wrapper(uint32_t max, uint32_t init)
 
 static void semphr_delete_wrapper(void *semphr)
 {
+    void *handle = NULL;
+#if CONFIG_BTDM_CTRL_HLI
+    if (((hli_queue_handle_t)semphr)->downstream != NULL) {
+        handle = ((hli_queue_handle_t)semphr)->downstream;
+     }
+
+    hli_queue_delete(semphr);
+#else
+    handle = semphr;
+#endif /* CONFIG_BTDM_CTRL_HLI */
+
 #if !CONFIG_SPIRAM_USE_MALLOC
-    vSemaphoreDelete(semphr);
+    vSemaphoreDelete(handle);
 #else
     btdm_queue_item_t item = {
-        .handle = semphr,
+        .handle = handle,
         .storage = NULL,
         .buffer = NULL,
     };
@@ -573,33 +694,55 @@ static void semphr_delete_wrapper(void *semphr)
         vSemaphoreDelete(item.handle);
         free(item.buffer);
     }
-
-    return;
 #endif
 }
 
 static int32_t IRAM_ATTR semphr_take_from_isr_wrapper(void *semphr, void *hptw)
 {
+#if CONFIG_BTDM_CTRL_HLI
+    return (int32_t)xSemaphoreTakeFromISR(((hli_queue_handle_t)semphr)->downstream, hptw);
+#else
     return (int32_t)xSemaphoreTakeFromISR(semphr, hptw);
+#endif /* CONFIG_BTDM_CTRL_HLI */
 }
 
 static int32_t IRAM_ATTR semphr_give_from_isr_wrapper(void *semphr, void *hptw)
 {
+#if CONFIG_BTDM_CTRL_HLI
+    UNUSED(hptw);
+    assert(xPortGetCoreID() == CONFIG_BTDM_CTRL_PINNED_TO_CORE);
+    return hli_semaphore_give(semphr);
+#else
     return (int32_t)xSemaphoreGiveFromISR(semphr, hptw);
+#endif /* CONFIG_BTDM_CTRL_HLI */
 }
 
 static int32_t semphr_take_wrapper(void *semphr, uint32_t block_time_ms)
 {
+    bool ret;
+#if CONFIG_BTDM_CTRL_HLI
+    if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) {
+        ret = xSemaphoreTake(((hli_queue_handle_t)semphr)->downstream, portMAX_DELAY);
+    } else {
+        ret = xSemaphoreTake(((hli_queue_handle_t)semphr)->downstream, block_time_ms / portTICK_PERIOD_MS);
+    }
+#else
     if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) {
-        return (int32_t)xSemaphoreTake(semphr, portMAX_DELAY);
+        ret = xSemaphoreTake(semphr, portMAX_DELAY);
     } else {
-        return (int32_t)xSemaphoreTake(semphr, block_time_ms / portTICK_PERIOD_MS);
+        ret = xSemaphoreTake(semphr, block_time_ms / portTICK_PERIOD_MS);
     }
+#endif /* CONFIG_BTDM_CTRL_HLI */
+    return (int32_t)ret;
 }
 
 static int32_t semphr_give_wrapper(void *semphr)
 {
+#if CONFIG_BTDM_CTRL_HLI
+    return (int32_t)xSemaphoreGive(((hli_queue_handle_t)semphr)->downstream);
+#else
     return (int32_t)xSemaphoreGive(semphr);
+#endif /* CONFIG_BTDM_CTRL_HLI */
 }
 
 static void *mutex_create_wrapper(void)
@@ -745,6 +888,79 @@ static void queue_delete_wrapper(void *queue)
 #endif
 }
 
+#if CONFIG_BTDM_CTRL_HLI
+static void *queue_create_hlevel_wrapper(uint32_t queue_len, uint32_t item_size)
+{
+    QueueHandle_t downstream_queue = queue_create_wrapper(queue_len, item_size);
+    assert(downstream_queue);
+    hli_queue_handle_t queue = hli_queue_create(queue_len, item_size, downstream_queue);
+    assert(queue);
+    return queue;
+}
+
+static void *customer_queue_create_hlevel_wrapper(uint32_t queue_len, uint32_t item_size)
+{
+    QueueHandle_t downstream_queue = queue_create_wrapper(queue_len, item_size);
+    assert(downstream_queue);
+    hli_queue_handle_t queue = hli_customer_queue_create(queue_len, item_size, downstream_queue);
+    assert(queue);
+    return queue;
+}
+
+static void queue_delete_hlevel_wrapper(void *queue)
+{
+    if (((hli_queue_handle_t)queue)->downstream != NULL) {
+        queue_delete_wrapper(((hli_queue_handle_t)queue)->downstream);
+    }
+    hli_queue_delete(queue);
+}
+
+static int32_t queue_send_hlevel_wrapper(void *queue, void *item, uint32_t block_time_ms)
+{
+    if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) {
+        return (int32_t)xQueueSend(((hli_queue_handle_t)queue)->downstream, item, portMAX_DELAY);
+    } else {
+        return (int32_t)xQueueSend(((hli_queue_handle_t)queue)->downstream, item, block_time_ms / portTICK_PERIOD_MS);
+    }
+}
+
+/**
+ * Queue send from isr
+ * @param  queue The queue which will send to
+ * @param  item  The message which will be send
+ * @param  hptw  need do task yield or not
+ * @return       send success or not
+ *               There is an issue here:  When the queue is full, it may reture true but it send fail to the queue, sometimes.
+ *               But in Bluetooth controller's isr, We don't care about the return value.
+ *               It only required tp send success when the queue is empty all the time.
+ *               So, this function meets the requirement.
+ */
+static int32_t IRAM_ATTR queue_send_from_isr_hlevel_wrapper(void *queue, void *item, void *hptw)
+{
+    UNUSED(hptw);
+    assert(xPortGetCoreID() == CONFIG_BTDM_CTRL_PINNED_TO_CORE);
+    return hli_queue_put(queue, item);
+}
+
+static int32_t queue_recv_hlevel_wrapper(void *queue, void *item, uint32_t block_time_ms)
+{
+    bool ret;
+    if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) {
+        ret = xQueueReceive(((hli_queue_handle_t)queue)->downstream, item, portMAX_DELAY);
+    } else {
+        ret = xQueueReceive(((hli_queue_handle_t)queue)->downstream, item, block_time_ms / portTICK_PERIOD_MS);
+    }
+
+    return (int32_t)ret;
+}
+
+static int32_t IRAM_ATTR queue_recv_from_isr_hlevel_wrapper(void *queue, void *item, void *hptw)
+{
+    return (int32_t)xQueueReceiveFromISR(((hli_queue_handle_t)queue)->downstream, item, hptw);
+}
+
+#else
+
 static int32_t queue_send_wrapper(void *queue, void *item, uint32_t block_time_ms)
 {
     if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) {
@@ -760,18 +976,23 @@ static int32_t IRAM_ATTR queue_send_from_isr_wrapper(void *queue, void *item, vo
 }
 
 static int32_t queue_recv_wrapper(void *queue, void *item, uint32_t block_time_ms)
-{
+ {
+    bool ret;
     if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) {
-        return (int32_t)xQueueReceive(queue, item, portMAX_DELAY);
+        ret = xQueueReceive(queue, item, portMAX_DELAY);
     } else {
-        return (int32_t)xQueueReceive(queue, item, block_time_ms / portTICK_PERIOD_MS);
+        ret = xQueueReceive(queue, item, block_time_ms / portTICK_PERIOD_MS);
     }
-}
+
+    return (int32_t)ret;
+ }
 
 static int32_t IRAM_ATTR queue_recv_from_isr_wrapper(void *queue, void *item, void *hptw)
 {
     return (int32_t)xQueueReceiveFromISR(queue, item, hptw);
 }
+#endif /* CONFIG_BTDM_CTRL_HLI */
+
 
 static int32_t task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id)
 {
@@ -1317,11 +1538,35 @@ esp_err_t esp_bt_mem_release(esp_bt_mode_t mode)
     return ESP_OK;
 }
 
+#if CONFIG_BTDM_CTRL_HLI
+static void hli_queue_setup_cb(void* arg)
+{
+    hli_queue_setup();
+}
+
+static void hli_queue_setup_pinned_to_core(int core_id)
+{
+#if CONFIG_FREERTOS_UNICORE
+    hli_queue_setup_cb(NULL);
+#else /* CONFIG_FREERTOS_UNICORE */
+    if (xPortGetCoreID() == core_id) {
+        hli_queue_setup_cb(NULL);
+    } else {
+        esp_ipc_call(core_id, hli_queue_setup_cb, NULL);
+    }
+#endif /* !CONFIG_FREERTOS_UNICORE */
+}
+#endif /* CONFIG_BTDM_CTRL_HLI */
+
 esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
 {
     esp_err_t err;
     uint32_t btdm_cfg_mask = 0;
 
+#if CONFIG_BTDM_CTRL_HLI
+    hli_queue_setup_pinned_to_core(CONFIG_BTDM_CTRL_PINNED_TO_CORE);
+#endif /* CONFIG_BTDM_CTRL_HLI */
+
     //if all the bt available memory was already released, cannot initialize bluetooth controller
     if (btdm_dram_available_region[0].mode == ESP_BT_MODE_IDLE) {
         return ESP_ERR_INVALID_STATE;
@@ -1394,7 +1639,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
 #if CONFIG_BTDM_CTRL_LPCLK_SEL_EXT_32K_XTAL
     // check whether or not EXT_CRYS is working
     if (rtc_clk_slow_freq_get() == RTC_SLOW_FREQ_32K_XTAL) {
-        btdm_lpclk_sel = BTDM_LPCLK_SEL_XTAL32K; // set default value
+        btdm_lpclk_sel = BTDM_LPCLK_SEL_XTAL32K; // External 32kHz XTAL
 #ifdef CONFIG_PM_ENABLE
         s_btdm_allow_light_sleep = true;
 #endif
@@ -1736,4 +1981,15 @@ esp_err_t esp_ble_scan_dupilcate_list_flush(void)
     return ESP_OK;
 }
 
+/**
+ * This function re-write controller's function,
+ * As coredump can not show paramerters in function which is in a .a file.
+ *
+ * After coredump fixing this issue, just delete this function.
+ */
+void IRAM_ATTR r_assert(const char *condition, int param0, int param1, const char *file, int line)
+{
+    __asm__ __volatile__("ill\n");
+}
+
 #endif /*  CONFIG_BT_ENABLED */

+ 306 - 0
components/bt/controller/esp32/hli_api.c

@@ -0,0 +1,306 @@
+// Copyright 2015-2021 Espressif Systems (Shanghai) CO LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+#include <string.h>
+#include "esp_log.h"
+#include "esp_heap_caps.h"
+#include "xtensa/core-macros.h"
+#include "soc/dport_reg.h"
+#include "hli_api.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/queue.h"
+
+#if CONFIG_BTDM_CTRL_HLI
+#define HLI_MAX_HANDLERS    4
+
+typedef struct {
+    intr_handler_t handler;
+    void* arg;
+    uint32_t intr_reg;
+    uint32_t intr_mask;
+} hli_handler_info_t;
+
+typedef struct {
+#define CUSTOMER_TYPE_REQUEST (0)
+#define CUSTOMER_TYPE_RELEASE (1)
+    struct {
+        uint32_t cb_type;
+        union {
+            int (* request)(uint32_t, uint32_t, uint32_t);
+            int (* release)(uint32_t);
+        } cb;
+    } customer_cb;
+    uint32_t arg0, arg1, arg2;
+} customer_swisr_t;
+
+static void IRAM_ATTR customer_swisr_handle(customer_swisr_t *cus_swisr)
+{
+    if (cus_swisr->customer_cb.cb_type == CUSTOMER_TYPE_REQUEST) {
+        if (cus_swisr->customer_cb.cb.request != NULL) {
+            cus_swisr->customer_cb.cb.request(cus_swisr->arg0, cus_swisr->arg1, cus_swisr->arg2);
+        }
+    } else if(cus_swisr->customer_cb.cb_type == CUSTOMER_TYPE_RELEASE) {
+        if (cus_swisr->customer_cb.cb.release != NULL) {
+            cus_swisr->customer_cb.cb.release(cus_swisr->arg0);
+        }
+    }
+}
+
+static DRAM_ATTR hli_handler_info_t s_hli_handlers[HLI_MAX_HANDLERS];
+
+esp_err_t hli_intr_register(intr_handler_t handler, void* arg, uint32_t intr_reg, uint32_t intr_mask)
+{
+    for (hli_handler_info_t* hip = s_hli_handlers;
+         hip < s_hli_handlers + HLI_MAX_HANDLERS;
+         ++hip) {
+        if (hip->handler == NULL) {
+            hip->arg = arg;
+            hip->intr_reg = intr_reg;
+            hip->intr_mask = intr_mask;
+            hip->handler = handler;     /* set last, indicates the entry as valid */
+            return ESP_OK;
+        }
+    }
+    return ESP_ERR_NO_MEM;
+}
+
+void IRAM_ATTR hli_c_handler(void)
+{
+    bool handled = false;
+    /* Iterate over registered interrupt handlers,
+     * and check if the expected mask is present in the interrupt status register.
+     */
+    for (hli_handler_info_t* hip = s_hli_handlers;
+         hip < s_hli_handlers + HLI_MAX_HANDLERS;
+         ++hip) {
+        if (hip->handler == NULL) {
+            continue;
+        }
+        uint32_t reg = hip->intr_reg;
+        uint32_t val;
+        if (reg == 0) { /* special case for CPU internal interrupts */
+            val = XTHAL_GET_INTERRUPT();
+        } else {
+            /* "reg" might not be in DPORT, but this will work in any case */
+            val = DPORT_REG_READ(reg);
+        }
+        if ((val & hip->intr_mask) != 0) {
+            handled = true;
+            (*hip->handler)(hip->arg);
+        }
+    }
+    if (!handled) {
+        /* no handler found, it is OK in this case. */
+    }
+}
+
+uint32_t IRAM_ATTR hli_intr_disable(void)
+{
+    /* disable level 4 and below */
+    return XTOS_SET_INTLEVEL(XCHAL_DEBUGLEVEL - 2);
+}
+
+void IRAM_ATTR hli_intr_restore(uint32_t state)
+{
+    XTOS_RESTORE_JUST_INTLEVEL(state);
+}
+
+#define HLI_META_QUEUE_SIZE     16
+#define HLI_QUEUE_MAX_ELEM_SIZE 32
+#define HLI_QUEUE_SW_INT_NUM    29
+
+#define HLI_QUEUE_FLAG_SEMAPHORE    BIT(0)
+#define HLI_QUEUE_FLAG_CUSTOMER     BIT(1)
+
+static DRAM_ATTR struct hli_queue_t *s_meta_queue_ptr = NULL;
+static intr_handle_t ret_handle;
+
+static inline char* IRAM_ATTR wrap_ptr(hli_queue_handle_t queue, char *ptr)
+{
+    return (ptr == queue->bufend) ? queue->buf : ptr;
+}
+
+static inline bool IRAM_ATTR queue_empty(hli_queue_handle_t queue)
+{
+    return queue->begin == queue->end;
+}
+
+static inline bool IRAM_ATTR queue_full(hli_queue_handle_t queue)
+{
+    return wrap_ptr(queue, queue->end + queue->elem_size) == queue->begin;
+}
+
+static void IRAM_ATTR queue_isr_handler(void* arg)
+{
+    int do_yield = pdFALSE;
+    XTHAL_SET_INTCLEAR(BIT(HLI_QUEUE_SW_INT_NUM));
+    hli_queue_handle_t queue;
+
+    while (hli_queue_get(s_meta_queue_ptr, &queue)) {
+        static DRAM_ATTR char scratch[HLI_QUEUE_MAX_ELEM_SIZE];
+        while (hli_queue_get(queue, scratch)) {
+            int res = pdPASS;
+            if ((queue->flags & HLI_QUEUE_FLAG_CUSTOMER) != 0) {
+                customer_swisr_handle((customer_swisr_t *)scratch);
+            } else if ((queue->flags & HLI_QUEUE_FLAG_SEMAPHORE) != 0) {
+                res = xSemaphoreGiveFromISR((SemaphoreHandle_t) queue->downstream, &do_yield);
+            } else {
+                res = xQueueSendFromISR(queue->downstream, scratch, &do_yield);
+            }
+            if (res == pdFAIL) {
+                /* Failed to send to downstream queue, it is OK in this case. */
+            }
+        }
+    }
+    if (do_yield) {
+        portYIELD_FROM_ISR();
+    }
+}
+
+/* Notify the level 3 handler that an element is added to the given hli queue.
+ * Do this by placing the queue handle onto s_meta_queue, and raising a SW interrupt.
+ *
+ * This function must be called with HL interrupts disabled!
+ */
+static void IRAM_ATTR queue_signal(hli_queue_handle_t queue)
+{
+    /* See if the queue is already in s_meta_queue, before adding */
+    bool found = false;
+    const hli_queue_handle_t *end = (hli_queue_handle_t*) s_meta_queue_ptr->end;
+    hli_queue_handle_t *item = (hli_queue_handle_t*) s_meta_queue_ptr->begin;
+    for (;item != end; item = (hli_queue_handle_t*) wrap_ptr(s_meta_queue_ptr, (char*) (item + 1))) {
+        if (*item == queue) {
+            found = true;
+            break;
+        }
+    }
+    if (!found) {
+        bool res = hli_queue_put(s_meta_queue_ptr, &queue);
+        if (!res) {
+            esp_rom_printf(DRAM_STR("Fatal error in queue_signal: s_meta_queue full\n"));
+            abort();
+        }
+        XTHAL_SET_INTSET(BIT(HLI_QUEUE_SW_INT_NUM));
+    }
+}
+
+static void queue_init(hli_queue_handle_t queue, size_t buf_size, size_t elem_size, QueueHandle_t downstream)
+{
+    queue->elem_size = elem_size;
+    queue->begin = queue->buf;
+    queue->end = queue->buf;
+    queue->bufend = queue->buf + buf_size;
+    queue->downstream = downstream;
+    queue->flags = 0;
+}
+
+void hli_queue_setup(void)
+{
+    if (s_meta_queue_ptr == NULL) {
+        s_meta_queue_ptr = hli_queue_create(HLI_META_QUEUE_SIZE, sizeof(void*), NULL);
+        ESP_ERROR_CHECK(esp_intr_alloc(ETS_INTERNAL_SW1_INTR_SOURCE, ESP_INTR_FLAG_IRAM, queue_isr_handler, NULL, &ret_handle));
+        xt_ints_on(BIT(HLI_QUEUE_SW_INT_NUM));
+    }
+}
+
+void hli_queue_shutdown(void)
+{
+    if (s_meta_queue_ptr != NULL) {
+        hli_queue_delete(s_meta_queue_ptr);
+        s_meta_queue_ptr = NULL;
+        esp_intr_free(ret_handle);
+        xt_ints_off(BIT(HLI_QUEUE_SW_INT_NUM));
+    }
+}
+
+hli_queue_handle_t hli_queue_create(size_t nelem, size_t elem_size, QueueHandle_t downstream)
+{
+    const size_t buf_elem = nelem + 1;
+    if (elem_size > HLI_QUEUE_MAX_ELEM_SIZE) {
+        return NULL;
+    }
+    size_t buf_size = buf_elem * elem_size;
+    hli_queue_handle_t res = (hli_queue_handle_t) heap_caps_malloc(sizeof(struct hli_queue_t) + buf_size,
+        MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
+    if (res == NULL) {
+        return NULL;
+    }
+    queue_init(res, buf_size, elem_size, downstream);
+    return res;
+}
+
+hli_queue_handle_t hli_customer_queue_create(size_t nelem, size_t elem_size, QueueHandle_t downstream)
+{
+    hli_queue_handle_t res = hli_queue_create(nelem, elem_size, (QueueHandle_t) downstream);
+    if (res == NULL) {
+        return NULL;
+    }
+    res->flags |= HLI_QUEUE_FLAG_CUSTOMER;
+    return res;
+}
+
+hli_queue_handle_t hli_semaphore_create(size_t max_count, SemaphoreHandle_t downstream)
+{
+    const size_t elem_size = 1;
+    hli_queue_handle_t res = hli_queue_create(max_count, elem_size, (QueueHandle_t) downstream);
+    if (res == NULL) {
+        return NULL;
+    }
+    res->flags |= HLI_QUEUE_FLAG_SEMAPHORE;
+    return res;
+}
+
+void hli_queue_delete(hli_queue_handle_t queue)
+{
+    free(queue);
+}
+
+bool IRAM_ATTR hli_queue_get(hli_queue_handle_t queue, void* out)
+{
+    uint32_t int_state = hli_intr_disable();
+    bool res = false;
+    if (!queue_empty(queue)) {
+        memcpy(out, queue->begin, queue->elem_size);
+        queue->begin = wrap_ptr(queue, queue->begin + queue->elem_size);
+        res = true;
+    }
+    hli_intr_restore(int_state);
+    return res;
+}
+
+bool IRAM_ATTR hli_queue_put(hli_queue_handle_t queue, const void* data)
+{
+    uint32_t int_state = hli_intr_disable();
+    bool res = false;
+    bool was_empty = queue_empty(queue);
+    if (!queue_full(queue)) {
+        memcpy(queue->end, data, queue->elem_size);
+        queue->end = wrap_ptr(queue, queue->end + queue->elem_size);
+        if (was_empty && queue != s_meta_queue_ptr) {
+            queue_signal(queue);
+        }
+        res = true;
+    }
+    hli_intr_restore(int_state);
+    return res;
+}
+
+bool IRAM_ATTR hli_semaphore_give(hli_queue_handle_t queue)
+{
+    uint8_t data = 0;
+    return hli_queue_put(queue, &data);
+}
+
+#endif /* CONFIG_BTDM_CTRL_HLI */

+ 176 - 0
components/bt/controller/esp32/hli_api.h

@@ -0,0 +1,176 @@
+// Copyright 2015-2021 Espressif Systems (Shanghai) CO LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+#pragma once
+
+#include <stdint.h>
+#include "esp_err.h"
+#include "esp_intr_alloc.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/queue.h"
+#include "freertos/semphr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if CONFIG_BTDM_CTRL_HLI
+
+/*** Queues ***/
+
+struct hli_queue_t
+{
+    size_t elem_size;
+    char* begin;
+    char* end;
+    const char* bufend;
+    QueueHandle_t downstream;
+    int flags;
+    char buf[0];
+};
+
+/**
+ * @brief Register a high level interrupt function
+ *
+ * @param handler  interrupt handler function
+ * @param arg      argument to pass to the interrupt handler
+ * @param intr_reg   address of the peripheral register containing the interrupt status,
+ *                   or value 0 to get the status from CPU INTERRUPT register
+ * @param intr_mask  mask of the interrupt, in the interrupt status register
+ * @return
+ *      - ESP_OK on success
+ *      - ESP_ERR_NO_MEM if too many handlers are registered
+ */
+esp_err_t hli_intr_register(intr_handler_t handler, void* arg, uint32_t intr_reg, uint32_t intr_mask);
+
+/**
+ * @brief Mask all interrupts (including high level ones) on the current CPU
+ *
+ * @return uint32_t interrupt status, pass it to hli_intr_restore
+ */
+uint32_t hli_intr_disable(void);
+
+/**
+ * @brief Re-enable interrupts
+ *
+ * @param state value returned by hli_intr_disable
+ */
+void hli_intr_restore(uint32_t state);
+
+/**
+ * @brief Type of a hli queue
+ */
+typedef struct hli_queue_t* hli_queue_handle_t;
+
+/**
+ * @brief Initialize hli_queue module. Must be called once before using hli queue APIs.
+ */
+void hli_queue_setup(void);
+
+/**
+ * @brief Shutdown hli_queue module.
+ */
+void hli_queue_shutdown(void);
+
+/**
+ * @brief Create a hli queue, wrapping a FreeRTOS queue
+ *
+ * This queue can be used from high level interrupts,
+ * but **ONLY ON THE CPU WHERE hli_queue_setup WAS CALLED**. Values sent to this
+ * queue are automatically forwarded to "downstream" FreeRTOS queue using a level 3
+ * software interrupt.
+ *
+ * @param nelem  number of elements in the queue
+ * @param elem_size  size of one element; must match element size of a downstream queue
+ * @param downstream  FreeRTOS queue to send the values to
+ * @return hli_queue_handle_t  handle of the created queue, or NULL on failure
+ */
+hli_queue_handle_t hli_queue_create(size_t nelem, size_t elem_size, QueueHandle_t downstream);
+
+/**
+ * @brief Create a customer hli queue, wrapping a FreeRTOS queue
+ *
+ * This queue can be used from high level interrupts,
+ * but **ONLY ON THE CPU WHERE hli_queue_setup WAS CALLED**. Values sent to this
+ * queue are automatically forwarded to "downstream" FreeRTOS queue using a level 3
+ * software interrupt.
+ *
+ * @param nelem  number of elements in the queue
+ * @param elem_size  size of one element; must match element size of a downstream queue
+ * @param downstream  FreeRTOS queue to send the values to
+ * @return hli_queue_handle_t  handle of the created queue, or NULL on failure
+ */
+hli_queue_handle_t hli_customer_queue_create(size_t nelem, size_t elem_size, QueueHandle_t downstream);
+
+/**
+ * @brief Create a hli queue, wrapping a FreeRTOS semaphore
+ *
+ * See notes on hli_queue_create.
+ *
+ * @param max_count  maximum semaphore count
+ * @param downstream  FreeRTOS semaphore to forward the calls to
+ * @return hli_queue_handle_t  handle of the created queue, or NULL on failure
+ */
+hli_queue_handle_t hli_semaphore_create(size_t max_count, SemaphoreHandle_t downstream);
+
+/**
+ * @brief Delete a hli queue
+ *
+ * Make sure noone is using the queue before deleting it.
+ *
+ * @param queue  handle returned by hli_queue_create or hli_semaphore_create
+ */
+void hli_queue_delete(hli_queue_handle_t queue);
+
+/**
+ * @brief Get one element from a hli queue
+ *
+ * Usually not used, values get sent to a downstream FreeRTOS queue automatically.
+ * However if downstream queue is NULL, this API can be used to get values from a hli queue.
+ *
+ * @param queue  handle of a queue
+ * @param out  pointer where to store the element
+ * @return true if the element was successfully read from the queue
+ */
+bool hli_queue_get(hli_queue_handle_t queue, void* out);
+
+/**
+ * @brief Put one element into a hli queue
+ *
+ * This puts copies an element into the queue and raises a software interrupt (level 3).
+ * In the interrupt, the value is copied to a FreeRTOS "downstream" queue.
+ *
+ * Note that if the value does not fit into a downstream queue, no error is returned,
+ * and the value is lost.
+ *
+ * @param queue handle of a queue
+ * @param data  pointer to the element to be sent
+ * @return true if data was placed into the hli queue successfully
+ */
+bool hli_queue_put(hli_queue_handle_t queue, const void* data);
+
+/**
+ * @brief "Give" a semaphore wrapped by a hli queue
+ *
+ * @param queue  handle returned by hli_semaphore_create
+ * @return true  if the event was sent to a hli queue successfully
+ */
+bool hli_semaphore_give(hli_queue_handle_t queue);
+
+#endif /* CONFIG_BTDM_CTRL_HLI */
+
+#ifdef __cplusplus
+}
+#endif

+ 275 - 0
components/bt/controller/esp32/hli_vectors.S

@@ -0,0 +1,275 @@
+// Copyright 2015-2021 Espressif Systems (Shanghai) CO LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+#include <xtensa/coreasm.h>
+#include <xtensa/corebits.h>
+#include <xtensa/config/system.h>
+#include "freertos/xtensa_context.h"
+#include "sdkconfig.h"
+#include "soc/soc.h"
+
+#if CONFIG_BTDM_CTRL_HLI
+
+/* Interrupt stack size, for C code.
+ * TODO: reduce and make configurable.
+ */
+#define L4_INTR_STACK_SIZE  4096
+
+/* Save area for the CPU state:
+ * - 64 words for the general purpose registers
+ * - 7 words for some of the special registers:
+ *   - WINDOWBASE, WINDOWSTART — only WINDOWSTART is truly needed
+ *   - SAR, LBEG, LEND, LCOUNT — since the C code might use these
+ *   - EPC1 — since the C code might cause window overflow exceptions
+ * This is not laid out as standard exception frame structure
+ * for simplicity of the save/restore code.
+ */
+#define REG_FILE_SIZE         (64 * 4)
+#define SPECREG_OFFSET        REG_FILE_SIZE
+#define SPECREG_SIZE          (7 * 4)
+#define REG_SAVE_AREA_SIZE    (SPECREG_OFFSET + SPECREG_SIZE)
+
+    .data
+_l4_intr_stack:
+    .space      L4_INTR_STACK_SIZE
+_l4_save_ctx:
+    .space      REG_SAVE_AREA_SIZE
+
+    .section .iram1,"ax"
+    .global     xt_highint4
+    .type       xt_highint4,@function
+    .align      4
+
+xt_highint4:
+
+#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
+    /*
+    Here, Timer2 is used to count a little time(50us).
+    The subsequent dram0 write operation is blocked due to live lock, which will
+    cause timer2 to timeout and trigger a level 5 interrupt.
+    */
+    rsr.ccount  a0
+    addmi   a0, a0, (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ*50)
+    wsr     a0, CCOMPARE2
+
+    /* Enable Timer 2 interrupt */
+    rsr     a0, INTENABLE
+    extui   a0, a0, 16, 1
+    bnez    a0, 1f
+    movi    a0, 0
+    xsr     a0, INTENABLE     /* disable all interrupts */
+    /* And a0 with (1 << 16) for Timer 2 interrupt mask */
+    addmi   a0, a0, (1<<14)
+    addmi   a0, a0, (1<<14)
+    addmi   a0, a0, (1<<14)
+    addmi   a0, a0, (1<<14)
+    wsr     a0, INTENABLE    /* Enable Timer 2 */
+1:
+#endif
+
+    movi    a0, _l4_save_ctx
+    /* save 4 lower registers */
+    s32i    a1, a0, 4
+    s32i    a2, a0, 8
+    s32i    a3, a0, 12
+    rsr     a2, EXCSAVE_4  /* holds the value of a0 */
+    s32i    a2, a0, 0
+
+    /* Save special registers */
+    addi    a0, a0, SPECREG_OFFSET
+    rsr     a2, WINDOWBASE
+    s32i    a2, a0, 0
+    rsr     a2, WINDOWSTART
+    s32i    a2, a0, 4
+    rsr     a2, SAR
+    s32i    a2, a0, 8
+    rsr     a2, LBEG
+    s32i    a2, a0, 12
+    rsr     a2, LEND
+    s32i    a2, a0, 16
+    rsr     a2, LCOUNT
+    s32i    a2, a0, 20
+    rsr     a2, EPC1
+    s32i    a2, a0, 24
+
+#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
+    movi    a0, 0
+    xsr     a0, INTENABLE     /* disable all interrupts */
+    movi    a2, ~(1<<16)
+    and     a0, a2, a0
+    wsr     a0, INTENABLE
+#endif
+
+    /* disable exception mode, window overflow */
+    movi    a0, PS_INTLEVEL(5) | PS_EXCM
+    wsr     a0, PS
+    rsync
+
+    /* Save the remaining physical registers.
+     * 4 registers are already saved, which leaves 60 registers to save.
+     * (FIXME: consider the case when the CPU is configured with physical 32 registers)
+     * These 60 registers are saved in 5 iterations, 12 registers at a time.
+     */
+    movi    a1, 5
+    movi    a3, _l4_save_ctx + 4 * 4
+
+    /* This is repeated 5 times, each time the window is shifted by 12 registers.
+     * We come here with a1 = downcounter, a3 = save pointer, a2 and a0 unused.
+     */
+1:
+    s32i    a4, a3, 0
+    s32i    a5, a3, 4
+    s32i    a6, a3, 8
+    s32i    a7, a3, 12
+    s32i    a8, a3, 16
+    s32i    a9, a3, 20
+    s32i    a10, a3, 24
+    s32i    a11, a3, 28
+    s32i    a12, a3, 32
+    s32i    a13, a3, 36
+    s32i    a14, a3, 40
+    s32i    a15, a3, 44
+
+    /* We are about to rotate the window, so that a12-a15 will become the new a0-a3.
+     * Copy a0-a3 to a12-15 to still have access to these values.
+     * At the same time we can decrement the counter and adjust the save area pointer
+     */
+
+    /* a0 is constant (_l4_save_ctx), no need to copy */
+    addi    a13, a1, -1  /* copy and decrement the downcounter */
+    /* a2 is scratch so no need to copy */
+    addi    a15, a3, 48  /* copy and adjust the save area pointer */
+    beqz    a13, 2f      /* have saved all registers ? */
+    rotw    3            /* rotate the window and go back */
+    j       1b
+
+    /* the loop is complete */
+2:
+    rotw 4      /* this brings us back to the original window */
+    /* a0 still points to _l4_save_ctx */
+
+    /* Can clear WINDOWSTART now, all registers are saved */
+    rsr     a2, WINDOWBASE
+    /* WINDOWSTART = (1 << WINDOWBASE) */
+    movi    a3, 1
+    ssl     a2
+    sll     a3, a3
+    wsr     a3, WINDOWSTART
+
+_highint4_stack_switch:
+    movi    a0, 0
+    movi    sp, _l4_intr_stack + L4_INTR_STACK_SIZE - 16
+    s32e    a0, sp, -12         /* For GDB: set null SP */
+    s32e    a0, sp, -16         /* For GDB: set null PC */
+    movi    a0, _highint4_stack_switch     /* For GDB: cosmetics, for the frame where stack switch happened */
+
+    /* Set up PS for C, disable all interrupts except NMI and debug, and clear EXCM. */
+    movi    a6, PS_INTLEVEL(4) | PS_UM | PS_WOE
+    wsr     a6, PS
+    rsync
+
+    /* Call C handler */
+    mov     a6, sp
+    call4   hli_c_handler
+
+    l32e    sp, sp, -12                     /* switch back to the original stack */
+
+    /* Done with C handler; re-enable exception mode, disabling window overflow */
+    movi    a2, PS_INTLEVEL(5) | PS_EXCM    /* TOCHECK */
+    wsr     a2, PS
+    rsync
+
+    /* Restore the special registers.
+     * WINDOWSTART will be restored near the end.
+     */
+    movi    a0, _l4_save_ctx + SPECREG_OFFSET
+    l32i    a2, a0, 8
+    wsr     a2, SAR
+    l32i    a2, a0, 12
+    wsr     a2, LBEG
+    l32i    a2, a0, 16
+    wsr     a2, LEND
+    l32i    a2, a0, 20
+    wsr     a2, LCOUNT
+    l32i    a2, a0, 24
+    wsr     a2, EPC1
+
+    /* Restoring the physical registers.
+     * This is the reverse to the saving process above.
+     */
+
+    /* Rotate back to the final window, then start loading 12 registers at a time,
+     * in 5 iterations.
+     * Again, a1 is the downcounter and a3 is the save area pointer.
+     * After each rotation, a1 and a3 are copied from a13 and a15.
+     * To simplify the loop, we put the initial values into a13 and a15.
+     */
+    rotw     -4
+    movi    a15, _l4_save_ctx + 64 * 4  /* point to the end of the save area */
+    movi    a13, 5
+
+1:
+    /* Copy a1 and a3 from their previous location,
+     * at the same time decrementing and adjusting the save area pointer.
+     */
+    addi    a1, a13, -1
+    addi    a3, a15, -48
+
+    /* Load 12 registers */
+    l32i    a4, a3, 0
+    l32i    a5, a3, 4
+    l32i    a6, a3, 8
+    l32i    a7, a3, 12
+    l32i    a8, a3, 16
+    l32i    a9, a3, 20
+    l32i    a10, a3, 24
+    l32i    a11, a3, 28                                /* ensure PS and EPC written */
+    l32i    a12, a3, 32
+    l32i    a13, a3, 36
+    l32i    a14, a3, 40
+    l32i    a15, a3, 44
+
+    /* Done with the loop? */
+    beqz    a1, 2f
+    /* If no, rotate the window and repeat */
+    rotw    -3
+    j       1b
+
+2:
+    /* Done with the loop. Only 4 registers (a0-a3 in the original window) remain
+     * to be restored. Also need to restore WINDOWSTART, since all the general
+     * registers are now in place.
+     */
+    movi    a0, _l4_save_ctx
+
+    l32i    a2, a0, SPECREG_OFFSET + 4
+    wsr     a2, WINDOWSTART
+
+    l32i    a1, a0, 4
+    l32i    a2, a0, 8
+    l32i    a3, a0, 12
+    rsr     a0, EXCSAVE_4  /* holds the value of a0 before the interrupt handler */
+
+    /* Return from the interrupt, restoring PS from EPS_4 */
+    rfi     4
+
+#endif /* CONFIG_BTDM_CTRL_HLI */
+
+/* The linker has no reason to link in this file; all symbols it exports are already defined
+   (weakly!) in the default int handler. Define a symbol here so we can use it to have the
+   linker inspect this anyway. */
+
+    .global ld_include_hli_vectors_bt
+ld_include_hli_vectors_bt:

+ 2 - 1
components/bt/controller/esp32c3/Kconfig.in

@@ -359,7 +359,8 @@ menu "MODEM SLEEP Options"
             bool "Internal 150kHz RC oscillator"
             depends on ESP32C3_RTC_CLK_SRC_INT_RC
             help
-                Internal 150kHz RC oscillator.
+                Internal 150kHz RC oscillator. The accuracy of this clock is a lot larger than 500ppm which is required
+                in Bluetooth communication, so don't select this option in scenarios such as BLE connection state.
 
 
     endchoice

+ 11 - 13
components/bt/controller/esp32c3/bt.c

@@ -992,7 +992,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
 
         // configure and initialize resources
         s_lp_cntl.enable = (cfg->sleep_mode == ESP_BT_SLEEP_MODE_1) ? 1 : 0;
-        s_lp_cntl.no_light_sleep = 0;
+        s_lp_cntl.no_light_sleep = 1;
 
         if (s_lp_cntl.enable) {
 #if (CONFIG_MAC_BB_PD)
@@ -1029,31 +1029,29 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
         btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT;
         btdm_lpcycle_us = 2 << (btdm_lpcycle_us_frac);
 
-        // // set default bluetooth sleep clock source
-        // s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL;
+        // set default bluetooth sleep clock source
+        s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL;  // set default value
 #if CONFIG_BT_CTRL_LPCLK_SEL_EXT_32K_XTAL
         // check whether or not EXT_CRYS is working
         if (rtc_clk_slow_freq_get() == RTC_SLOW_FREQ_32K_XTAL) {
-            s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL32K; // set default value
-// #ifdef CONFIG_PM_ENABLE
-//             s_btdm_allow_light_sleep = true;
-// #endif
+            s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL32K; // External 32 kHz XTAL
+            s_lp_cntl.no_light_sleep = 0;
         } else {
             ESP_LOGW(BTDM_LOG_TAG, "32.768kHz XTAL not detected, fall back to main XTAL as Bluetooth sleep clock\n"
                  "light sleep mode will not be able to apply when bluetooth is enabled");
-            s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value
         }
 #elif (CONFIG_BT_CTRL_LPCLK_SEL_RTC_SLOW)
         // check whether or not EXT_CRYS is working
         if (rtc_clk_slow_freq_get() == RTC_SLOW_FREQ_RTC) {
-            s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_RTC_SLOW; // set default value
+            s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_RTC_SLOW; // Internal 150 kHz RC oscillator
+            ESP_LOGW(BTDM_LOG_TAG, "Internal 150kHz RC osciallator. The accuracy of this clock is a lot larger than 500ppm which is "
+                 "required in Bluetooth communication, so don't select this option in scenarios such as BLE connection state.");
         } else {
-            ESP_LOGW(BTDM_LOG_TAG, "Internal 150kHz RC oscillator not detected, fall back to main XTAL as Bluetooth sleep clock\n"
-                 "light sleep mode will not be able to apply when bluetooth is enabled");
-            s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value
+            ESP_LOGW(BT_LOG_TAG, "Internal 150kHz RC oscillator not detected.");
+            assert(0);
         }
 #else
-        s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value
+        s_lp_cntl.no_light_sleep = 1;
 #endif
 
         bool select_src_ret __attribute__((unused));

+ 0 - 0
docs/extensions/__init__.py → components/bt/controller/esp32h2/Kconfig.in


+ 0 - 0
docs/idf_extensions/__init__.py → components/bt/controller/esp32s2/Kconfig.in


+ 3 - 2
components/bt/controller/esp32s3/Kconfig.in

@@ -373,10 +373,11 @@ menu "MODEM SLEEP Options"
                 modem sleep to be used with both DFS and light sleep.
 
         config BT_CTRL_LPCLK_SEL_RTC_SLOW
-            bool "Internal 90kHz RC oscillator"
+            bool "Internal 150kHz RC oscillator"
             depends on ESP32S3_RTC_CLK_SRC_INT_RC
             help
-                Internal 90kHz RC oscillator.
+                Internal 150kHz RC oscillator. The accuracy of this clock is a lot larger than 500ppm which is required
+                in Bluetooth communication, so don't select this option in scenarios such as BLE connection state.
 
 
     endchoice

+ 11 - 13
components/bt/controller/esp32s3/bt.c

@@ -972,7 +972,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
 
         // configure and initialize resources
         s_lp_cntl.enable = (cfg->sleep_mode == ESP_BT_SLEEP_MODE_1) ? 1 : 0;
-        s_lp_cntl.no_light_sleep = 0;
+        s_lp_cntl.no_light_sleep = 1;
 
         if (s_lp_cntl.enable) {
 #if (CONFIG_MAC_BB_PD)
@@ -1009,31 +1009,29 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
         btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT;
         btdm_lpcycle_us = 2 << (btdm_lpcycle_us_frac);
 
-        // // set default bluetooth sleep clock source
-        // s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL;
+        // set default bluetooth sleep clock source
+        s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value
 #if CONFIG_BT_CTRL_LPCLK_SEL_EXT_32K_XTAL
         // check whether or not EXT_CRYS is working
         if (rtc_clk_slow_freq_get() == RTC_SLOW_FREQ_32K_XTAL) {
-            s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL32K; // set default value
-// #ifdef CONFIG_PM_ENABLE
-//             s_btdm_allow_light_sleep = true;
-// #endif
+            s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL32K; // External 32 kHz XTAL
+            s_lp_cntl.no_light_sleep = 0;
         } else {
             ESP_LOGW(BT_LOG_TAG, "32.768kHz XTAL not detected, fall back to main XTAL as Bluetooth sleep clock\n"
                  "light sleep mode will not be able to apply when bluetooth is enabled");
-            s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value
         }
 #elif (CONFIG_BT_CTRL_LPCLK_SEL_RTC_SLOW)
         // check whether or not EXT_CRYS is working
         if (rtc_clk_slow_freq_get() == RTC_SLOW_FREQ_RTC) {
-            s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_RTC_SLOW; // set default value
+            s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_RTC_SLOW; // Internal 150 kHz RC oscillator
+            ESP_LOGW(BTDM_LOG_TAG, "Internal 150kHz RC osciallator. The accuracy of this clock is a lot larger than 500ppm which is "
+                 "required in Bluetooth communication, so don't select this option in scenarios such as BLE connection state.");
         } else {
-            ESP_LOGW(BT_LOG_TAG, "Internal 90kHz RC oscillator not detected, fall back to main XTAL as Bluetooth sleep clock\n"
-                 "light sleep mode will not be able to apply when bluetooth is enabled");
-            s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value
+            ESP_LOGW(BT_LOG_TAG, "Internal 150kHz RC oscillator not detected.");
+            assert(0);
         }
 #else
-        s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value
+        s_lp_cntl.no_light_sleep = 1;
 #endif
 
         bool select_src_ret __attribute__((unused));

+ 1 - 1
components/bt/controller/lib_esp32

@@ -1 +1 @@
-Subproject commit b97b2abd1a98ab887fb4cdc0553fabcba95aedaf
+Subproject commit fe0a3d00f11dbf9d219f2a291e3cab7419e5cac1

+ 1 - 1
components/bt/controller/lib_esp32c3_family

@@ -1 +1 @@
-Subproject commit b223604efd557d0a5314afb3b751229df424d244
+Subproject commit 32f15e826a102d2d64e612620468122ea2234a2e

+ 4 - 4
components/bt/esp_ble_mesh/Kconfig.in

@@ -9,10 +9,10 @@ if BLE_MESH
     config BLE_MESH_USE_DUPLICATE_SCAN
         bool "Support Duplicate Scan in BLE Mesh"
         depends on BT_BLUEDROID_ENABLED
-        select BTDM_BLE_SCAN_DUPL if BT_CTRL_ESP32
-        select BTDM_BLE_MESH_SCAN_DUPL_EN if BT_CTRL_ESP32
-        select BT_CTRL_BLE_SCAN_DUPL if BT_CTRL_ESP32C3
-        select BT_CTRL_BLE_MESH_SCAN_DUPL_EN if BT_CTRL_ESP32C3
+        select BTDM_BLE_SCAN_DUPL if IDF_TARGET_ESP32
+        select BTDM_BLE_MESH_SCAN_DUPL_EN if IDF_TARGET_ESP32
+        select BT_CTRL_BLE_SCAN_DUPL if IDF_TARGET_ESP32C3
+        select BT_CTRL_BLE_MESH_SCAN_DUPL_EN if IDF_TARGET_ESP32C3
         default y
         help
             Enable this option to allow using specific duplicate scan filter

+ 18 - 0
components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_provisioning_api.h

@@ -69,6 +69,12 @@ esp_err_t esp_ble_mesh_node_prov_disable(esp_ble_mesh_prov_bearer_t bearers);
 /**
  * @brief        Unprovisioned device set own oob public key & private key pair.
  *
+ * @note         In order to avoid suffering brute-forcing attack (CVE-2020-26559).
+ *               The Bluetooth SIG recommends that potentially vulnerable mesh provisioners
+ *               use an out-of-band mechanism to exchange the public keys.
+ *               So as an unprovisioned device, it should use this function to input
+ *               the Public Key exchanged through the out-of-band mechanism.
+ *
  * @param[in]    pub_key_x:   Unprovisioned device's Public Key X
  * @param[in]    pub_key_y:   Unprovisioned device's Public Key Y
  * @param[in]    private_key: Unprovisioned device's Private Key
@@ -121,6 +127,10 @@ esp_err_t esp_ble_mesh_set_unprovisioned_device_name(const char *name);
 /**
  * @brief        Provisioner inputs unprovisioned device's oob public key.
  *
+ * @note         In order to avoid suffering brute-forcing attack (CVE-2020-26559).
+ *               The Bluetooth SIG recommends that potentially vulnerable mesh provisioners
+ *               use an out-of-band mechanism to exchange the public keys.
+ *
  * @param[in]    link_idx:   The provisioning link index
  * @param[in]    pub_key_x:  Unprovisioned device's Public Key X
  * @param[in]    pub_key_y:  Unprovisioned device's Public Key Y
@@ -329,6 +339,14 @@ esp_err_t esp_ble_mesh_provisioner_set_prov_data_info(esp_ble_mesh_prov_data_inf
  *                A large entropy helps ensure that a brute-force of the AuthValue, even a static
  *                AuthValue, cannot normally be completed in a reasonable time (CVE-2020-26557).
  *
+ *                AuthValues selected using a cryptographically secure random or pseudorandom number
+ *                generator and having the maximum permitted entropy (128-bits) will be most difficult
+ *                to brute-force. AuthValues with reduced entropy or generated in a predictable manner
+ *                will not grant the same level of protection against this vulnerability. Selecting a
+ *                new AuthValue with each provisioning attempt can also make it more difficult to launch
+ *                a brute-force attack by requiring the attacker to restart the search with each
+ *                provisioning attempt (CVE-2020-26556).
+ *
  * @param[in]     value:  Pointer to the static oob value.
  * @param[in]     length: Length of the static oob value.
  *

+ 12 - 2
components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h

@@ -573,8 +573,10 @@ typedef struct {
     esp_ble_mesh_prov_oob_info_t oob_info;
 
     /* NOTE: In order to avoid suffering brute-forcing attack (CVE-2020-26559).
-     * The Bluetooth SIG recommends that potentially vulnerable mesh node
+     * The Bluetooth SIG recommends that potentially vulnerable mesh provisioners
      * support an out-of-band mechanism to exchange the public keys.
+     * So as an unprovisioned device, it should enable this flag to support
+     * using an out-of-band mechanism to exchange Public Key.
      */
     /** Flag indicates whether unprovisioned devices support OOB public key */
     bool oob_pub_key;
@@ -629,7 +631,7 @@ typedef struct {
     /** Provisioning Algorithm for the Provisioner */
     uint8_t        prov_algorithm;
 
-    /* NOTE: In order to avoid suffering brute-forcing attack(CVE-2020-26559).
+    /* NOTE: In order to avoid suffering brute-forcing attack (CVE-2020-26559).
      * The Bluetooth SIG recommends that potentially vulnerable mesh provisioners
      * use an out-of-band mechanism to exchange the public keys.
      */
@@ -643,6 +645,14 @@ typedef struct {
      * selected AuthValue using all of the available bits, where permitted by the
      * implementation. A large entropy helps ensure that a brute-force of the AuthValue,
      * even a static AuthValue, cannot normally be completed in a reasonable time (CVE-2020-26557).
+     *
+     * AuthValues selected using a cryptographically secure random or pseudorandom number
+     * generator and having the maximum permitted entropy (128-bits) will be most difficult
+     * to brute-force. AuthValues with reduced entropy or generated in a predictable manner
+     * will not grant the same level of protection against this vulnerability. Selecting a
+     * new AuthValue with each provisioning attempt can also make it more difficult to launch
+     * a brute-force attack by requiring the attacker to restart the search with each
+     * provisioning attempt (CVE-2020-26556).
      */
     /** Provisioner static oob value */
     uint8_t        *prov_static_oob_val;

+ 23 - 12
components/bt/esp_ble_mesh/mesh_core/provisioner_prov.c

@@ -1930,6 +1930,19 @@ static int prov_auth(const uint8_t idx, uint8_t method, uint8_t action, uint8_t
         /* Provisioner ouput number/string and wait for device's Provisioning Input Complete PDU */
         link[idx].expect = PROV_INPUT_COMPLETE;
 
+        /* NOTE: The Bluetooth SIG recommends that mesh implementations enforce a randomly
+         * selected AuthValue using all of the available bits, where permitted by the
+         * implementation. A large entropy helps ensure that a brute-force of the AuthValue,
+         * even a static AuthValue, cannot normally be completed in a reasonable time (CVE-2020-26557).
+         *
+         * AuthValues selected using a cryptographically secure random or pseudorandom number
+         * generator and having the maximum permitted entropy (128-bits) will be most difficult
+         * to brute-force. AuthValues with reduced entropy or generated in a predictable manner
+         * will not grant the same level of protection against this vulnerability. Selecting a
+         * new AuthValue with each provisioning attempt can also make it more difficult to launch
+         * a brute-force attack by requiring the attacker to restart the search with each
+         * provisioning attempt (CVE-2020-26556).
+         */
         if (input == BLE_MESH_ENTER_STRING) {
             unsigned char str[9] = {'\0'};
             uint8_t j = 0U;
@@ -2312,12 +2325,11 @@ static void prov_confirm(const uint8_t idx, const uint8_t *data)
 
     BT_DBG("Remote Confirm: %s", bt_hex(data, 16));
 
-    /* NOTE: The Bluetooth SIG recommends that potentially vulnerable mesh
-     * provisioners restrict the authentication procedure and not accept
-     * provisioning random and provisioning confirmation numbers from a remote
-     * peer that are the same as those selected by the local device (CVE-2020-26556
-     * & CVE-2020-26560).
-     * */
+    /* NOTE: The Bluetooth SIG recommends that potentially vulnerable mesh provisioners
+     * restrict the authentication procedure and not accept provisioning random and
+     * provisioning confirmation numbers from a remote peer that are the same as those
+     * selected by the local device (CVE-2020-26560).
+     */
     if (!memcmp(data, link[idx].local_conf, 16)) {
         BT_ERR("Confirmation value is identical to ours, rejecting.");
         close_link(idx, CLOSE_REASON_FAILED);
@@ -2534,12 +2546,11 @@ static void prov_random(const uint8_t idx, const uint8_t *data)
 
     BT_DBG("Remote Random: %s", bt_hex(data, 16));
 
-    /* NOTE: The Bluetooth SIG recommends that potentially vulnerable mesh
-     * provisioners restrict the authentication procedure and not accept
-     * provisioning random and provisioning confirmation numbers from a remote
-     * peer that are the same as those selected by the local device (CVE-2020-26556
-     * & CVE-2020-26560).
-     * */
+    /* NOTE: The Bluetooth SIG recommends that potentially vulnerable mesh provisioners
+     * restrict the authentication procedure and not accept provisioning random and
+     * provisioning confirmation numbers from a remote peer that are the same as those
+     * selected by the local device (CVE-2020-26560).
+     */
     if (!memcmp(data, link[idx].rand, 16)) {
         BT_ERR("Random value is identical to ours, rejecting.");
         goto fail;

+ 17 - 8
components/bt/host/bluedroid/Kconfig.in

@@ -42,7 +42,7 @@ config BT_BLUEDROID_MEM_DEBUG
 
 config BT_CLASSIC_ENABLED
     bool "Classic Bluetooth"
-    depends on BT_BLUEDROID_ENABLED && BT_CTRL_ESP32
+    depends on BT_BLUEDROID_ENABLED && IDF_TARGET_ESP32
     default n
     help
         For now this option needs "SMP_ENABLE" to be set to yes
@@ -99,13 +99,27 @@ config BT_HFP_WBS_ENABLE
         This enables Wide Band Speech. Should disable it when SCO data path is PCM.
         Otherwise there will be no data transmited via GPIOs.
 
-config BT_HID_HOST_ENABLED
-    bool "Classic BT HID Host"
+config BT_HID_ENABLED
+    bool "Classic BT HID"
     depends on BT_CLASSIC_ENABLED
     default n
     help
         This enables the BT HID Host
 
+choice BT_HID_ROLE
+    prompt "Profile Role configuration"
+    depends on BT_HID_ENABLED
+    config BT_HID_HOST_ENABLED
+        bool "Classic BT HID Host"
+        help
+            This enables the BT HID Host
+
+    config BT_HID_DEVICE_ENABLED
+        bool "Classic BT HID Device"
+        help
+            This enables the BT HID Device
+endchoice
+
 config BT_SSP_ENABLED
     bool "Secure Simple Pairing"
     depends on BT_CLASSIC_ENABLED
@@ -1056,8 +1070,3 @@ config BT_BLE_42_FEATURES_SUPPORTED
     default n
     help
         This enables BLE 4.2 features.
-
-config BT_RESERVE_DRAM
-    hex
-    default 0xdb5c if BT_ENABLED
-    default 0

+ 176 - 0
components/bt/host/bluedroid/api/esp_hidd_api.c

@@ -0,0 +1,176 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+// Copyright 2019      Blake Felt
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <string.h>
+#include "esp_err.h"
+#include "esp_bt_main.h"
+#include "btc/btc_manage.h"
+#include "btc_hd.h"
+#include "esp_hidd_api.h"
+
+#if (defined BTC_HD_INCLUDED && BTC_HD_INCLUDED == TRUE)
+
+esp_err_t esp_bt_hid_device_register_callback(esp_hd_cb_t *callback)
+{
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+
+    if (callback == NULL) {
+        return ESP_FAIL;
+    }
+
+    btc_profile_cb_set(BTC_PID_HD, callback);
+    return ESP_OK;
+}
+
+esp_err_t esp_bt_hid_device_init(void)
+{
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+
+    btc_msg_t msg;
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HD;
+    msg.act = BTC_HD_INIT_EVT;
+
+    /* Switch to BTC context */
+    bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hid_device_deinit(void)
+{
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+
+    btc_msg_t msg;
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HD;
+    msg.act = BTC_HD_DEINIT_EVT;
+
+    bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hid_device_register_app(esp_hidd_app_param_t* app_param, esp_hidd_qos_param_t* in_qos, esp_hidd_qos_param_t* out_qos)
+{
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+
+    btc_msg_t msg;
+    btc_hidd_args_t args;
+    memset(&args, 0, sizeof(btc_hidd_args_t));
+    args.register_app.app_param = app_param;
+    args.register_app.in_qos = in_qos;
+    args.register_app.out_qos = out_qos;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HD;
+    msg.act = BTC_HD_REGISTER_APP_EVT;
+
+    bt_status_t stat = btc_transfer_context(&msg, &args, sizeof(btc_hidd_args_t), NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hid_device_unregister_app(void)
+{
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+
+    btc_msg_t msg;
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HD;
+    msg.act = BTC_HD_UNREGISTER_APP_EVT;
+
+    bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hid_device_connect(esp_bd_addr_t bd_addr)
+{
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+
+    btc_msg_t msg;
+    btc_hidd_args_t args;
+    memset(&args, 0, sizeof(btc_hidd_args_t));
+    memcpy(args.connect.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HD;
+    msg.act = BTC_HD_CONNECT_EVT;
+
+    bt_status_t stat = btc_transfer_context(&msg, &args, sizeof(btc_hidd_args_t), NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hid_device_disconnect(void)
+{
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+
+    btc_msg_t msg;
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HD;
+    msg.act = BTC_HD_DISCONNECT_EVT;
+
+    bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hid_device_send_report(esp_hidd_report_type_t type, uint8_t id, uint16_t len, uint8_t* data)
+{
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+
+    btc_msg_t msg;
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HD;
+    msg.act = BTC_HD_SEND_REPORT_EVT;
+
+    btc_hidd_args_t args;
+    memset(&args, 0, sizeof(btc_hidd_args_t));
+    args.send_report.type = type;
+    args.send_report.id = id;
+    args.send_report.len = len;
+    args.send_report.data = data;
+
+    bt_status_t stat = btc_transfer_context(&msg, &args, sizeof(btc_hidd_args_t), btc_hd_arg_deep_copy);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hid_device_report_error(esp_hidd_handshake_error_t error)
+{
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+
+    btc_msg_t msg;
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HD;
+    msg.act = BTC_HD_REPORT_ERROR_EVT;
+
+    btc_hidd_args_t args;
+    memset(&args, 0, sizeof(btc_hidd_args_t));
+    args.error = error;
+
+    bt_status_t stat = btc_transfer_context(&msg, &args, sizeof(btc_hidd_args_t), NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hid_device_virtual_cable_unplug(void)
+{
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+
+    btc_msg_t msg;
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HD;
+    msg.act = BTC_HD_UNPLUG_EVT;
+
+    bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+#endif /* defined BTC_HD_INCLUDED && BTC_HD_INCLUDED == TRUE */

+ 254 - 0
components/bt/host/bluedroid/api/esp_hidh_api.c

@@ -0,0 +1,254 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+// Copyright 2019      Blake Felt
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "btc/btc_manage.h"
+#include "btc_hh.h"
+#include "esp_bt_main.h"
+#include "esp_err.h"
+#include "esp_hidh_api.h"
+#include <string.h>
+
+#if (defined BTC_HH_INCLUDED && BTC_HH_INCLUDED == TRUE)
+
+esp_err_t esp_bt_hid_host_register_callback(esp_hh_cb_t *callback)
+{
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+
+    if (callback == NULL) {
+        return ESP_FAIL;
+    }
+
+    btc_profile_cb_set(BTC_PID_HH, callback);
+    return ESP_OK;
+}
+
+esp_err_t esp_bt_hid_host_init(void)
+{
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+
+    btc_msg_t msg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HH;
+    msg.act = BTC_HH_INIT_EVT;
+
+    bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hid_host_deinit(void)
+{
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+
+    btc_msg_t msg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HH;
+    msg.act = BTC_HH_DEINIT_EVT;
+
+    bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hid_host_connect(esp_bd_addr_t bd_addr)
+{
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+    btc_msg_t msg;
+    btc_hidh_args_t arg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HH;
+    msg.act = BTC_HH_CONNECT_EVT;
+
+    memcpy(arg.connect.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
+
+    bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hid_host_disconnect(esp_bd_addr_t bd_addr)
+{
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+    btc_msg_t msg;
+    btc_hidh_args_t arg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HH;
+    msg.act = BTC_HH_DISCONNECT_EVT;
+
+    memcpy(arg.disconnect.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
+
+    bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hid_host_virtual_cable_unplug(esp_bd_addr_t bd_addr)
+{
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+    btc_msg_t msg;
+    btc_hidh_args_t arg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HH;
+    msg.act = BTC_HH_UNPLUG_EVT;
+
+    memcpy(arg.unplug.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
+
+    bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hid_host_set_info(esp_bd_addr_t bd_addr, esp_hidh_hid_info_t *hid_info)
+{
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+    btc_msg_t msg;
+    btc_hidh_args_t arg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HH;
+    msg.act = BTC_HH_SET_INFO_EVT;
+
+    memcpy(arg.set_info.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
+    arg.set_info.hid_info = hid_info;
+
+    bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), btc_hh_arg_deep_copy);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hid_host_get_protocol(esp_bd_addr_t bd_addr)
+{
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+    btc_msg_t msg;
+    btc_hidh_args_t arg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HH;
+    msg.act = BTC_HH_GET_PROTO_EVT;
+
+    memcpy(arg.get_protocol.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
+
+    bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hid_host_set_protocol(esp_bd_addr_t bd_addr, esp_hidh_protocol_mode_t protocol_mode)
+{
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+    btc_msg_t msg;
+    btc_hidh_args_t arg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HH;
+    msg.act = BTC_HH_SET_PROTO_EVT;
+
+    memcpy(arg.set_protocol.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
+    arg.set_protocol.protocol_mode = protocol_mode;
+
+    bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hid_host_get_idle(esp_bd_addr_t bd_addr)
+{
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+    btc_msg_t msg;
+    btc_hidh_args_t arg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HH;
+    msg.act = BTC_HH_GET_IDLE_EVT;
+
+    memcpy(arg.get_idle.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
+
+    bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hid_host_set_idle(esp_bd_addr_t bd_addr, uint16_t idle_time)
+{
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+    btc_msg_t msg;
+    btc_hidh_args_t arg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HH;
+    msg.act = BTC_HH_SET_IDLE_EVT;
+
+    memcpy(arg.set_idle.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
+    arg.set_idle.idle_time = idle_time;
+
+    bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hid_host_get_report(esp_bd_addr_t bd_addr, esp_hidh_report_type_t report_type, uint8_t report_id,
+                                     int buffer_size)
+{
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+    btc_msg_t msg;
+    btc_hidh_args_t arg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HH;
+    msg.act = BTC_HH_GET_REPORT_EVT;
+
+    memcpy(arg.get_report.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
+    arg.get_report.report_type = report_type;
+    arg.get_report.report_id = report_id;
+    arg.get_report.buffer_size = buffer_size;
+
+    bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), NULL);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hid_host_set_report(esp_bd_addr_t bd_addr, esp_hidh_report_type_t report_type, uint8_t *report,
+                                     size_t len)
+{
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+    btc_msg_t msg;
+    btc_hidh_args_t arg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HH;
+    msg.act = BTC_HH_SET_REPORT_EVT;
+
+    memcpy(arg.set_report.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
+    arg.set_report.report_type = report_type;
+    arg.set_report.len = len;
+    arg.set_report.report = report;
+
+    bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), btc_hh_arg_deep_copy);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hid_host_send_data(esp_bd_addr_t bd_addr, uint8_t *data, size_t len)
+{
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+    btc_msg_t msg;
+    btc_hidh_args_t arg;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_HH;
+    msg.act = BTC_HH_SEND_DATA_EVT;
+
+    memcpy(arg.send_data.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
+    arg.send_data.len = len;
+    arg.send_data.data = data;
+
+    bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), btc_hh_arg_deep_copy);
+    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+#endif /* defined BTC_HH_INCLUDED && BTC_HH_INCLUDED == TRUE */

+ 6 - 6
components/bt/host/bluedroid/api/include/api/esp_gap_ble_api.h

@@ -467,7 +467,7 @@ typedef struct
 {
     uint16_t rx_len;                   /*!< pkt rx data length value */
     uint16_t tx_len;                   /*!< pkt tx data length value */
-}esp_ble_pkt_data_length_params_t;
+} esp_ble_pkt_data_length_params_t;
 
 /**
 * @brief BLE encryption keys
@@ -648,7 +648,7 @@ typedef enum {
 typedef enum{
     ESP_BLE_WHITELIST_REMOVE     = 0X00,    /*!< remove mac from whitelist */
     ESP_BLE_WHITELIST_ADD        = 0X01,    /*!< add address to whitelist */
-}esp_ble_wl_opration_t;
+} esp_ble_wl_opration_t;
 #if (BLE_42_FEATURE_SUPPORT == TRUE)
 typedef enum {
     ESP_BLE_DUPLICATE_EXCEPTIONAL_LIST_ADD      = 0,  /*!< Add device info into duplicate scan exceptional list */
@@ -998,7 +998,7 @@ typedef union {
         uint16_t conn_int;                         /*!< Current connection interval */
         uint16_t timeout;                          /*!< Supervision timeout for the LE Link. Range: 0x000A to 0x0C80.
                                                      Mandatory Range: 0x000A to 0x0C80 Time = N * 10 msec */
-    }update_conn_params;                           /*!< Event parameter of ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT */
+    } update_conn_params;                          /*!< Event parameter of ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT */
     /**
      * @brief ESP_GAP_BLE_SET_PKT_LENGTH_COMPLETE_EVT
      */
@@ -1018,13 +1018,13 @@ typedef union {
     struct ble_remove_bond_dev_cmpl_evt_param {
         esp_bt_status_t status;                     /*!< Indicate the remove bond device operation success status */
         esp_bd_addr_t bd_addr;                      /*!< The device address which has been remove from the bond list */
-    }remove_bond_dev_cmpl;                          /*!< Event parameter of ESP_GAP_BLE_REMOVE_BOND_DEV_COMPLETE_EVT */
+    } remove_bond_dev_cmpl;                         /*!< Event parameter of ESP_GAP_BLE_REMOVE_BOND_DEV_COMPLETE_EVT */
     /**
      * @brief ESP_GAP_BLE_CLEAR_BOND_DEV_COMPLETE_EVT
      */
     struct ble_clear_bond_dev_cmpl_evt_param {
         esp_bt_status_t status;                     /*!< Indicate the clear bond device operation success status */
-    }clear_bond_dev_cmpl;                           /*!< Event parameter of ESP_GAP_BLE_CLEAR_BOND_DEV_COMPLETE_EVT */
+    } clear_bond_dev_cmpl;                          /*!< Event parameter of ESP_GAP_BLE_CLEAR_BOND_DEV_COMPLETE_EVT */
     /**
      * @brief ESP_GAP_BLE_GET_BOND_DEV_COMPLETE_EVT
      */
@@ -1032,7 +1032,7 @@ typedef union {
         esp_bt_status_t status;                     /*!< Indicate the get bond device operation success status */
         uint8_t dev_num;                            /*!< Indicate the get number device in the bond list */
         esp_ble_bond_dev_t *bond_dev;               /*!< the pointer to the bond device Structure */
-    }get_bond_dev_cmpl;                             /*!< Event parameter of ESP_GAP_BLE_GET_BOND_DEV_COMPLETE_EVT */
+    } get_bond_dev_cmpl;                            /*!< Event parameter of ESP_GAP_BLE_GET_BOND_DEV_COMPLETE_EVT */
     /**
      * @brief ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT
      */

+ 1 - 1
components/bt/host/bluedroid/api/include/api/esp_gattc_api.h

@@ -380,7 +380,7 @@ esp_err_t esp_ble_gattc_search_service(esp_gatt_if_t gattc_if, uint16_t conn_id,
 /**
  * @brief           Find all the service with the given service uuid in the gattc cache, if the svc_uuid is NULL, find all the service.
  *                  Note: It just get service from local cache, won't get from remote devices. If want to get it from remote device, need
- *                  to used the esp_ble_gattc_search_service.
+ *                  to used the esp_ble_gattc_cache_refresh, then call esp_ble_gattc_get_service again.
  *
  * @param[in]       gattc_if: Gatt client access interface.
  * @param[in]       conn_id: connection ID which identify the server.

+ 379 - 0
components/bt/host/bluedroid/api/include/api/esp_hidd_api.h

@@ -0,0 +1,379 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+// Copyright 2019      Blake Felt
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __ESP_HIDD_API_H__
+#define __ESP_HIDD_API_H__
+
+#include "esp_bt_defs.h"
+#include "esp_err.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* sub_class of hid device */
+#define ESP_HID_CLASS_UNKNOWN      (0x00<<2)
+#define ESP_HID_CLASS_JOS          (0x01<<2)           /* joy stick */
+#define ESP_HID_CLASS_GPD          (0x02<<2)           /* game pad */
+#define ESP_HID_CLASS_RMC          (0x03<<2)           /* remote control */
+#define ESP_HID_CLASS_SED          (0x04<<2)           /* sensing device */
+#define ESP_HID_CLASS_DGT          (0x05<<2)           /* Digitizer tablet */
+#define ESP_HID_CLASS_CDR          (0x06<<2)           /* card reader */
+#define ESP_HID_CLASS_KBD          (0x10<<2)           /* keyboard */
+#define ESP_HID_CLASS_MIC          (0x20<<2)           /* pointing device */
+#define ESP_HID_CLASS_COM          (0x30<<2)           /* Combo keyboard/pointing */
+
+/**
+ * @brief HIDD handshake error
+ */
+typedef enum {
+    ESP_HID_PAR_HANDSHAKE_RSP_SUCCESS = 0,
+    ESP_HID_PAR_HANDSHAKE_RSP_NOT_READY = 1,
+    ESP_HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID = 2,
+    ESP_HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ = 3,
+    ESP_HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM = 4,
+    ESP_HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN = 14,
+    ESP_HID_PAR_HANDSHAKE_RSP_ERR_FATAL = 15
+} esp_hidd_handshake_error_t;
+
+/**
+ * @brief HIDD report types
+ */
+typedef enum {
+    ESP_HIDD_REPORT_TYPE_OTHER = 0,
+    ESP_HIDD_REPORT_TYPE_INPUT,
+    ESP_HIDD_REPORT_TYPE_OUTPUT,
+    ESP_HIDD_REPORT_TYPE_FEATURE,
+    // special value for reports to be sent on INTR(INPUT is assumed)
+    ESP_HIDD_REPORT_TYPE_INTRDATA
+} esp_hidd_report_type_t;
+
+/**
+ * @brief HIDD connection state
+ */
+typedef enum {
+    ESP_HIDD_CONN_STATE_CONNECTED,
+    ESP_HIDD_CONN_STATE_CONNECTING,
+    ESP_HIDD_CONN_STATE_DISCONNECTED,
+    ESP_HIDD_CONN_STATE_DISCONNECTING,
+    ESP_HIDD_CONN_STATE_UNKNOWN
+} esp_hidd_connection_state_t;
+
+/**
+ * @brief HID device protocol modes
+ */
+typedef enum {
+    ESP_HIDD_REPORT_MODE = 0x00,
+    ESP_HIDD_BOOT_MODE = 0x01,
+    ESP_HIDD_UNSUPPORTED_MODE = 0xff
+} esp_hidd_protocol_mode_t;
+
+
+/**
+ * @brief HIDD characteristics for SDP report
+ */
+typedef struct {
+    const char *name;
+    const char *description;
+    const char *provider;
+    uint8_t subclass;
+    uint8_t *desc_list;
+    int desc_list_len;
+} esp_hidd_app_param_t;
+
+/**
+ * @brief HIDD Quality of Service parameters
+ */
+typedef struct {
+    uint8_t service_type;
+    uint32_t token_rate;
+    uint32_t token_bucket_size;
+    uint32_t peak_bandwidth;
+    uint32_t access_latency;
+    uint32_t delay_variation;
+} esp_hidd_qos_param_t;
+
+/**
+ * @brief HID device callback function events
+ */
+typedef enum {
+    ESP_HIDD_INIT_EVT = 0,       /*!< When HID device is inited, the event comes */
+    ESP_HIDD_DEINIT_EVT,         /*!< When HID device is deinited, the event comes */
+    ESP_HIDD_REGISTER_APP_EVT,   /*!< When HID device application registered, the event comes */
+    ESP_HIDD_UNREGISTER_APP_EVT, /*!< When HID device application unregistered, the event comes */
+    ESP_HIDD_OPEN_EVT,           /*!< When HID device connection to host opened, the event comes */
+    ESP_HIDD_CLOSE_EVT,          /*!< When HID device connection to host closed, the event comes */
+    ESP_HIDD_SEND_REPORT_EVT,    /*!< When HID device send report to lower layer, the event comes */
+    ESP_HIDD_REPORT_ERR_EVT,     /*!< When HID device report handshanke error to lower layer, the event comes */
+    ESP_HIDD_GET_REPORT_EVT,     /*!< When HID device receives GET_REPORT request from host, the event comes */
+    ESP_HIDD_SET_REPORT_EVT,     /*!< When HID device receives SET_REPORT request from host, the event comes */
+    ESP_HIDD_SET_PROTOCOL_EVT,   /*!< When HID device receives SET_PROTOCOL request from host, the event comes */
+    ESP_HIDD_INTR_DATA_EVT,      /*!< When HID device receives DATA from host on intr, the event comes */
+    ESP_HIDD_VC_UNPLUG_EVT,      /*!< When HID device initiates Virtual Cable Unplug, the event comes */
+    ESP_HIDD_API_ERR_EVT         /*!< When HID device has API error, the event comes */
+} esp_hidd_cb_event_t;
+
+typedef enum {
+    ESP_HIDD_SUCCESS,
+    ESP_HIDD_ERROR,         /*!< general ESP HD error */
+    ESP_HIDD_NO_RES,        /*!< out of system resources */
+    ESP_HIDD_BUSY,          /*!< Temporarily can not handle this request. */
+    ESP_HIDD_NO_DATA,       /*!< No data. */
+    ESP_HIDD_NEED_INIT,     /*!< HIDD module shall init first */
+    ESP_HIDD_NEED_DEINIT,   /*!< HIDD module shall deinit first */
+    ESP_HIDD_NEED_REG,      /*!< HIDD module shall register first */
+    ESP_HIDD_NEED_DEREG,    /*!< HIDD module shall deregister first */
+    ESP_HIDD_NO_CONNECTION, /*!< connection may have been closed */
+} esp_hidd_status_t;
+
+/**
+ * @brief HID device callback parameters union
+ */
+typedef union {
+    /**
+     * @brief ESP_HIDD_INIT_EVT
+     */
+    struct hidd_init_evt_param {
+        esp_hidd_status_t status; /*!< operation status */
+    } init;                       /*!< HIDD callback param of ESP_HIDD_INIT_EVT */
+
+    /**
+     * @brief ESP_HIDD_DEINIT_EVT
+     */
+    struct hidd_deinit_evt_param {
+        esp_hidd_status_t status; /*!< operation status */
+    } deinit;                     /*!< HIDD callback param of ESP_HIDD_DEINIT_EVT */
+
+    /**
+     * @brief ESP_HIDD_REGISTER_APP_EVT
+     */
+    struct hidd_register_app_evt_param {
+        esp_hidd_status_t status; /*!< operation status */
+        bool in_use;              /*!< indicate whether use virtual cable plug host address */
+        esp_bd_addr_t bd_addr;    /*!< host address */
+    } register_app;               /*!< HIDD callback param of ESP_HIDD_REGISTER_APP_EVT */
+
+    /**
+     * @brief ESP_HIDD_UNREGISTER_APP_EVT
+     */
+    struct hidd_unregister_app_evt_param {
+        esp_hidd_status_t status; /*!< operation status         */
+    } unregister_app;             /*!< HIDD callback param of ESP_HIDD_UNREGISTER_APP_EVT */
+
+    /**
+     * @brief ESP_HIDD_OPEN_EVT
+     */
+    struct hidd_open_evt_param {
+        esp_hidd_status_t status;                /*!< operation status         */
+        esp_hidd_connection_state_t conn_status; /*!< connection status */
+        esp_bd_addr_t bd_addr;                   /*!< host address */
+    } open;                                      /*!< HIDD callback param of ESP_HIDD_OPEN_EVT */
+
+    /**
+     * @brief ESP_HIDD_CLOSE_EVT
+     */
+    struct hidd_close_evt_param {
+        esp_hidd_status_t status;                /*!< operation status         */
+        esp_hidd_connection_state_t conn_status; /*!< connection status        */
+    } close;                                     /*!< HIDD callback param of ESP_HIDD_CLOSE_EVT */
+
+    /**
+     * @brief ESP_HIDD_SEND_REPORT_EVT
+     */
+    struct hidd_send_report_evt_param {
+        esp_hidd_status_t status;           /*!< operation status         */
+        uint8_t reason;                     /*!< lower layer failed reason(ref hiddefs.h)       */
+        esp_hidd_report_type_t report_type; /*!< report type        */
+        uint8_t report_id;                  /*!< report id         */
+    } send_report;                          /*!< HIDD callback param of ESP_HIDD_SEND_REPORT_EVT */
+
+    /**
+     * @brief ESP_HIDD_REPORT_ERR_EVT
+     */
+    struct hidd_report_err_evt_param {
+        esp_hidd_status_t status; /*!< operation status         */
+        uint8_t reason;           /*!< lower layer failed reason(ref hiddefs.h)           */
+    } report_err;                 /*!< HIDD callback param of ESP_HIDD_REPORT_ERR_EVT */
+
+    /**
+     * @brief ESP_HIDD_GET_REPORT_EVT
+     */
+    struct hidd_get_report_evt_param {
+        esp_hidd_report_type_t report_type; /*!< report type        */
+        uint8_t report_id;                  /*!< report id         */
+        uint16_t buffer_size;               /*!< buffer size         */
+    } get_report;                           /*!< HIDD callback param of ESP_HIDD_GET_REPORT_EVT */
+
+    /**
+     * @brief ESP_HIDD_SET_REPORT_EVT
+     */
+    struct hidd_set_report_evt_param {
+        esp_hidd_report_type_t report_type; /*!< report type        */
+        uint8_t report_id;                  /*!< report id         */
+        uint16_t len;                       /*!< set_report data length         */
+        uint8_t *data;                      /*!< set_report data pointer         */
+    } set_report;                           /*!< HIDD callback param of ESP_HIDD_SET_REPORT_EVT */
+
+    /**
+     * @brief ESP_HIDD_SET_PROTOCOL_EVT
+     */
+    struct hidd_set_protocol_evt_param {
+        esp_hidd_protocol_mode_t protocol_mode; /*!< protocol mode        */
+    } set_protocol;                             /*!< HIDD callback param of ESP_HIDD_SET_PROTOCOL_EVT */
+
+    /**
+     * @brief ESP_HIDD_INTR_DATA_EVT
+     */
+    struct hidd_intr_data_evt_param {
+        uint8_t report_id; /*!< interrupt channel report id         */
+        uint16_t len;      /*!< interrupt channel report data length         */
+        uint8_t *data;     /*!< interrupt channel report data pointer         */
+    } intr_data;           /*!< HIDD callback param of ESP_HIDD_INTR_DATA_EVT */
+
+    /**
+     * @brief ESP_HIDD_VC_UNPLUG_EVT
+     */
+    struct hidd_vc_unplug_param {
+        esp_hidd_status_t status;                /*!< operation status         */
+        esp_hidd_connection_state_t conn_status; /*!< connection status        */
+    } vc_unplug;                                 /*!< HIDD callback param of ESP_HIDD_VC_UNPLUG_EVT */
+} esp_hidd_cb_param_t;
+
+/**
+ * @brief       HID device callback function type.
+ * @param       event:      Event type
+ * @param       param:      Point to callback parameter, currently is union type
+ */
+typedef void (esp_hd_cb_t)(esp_hidd_cb_event_t event, esp_hidd_cb_param_t *param);
+
+/**
+ * @brief       This function is called to init callbacks with HID device module.
+ *
+ * @param[in]   callback:   pointer to the init callback function.
+ *
+ * @return
+ *              - ESP_OK: success
+ *              - other: failed
+ */
+esp_err_t esp_bt_hid_device_register_callback(esp_hd_cb_t callback);
+
+/**
+ * @brief       This function initializes HIDD. This function should be called after esp_bluedroid_enable and
+ *              esp_blueroid_init success, and should be called after esp_bt_hid_device_register_callback.
+ *              When the operation is complete the callback function will be called with ESP_HIDD_INIT_EVT.
+ *
+ * @return
+ *              - ESP_OK: success
+ *              - other: failed
+ */
+esp_err_t esp_bt_hid_device_init(void);
+
+/**
+ * @brief       This function de-initializes HIDD interface. This function should be called after esp_bluedroid_enable() and
+ *              esp_blueroid_init() success, and should be called after esp_bt_hid_device_init(). When the operation is complete the callback
+ *              function will be called with ESP_HIDD_DEINIT_EVT.
+ *
+ * @return    - ESP_OK: success
+ *            - other: failed
+ */
+esp_err_t esp_bt_hid_device_deinit(void);
+
+/**
+ * @brief     Registers HIDD parameters with SDP and sets l2cap Quality of Service. This function should be called after
+ *            esp_bluedroid_enable and esp_blueroid_init success, and must be done after esp_bt_hid_device_init. When the operation is complete the callback
+ *            function will be called with ESP_HIDD_REGISTER_APP_EVT.
+ *
+ * @param[in] app_param:  HIDD parameters
+ * @param[in] in_qos:     incoming QoS parameters
+ * @param[in] out_qos:    outgoing QoS parameters
+ *
+ * @return    - ESP_OK: success
+ *            - other: failed
+ */
+esp_err_t esp_bt_hid_device_register_app(esp_hidd_app_param_t *app_param, esp_hidd_qos_param_t *in_qos,
+                                         esp_hidd_qos_param_t *out_qos);
+
+/**
+ * @brief   Removes HIDD parameters from SDP and resets l2cap Quality of Service. This function should be called after esp_bluedroid_enable and
+ *          esp_blueroid_init success, and should be called after esp_bt_hid_device_init. When the operation is complete the callback
+ *          function will be called with ESP_HIDD_UNREGISTER_APP_EVT.
+ *
+ * @return  - ESP_OK: success
+ *          - other: failed
+ */
+esp_err_t esp_bt_hid_device_unregister_app(void);
+
+/**
+ * @brief     This function connects HIDD interface to connected bluetooth device, if not done already. When the operation is complete the callback
+ *            function will be called with ESP_HIDD_OPEN_EVT.
+ *
+ * @param[in] bd_addr:      Remote host bluetooth device address.
+ *
+ * @return
+ *            - ESP_OK: success
+ *            - other: failed
+ */
+esp_err_t esp_bt_hid_device_connect(esp_bd_addr_t bd_addr);
+
+/**
+ * @brief     This function disconnects HIDD interface. When the operation is complete the callback
+ *            function will be called with ESP_HIDD_CLOSE_EVT.
+ *
+ * @return
+ *            - ESP_OK: success
+ *            - other: failed
+ */
+esp_err_t esp_bt_hid_device_disconnect(void);
+
+/**
+ * @brief     Send HIDD report. When the operation is complete the callback
+ *            function will be called with ESP_HIDD_SEND_REPORT_EVT.
+ *
+ * @param[in] type:   type of report
+ * @param[in] id:     report id as defined by descriptor
+ * @param[in] len:    length of report
+ * @param[in] data:   report data
+ *
+ * @return
+ *            - ESP_OK: success
+ *            - other: failed
+ */
+esp_err_t esp_bt_hid_device_send_report(esp_hidd_report_type_t type, uint8_t id, uint16_t len, uint8_t *data);
+
+/**
+ * @brief     Sends HIDD handshake with error info for invalid set_report. When the operation is complete the callback
+ *            function will be called with ESP_HIDD_REPORT_ERR_EVT.
+ *
+ * @param[in] error: type of error
+ *
+ * @return    - ESP_OK: success
+ *            - other: failed
+ */
+esp_err_t esp_bt_hid_device_report_error(esp_hidd_handshake_error_t error);
+
+/**
+ * @brief     Unplug virtual cable of HIDD. When the operation is complete the callback
+ *            function will be called with ESP_HIDD_VC_UNPLUG_EVT.
+ *
+ * @return    - ESP_OK: success
+ *            - other: failed
+ */
+esp_err_t esp_bt_hid_device_virtual_cable_unplug(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 465 - 0
components/bt/host/bluedroid/api/include/api/esp_hidh_api.h

@@ -0,0 +1,465 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+// Copyright 2019      Blake Felt
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __ESP_HIDH_API_H__
+#define __ESP_HIDH_API_H__
+
+#include "esp_bt_defs.h"
+#include "esp_err.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define BTHH_MAX_DSC_LEN 884
+
+/**
+ * @brief HID host connection state
+ */
+typedef enum {
+    ESP_HIDH_CONN_STATE_CONNECTED = 0,           /*!< connected state */
+    ESP_HIDH_CONN_STATE_CONNECTING,              /*!< connecting state */
+    ESP_HIDH_CONN_STATE_DISCONNECTED,            /*!< disconnected state */
+    ESP_HIDH_CONN_STATE_DISCONNECTING,           /*!< disconnecting state */
+    ESP_HIDH_CONN_STATE_UNKNOWN                  /*!< unknown state(initial state) */
+} esp_hidh_connection_state_t;
+
+typedef enum {
+    ESP_HIDH_OK,
+    ESP_HIDH_HS_HID_NOT_READY,  /*!< handshake error : device not ready */
+    ESP_HIDH_HS_INVALID_RPT_ID, /*!< handshake error : invalid report ID */
+    ESP_HIDH_HS_TRANS_NOT_SPT,  /*!< handshake error : transaction not spt */
+    ESP_HIDH_HS_INVALID_PARAM,  /*!< handshake error : invalid paremter */
+    ESP_HIDH_HS_ERROR,          /*!< handshake error : unspecified HS error */
+    ESP_HIDH_ERR,               /*!< general ESP HH error */
+    ESP_HIDH_ERR_SDP,           /*!< SDP error */
+    ESP_HIDH_ERR_PROTO,         /*!< SET_Protocol error,
+                                  only used in ESP_HIDH_OPEN_EVT callback */
+
+    ESP_HIDH_ERR_DB_FULL,       /*!< device database full error, used in
+                                     ESP_HIDH_OPEN_EVT/ESP_HIDH_ADD_DEV_EVT */
+    ESP_HIDH_ERR_TOD_UNSPT,     /*!< type of device not supported */
+    ESP_HIDH_ERR_NO_RES,        /*!< out of system resources */
+    ESP_HIDH_ERR_AUTH_FAILED,   /*!< authentication fail */
+    ESP_HIDH_ERR_HDL,           /*!< connection handle error */
+    ESP_HIDH_ERR_SEC,           /*!< encryption error */
+    // self_defined
+    ESP_HIDH_BUSY,              /*!< Temporarily can not handle this request. */
+    ESP_HIDH_NO_DATA,           /*!< No data. */
+    ESP_HIDH_NEED_INIT,         /*!< HIDH module shall init first */
+    ESP_HIDH_NEED_DEINIT,       /*!< HIDH module shall deinit first */
+    ESP_HIDH_NO_CONNECTION,     /*!< connection may have been closed */
+} esp_hidh_status_t;
+
+/**
+ * @brief HID host protocol modes
+ */
+typedef enum {
+    ESP_HIDH_BOOT_MODE = 0x00,       /*!< boot protocol mode */
+    ESP_HIDH_REPORT_MODE = 0x01,     /*!< report protocol mode */
+    ESP_HIDH_UNSUPPORTED_MODE = 0xff /*!< unsupported protocol mode */
+} esp_hidh_protocol_mode_t;
+
+/**
+ * @brief HID host report types
+ */
+typedef enum {
+    ESP_HIDH_REPORT_TYPE_OTHER = 0, /*!< unsupported report type */
+    ESP_HIDH_REPORT_TYPE_INPUT,     /*!< input report type */
+    ESP_HIDH_REPORT_TYPE_OUTPUT,    /*!< output report type */
+    ESP_HIDH_REPORT_TYPE_FEATURE,   /*!< feature report type */
+} esp_hidh_report_type_t;
+
+/**
+ * @brief HID host callback function events
+ */
+typedef enum {
+    ESP_HIDH_INIT_EVT = 0,  /*!< When HID host is inited, the event comes */
+    ESP_HIDH_DEINIT_EVT,    /*!< When HID host is deinited, the event comes */
+    ESP_HIDH_OPEN_EVT,      /*!< When HID host connection opened, the event comes */
+    ESP_HIDH_CLOSE_EVT,     /*!< When HID host connection closed, the event comes */
+    ESP_HIDH_GET_RPT_EVT,   /*!< When Get_Report command is called, the event comes */
+    ESP_HIDH_SET_RPT_EVT,   /*!< When Set_Report command is called, the event comes */
+    ESP_HIDH_GET_PROTO_EVT, /*!< When Get_Protocol command is called, the event comes */
+    ESP_HIDH_SET_PROTO_EVT, /*!< When Set_Protocol command is called, the event comes */
+    ESP_HIDH_GET_IDLE_EVT,  /*!< When Get_Idle command is called, the event comes */
+    ESP_HIDH_SET_IDLE_EVT,  /*!< When Set_Idle command is called, the event comes */
+    ESP_HIDH_GET_DSCP_EVT,  /*!< When HIDH is inited, the event comes */
+    ESP_HIDH_ADD_DEV_EVT,   /*!< When a device is added, the event comes */
+    ESP_HIDH_RMV_DEV_EVT,   /*!< When a device is removed, the event comes */
+    ESP_HIDH_VC_UNPLUG_EVT, /*!< When virtually unplugged, the event comes */
+    ESP_HIDH_DATA_EVT,      /*!< When send data on interrupt channel, the event comes */
+    ESP_HIDH_DATA_IND_EVT,  /*!< When receive data on interrupt channel, the event comes */
+    ESP_HIDH_SET_INFO_EVT   /*!< When set the HID device descriptor, the event comes */
+} esp_hidh_cb_event_t;
+
+typedef struct {
+    int attr_mask;
+    uint8_t sub_class;
+    uint8_t app_id;
+    int vendor_id;
+    int product_id;
+    int version;
+    uint8_t ctry_code;
+    int dl_len;
+    uint8_t dsc_list[BTHH_MAX_DSC_LEN];
+} esp_hidh_hid_info_t;
+
+/**
+ * @brief HID host callback parameters union
+ */
+typedef union {
+    /**
+     * @brief ESP_HIDH_INIT_EVT
+     */
+    struct hidh_init_evt_param {
+        esp_hidh_status_t status; /*!< status */
+    } init;                       /*!< HIDH callback param of ESP_HIDH_INIT_EVT */
+
+    /**
+     * @brief ESP_HIDH_DEINIT_EVT
+     */
+    struct hidh_uninit_evt_param {
+        esp_hidh_status_t status; /*!< status */
+    } deinit;                     /*!< HIDH callback param of ESP_HIDH_DEINIT_EVT */
+
+    /**
+     * @brief ESP_HIDH_OPEN_EVT
+     */
+    struct hidh_open_evt_param {
+        esp_hidh_status_t status;                /*!< operation status         */
+        esp_hidh_connection_state_t conn_status; /*!< connection status        */
+        bool is_orig;                            /*!< indicate if host intiate the connection        */
+        uint8_t handle;                          /*!< device handle            */
+        esp_bd_addr_t bd_addr;                   /*!< device address           */
+    } open;                                      /*!< HIDH callback param of ESP_HIDH_OPEN_EVT */
+
+    /**
+     * @brief ESP_HIDH_CLOSE_EVT
+     */
+    struct hidh_close_evt_param {
+        esp_hidh_status_t status;                /*!< operation status         */
+        uint8_t reason;                          /*!< lower layer failed reason(ref hiddefs.h)       */
+        esp_hidh_connection_state_t conn_status; /*!< connection status        */
+        uint8_t handle;                          /*!< device handle            */
+    } close;                                     /*!< HIDH callback param of ESP_HIDH_CLOSE_EVT */
+
+    /**
+     * @brief ESP_HIDH_VC_UNPLUG_EVT
+     */
+    struct hidh_unplug_evt_param {
+        esp_hidh_status_t status;                /*!< operation status         */
+        esp_hidh_connection_state_t conn_status; /*!< connection status        */
+        uint8_t handle;                          /*!< device handle            */
+    } unplug;                                    /*!< HIDH callback param of ESP_HIDH_VC_UNPLUG_EVT */
+
+    /**
+     * @brief ESP_HIDH_GET_PROTO_EVT
+     */
+    struct hidh_get_proto_evt_param {
+        esp_hidh_status_t status;            /*!< operation status         */
+        uint8_t handle;                      /*!< device handle            */
+        esp_hidh_protocol_mode_t proto_mode; /*!< protocol mode            */
+    } get_proto;                             /*!< HIDH callback param of ESP_HIDH_GET_PROTO_EVT */
+
+    /**
+     * @brief ESP_HIDH_SET_PROTO_EVT
+     */
+    struct hidh_set_proto_evt_param {
+        esp_hidh_status_t status; /*!< operation status         */
+        uint8_t handle;           /*!< device handle            */
+    } set_proto;                  /*!< HIDH callback param of ESP_HIDH_SET_PROTO_EVT */
+
+    /**
+     * @brief ESP_HIDH_GET_RPT_EVT
+     */
+    struct hidh_get_rpt_evt_param {
+        esp_hidh_status_t status; /*!< operation status         */
+        uint8_t handle;           /*!< device handle            */
+        uint16_t len;             /*!< data length              */
+        uint8_t *data;            /*!< data pointer             */
+    } get_rpt;                    /*!< HIDH callback param of ESP_HIDH_GET_RPT_EVT */
+
+    /**
+     * @brief ESP_HIDH_SET_RPT_EVT
+     */
+    struct hidh_set_rpt_evt_param {
+        esp_hidh_status_t status; /*!< operation status         */
+        uint8_t handle;           /*!< device handle            */
+    } set_rpt;                    /*!< HIDH callback param of ESP_HIDH_SET_RPT_EVT */
+
+    /**
+     * @brief ESP_HIDH_DATA_EVT
+     */
+    struct hidh_send_data_evt_param {
+        esp_hidh_status_t status; /*!< operation status         */
+        uint8_t handle;           /*!< device handle            */
+        uint8_t reason;           /*!< lower layer failed reason(ref hiddefs.h)       */
+    } send_data;                  /*!< HIDH callback param of ESP_HIDH_DATA_EVT */
+
+    /**
+     * @brief ESP_HIDH_GET_IDLE_EVT
+     */
+    struct hidh_get_idle_evt_param {
+        esp_hidh_status_t status; /*!< operation status         */
+        uint8_t handle;           /*!< device handle            */
+        uint8_t idle_rate;        /*!< idle rate                */
+    } get_idle;                   /*!< HIDH callback param of ESP_HIDH_GET_IDLE_EVT */
+
+    /**
+     * @brief ESP_HIDH_SET_IDLE_EVT
+     */
+    struct hidh_set_idle_evt_param {
+        esp_hidh_status_t status; /*!< operation status         */
+        uint8_t handle;           /*!< device handle            */
+    } set_idle;                   /*!< HIDH callback param of ESP_HIDH_SET_IDLE_EVT */
+
+    /**
+     * @brief ESP_HIDH_DATA_IND_EVT
+     */
+    struct hidh_data_ind_evt_param {
+        esp_hidh_status_t status;            /*!< operation status         */
+        uint8_t handle;                      /*!< device handle            */
+        esp_hidh_protocol_mode_t proto_mode; /*!< protocol mode            */
+        uint16_t len;                        /*!< data length              */
+        uint8_t *data;                       /*!< data pointer             */
+    } data_ind;                              /*!< HIDH callback param of ESP_HIDH_DATA_IND_EVT */
+
+    /**
+     * @brief ESP_HIDH_ADD_DEV_EVT
+     */
+    struct hidh_add_dev_evt_param {
+        esp_hidh_status_t status; /*!< operation status         */
+        uint8_t handle;           /*!< device handle            */
+        esp_bd_addr_t bd_addr;    /*!< device address           */
+    } add_dev;                    /*!< HIDH callback param of ESP_HIDH_ADD_DEV_EVT */
+
+    /**
+     * @brief ESP_HIDH_RMV_DEV_EVT
+     */
+    struct hidh_rmv_dev_evt_param {
+        esp_hidh_status_t status; /*!< operation status         */
+        uint8_t handle;           /*!< device handle            */
+        esp_bd_addr_t bd_addr;    /*!< device address           */
+    } rmv_dev;                    /*!< HIDH callback param of ESP_HIDH_RMV_DEV_EVT */
+
+    /**
+     * @brief ESP_HIDH_GET_DSCP_EVT
+     */
+    struct hidh_get_dscp_evt_param {
+        esp_hidh_status_t status; /*!< operation status         */
+        uint8_t handle;           /*!< device handle            */
+        bool added;               /*!< Indicate if added        */
+        uint16_t vendor_id;       /*!< Vendor ID */
+        uint16_t product_id;      /*!< Product ID */
+        uint16_t version;         /*!< Version */
+        uint16_t ssr_max_latency; /*!< SSR max latency */
+        uint16_t ssr_min_tout;    /*!< SSR min timeout */
+        uint8_t ctry_code;        /*!< Country Code */
+        uint16_t dl_len;          /*!< Device descriptor length */
+        uint8_t *dsc_list;        /*!< Device descriptor pointer */
+    } dscp;                       /*!< HIDH callback param of ESP_HIDH_GET_DSCP_EVT */
+
+    /**
+     * @brief ESP_HIDH_SET_INFO_EVT
+     */
+    struct hidh_set_info_evt_param {
+        esp_hidh_status_t status; /*!< operation status         */
+        uint8_t handle;           /*!< device handle            */
+        esp_bd_addr_t bd_addr;    /*!< device address           */
+    } set_info;                   /*!< HIDH callback param of ESP_HIDH_SET_INFO_EVT */
+} esp_hidh_cb_param_t;
+
+/**
+ * @brief       HID host callback function type
+ * @param       event:      Event type
+ * @param       param:      Point to callback parameter, currently is union type
+ */
+typedef void (esp_hh_cb_t)(esp_hidh_cb_event_t event, esp_hidh_cb_param_t *param);
+
+/**
+ * @brief       This function is called to init callbacks with HID host module.
+ *
+ * @param[in]   callback:   pointer to the init callback function.
+ *
+ * @return
+ *              - ESP_OK: success
+ *              - other: failed
+ */
+esp_err_t esp_bt_hid_host_register_callback(esp_hh_cb_t callback);
+
+/**
+ * @brief       This function initializes HID host. This function should be called after esp_bluedroid_enable() and
+ *              esp_blueroid_init() success, and should be called after esp_bt_hid_host_register_callback().
+ *              When the operation is complete the callback function will be called with ESP_HIDH_INIT_EVT.
+ *
+ * @return
+ *              - ESP_OK: success
+ *              - other: failed
+ */
+esp_err_t esp_bt_hid_host_init(void);
+
+/**
+ * @brief       Closes the interface. This function should be called after esp_bluedroid_enable() and
+ *              esp_blueroid_init() success, and should be called after esp_bt_hid_host_init().
+ *              When the operation is complete the callback function will be called with ESP_HIDH_DEINIT_EVT.
+ *
+ * @return      - ESP_OK: success
+ *              - other: failed
+ */
+esp_err_t esp_bt_hid_host_deinit(void);
+
+/**
+ * @brief       Connect to hid device. When the operation is complete the callback
+ *              function will be called with ESP_HIDH_OPEN_EVT.
+ *
+ * @param[in]   bd_addr:  Remote device bluetooth device address.
+ *
+ * @return      - ESP_OK: success
+ *              - other: failed
+ */
+esp_err_t esp_bt_hid_host_connect(esp_bd_addr_t bd_addr);
+
+/**
+ * @brief       Disconnect from hid device. When the operation is complete the callback
+ *              function will be called with ESP_HIDH_CLOSE_EVT.
+ *
+ * @param[in]   bd_addr:  Remote device bluetooth device address.
+ *
+ * @return      - ESP_OK: success
+ *              - other: failed
+ */
+esp_err_t esp_bt_hid_host_disconnect(esp_bd_addr_t bd_addr);
+
+/**
+ * @brief       Virtual UnPlug (VUP) the specified HID device. When the operation is complete the callback
+ *              function will be called with ESP_HIDH_VC_UNPLUG_EVT.
+ *
+ * @param[in]   bd_addr:  Remote device bluetooth device address.
+ *
+ * @return      - ESP_OK: success
+ *              - other: failed
+ */
+esp_err_t esp_bt_hid_host_virtual_cable_unplug(esp_bd_addr_t bd_addr);
+
+/**
+ * @brief       Set the HID device descriptor for the specified HID device. When the operation is complete the callback
+ *              function will be called with ESP_HIDH_SET_INFO_EVT.
+ *
+ * @param[in]   bd_addr:  Remote device bluetooth device address.
+ * @param[in]   hid_info:  HID device descriptor structure.
+ *
+ * @return      - ESP_OK: success
+ *              - other: failed
+ */
+esp_err_t esp_bt_hid_host_set_info(esp_bd_addr_t bd_addr, esp_hidh_hid_info_t *hid_info);
+
+/**
+ * @brief       Get the HID proto mode. When the operation is complete the callback
+ *              function will be called with ESP_HIDH_GET_PROTO_EVT.
+ *
+ * @param[in]   bd_addr:  Remote device bluetooth device address.
+ *
+ * @return
+ *              - ESP_OK: success
+ *              - other: failed
+ */
+esp_err_t esp_bt_hid_host_get_protocol(esp_bd_addr_t bd_addr);
+
+/**
+ * @brief       Set the HID proto mode. When the operation is complete the callback
+ *              function will be called with ESP_HIDH_SET_PROTO_EVT.
+ *
+ * @param[in]   bd_addr:  Remote device bluetooth device address.
+ * @param[in]   protocol_mode:  Protocol mode type.
+ *
+ * @return
+ *              - ESP_OK: success
+ *              - other: failed
+ */
+esp_err_t esp_bt_hid_host_set_protocol(esp_bd_addr_t bd_addr, esp_hidh_protocol_mode_t protocol_mode);
+
+/**
+ * @brief       Get the HID Idle Time. When the operation is complete the callback
+ *              function will be called with ESP_HIDH_GET_IDLE_EVT.
+ *
+ * @param[in]   bd_addr:  Remote device bluetooth device address.
+ *
+ * @return
+ *              - ESP_OK: success
+ *              - other: failed
+ */
+esp_err_t esp_bt_hid_host_get_idle(esp_bd_addr_t bd_addr);
+
+/**
+ * @brief       Set the HID Idle Time. When the operation is complete the callback
+ *              function will be called with ESP_HIDH_SET_IDLE_EVT.
+ *
+ * @param[in]   bd_addr:  Remote device bluetooth device address.
+ * @param[in]   idle_time:  Idle time rate
+ *
+ * @return    - ESP_OK: success
+ *            - other: failed
+ */
+esp_err_t esp_bt_hid_host_set_idle(esp_bd_addr_t bd_addr, uint16_t idle_time);
+
+/**
+ * @brief       Send a GET_REPORT to HID device. When the operation is complete the callback
+ *              function will be called with ESP_HIDH_GET_RPT_EVT.
+ *
+ * @param[in]   bd_addr:  Remote device bluetooth device address.
+ * @param[in]   report_type:  Report type
+ * @param[in]   report_id:  Report id
+ * @param[in]   buffer_size:  Buffer size
+ *
+ * @return      - ESP_OK: success
+ *              - other: failed
+ */
+esp_err_t esp_bt_hid_host_get_report(esp_bd_addr_t bd_addr, esp_hidh_report_type_t report_type, uint8_t report_id,
+                                     int buffer_size);
+
+/**
+ * @brief       Send a SET_REPORT to HID device. When the operation is complete the callback
+ *              function will be called with ESP_HIDH_SET_RPT_EVT.
+ *
+ * @param[in]   bd_addr:  Remote device bluetooth device address.
+ * @param[in]   report_type:  Report type
+ * @param[in]   report:  Report data pointer
+ * @param[in]   len:  Report data length
+ *
+ * @return      - ESP_OK: success
+ *              - other: failed
+ */
+esp_err_t esp_bt_hid_host_set_report(esp_bd_addr_t bd_addr, esp_hidh_report_type_t report_type, uint8_t *report,
+                                     size_t len);
+
+/**
+ * @brief       Send data to HID device. When the operation is complete the callback
+ *              function will be called with ESP_HIDH_DATA_EVT.
+ *
+ * @param[in]   bd_addr:  Remote device bluetooth device address.
+ * @param[in]   data:  Data pointer
+ * @param[in]   len:  Data length
+ *
+ * @return      - ESP_OK: success
+ *              - other: failed
+ */
+esp_err_t esp_bt_hid_host_send_data(esp_bd_addr_t bd_addr, uint8_t *data, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 29 - 9
components/bt/host/bluedroid/bta/dm/bta_dm_act.c

@@ -126,7 +126,7 @@ static void bta_dm_ctrl_features_rd_cmpl_cback(tBTM_STATUS result);
 #endif
 #endif
 #if (SMP_INCLUDED == TRUE)
-static void bta_dm_remove_sec_dev_entry(BD_ADDR remote_bd_addr);
+static BOOLEAN bta_dm_remove_sec_dev_entry(BD_ADDR remote_bd_addr);
 #endif  ///SMP_INCLUDED == TRUE
 #if (BLE_INCLUDED == TRUE)
 static void bta_dm_observe_results_cb(tBTM_INQ_RESULTS *p_inq, UINT8 *p_eir);
@@ -3069,7 +3069,9 @@ static UINT8 bta_dm_authentication_complete_cback(BD_ADDR bd_addr, DEV_CLASS dev
             bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event);
         }
 
-        bta_dm_remove_sec_dev_entry(bd_addr);
+        if (bta_dm_remove_sec_dev_entry(bd_addr)) {
+            return BTM_SEC_DEV_REC_REMOVED;
+        }
     }
 
     return BTM_SUCCESS;
@@ -3740,12 +3742,13 @@ static void bta_dm_delay_role_switch_cback(TIMER_LIST_ENT *p_tle)
 **                  remtoe device does not exist, else schedule for dev entry removal upon
                      ACL close
 **
-** Returns          void
+** Returns          TRUE if device entry is removed from Security device DB, FALSE otherwise
 **
 *******************************************************************************/
 #if (SMP_INCLUDED == TRUE)
-static void bta_dm_remove_sec_dev_entry(BD_ADDR remote_bd_addr)
+static BOOLEAN bta_dm_remove_sec_dev_entry(BD_ADDR remote_bd_addr)
 {
+    BOOLEAN is_device_deleted = FALSE;
     UINT16 index = 0;
     if ( BTM_IsAclConnectionUp(remote_bd_addr, BT_TRANSPORT_LE) ||
             BTM_IsAclConnectionUp(remote_bd_addr, BT_TRANSPORT_BR_EDR)) {
@@ -3763,7 +3766,7 @@ static void bta_dm_remove_sec_dev_entry(BD_ADDR remote_bd_addr)
             APPL_TRACE_ERROR(" %s Device does not exist in DB", __FUNCTION__);
         }
     } else {
-        BTM_SecDeleteDevice (remote_bd_addr, bta_dm_cb.device_list.peer_device[index].transport);
+        is_device_deleted = BTM_SecDeleteDevice (remote_bd_addr, bta_dm_cb.device_list.peer_device[index].transport);
 #if (BLE_INCLUDED == TRUE && GATTC_INCLUDED == TRUE)
         /* need to remove all pending background connection */
         BTA_GATTC_CancelOpen(0, remote_bd_addr, FALSE);
@@ -3771,6 +3774,7 @@ static void bta_dm_remove_sec_dev_entry(BD_ADDR remote_bd_addr)
         BTA_GATTC_Refresh(remote_bd_addr, false);
 #endif
     }
+    return is_device_deleted;
 }
 #endif  ///SMP_INCLUDED == TRUE
 
@@ -3835,7 +3839,10 @@ static void bta_dm_adjust_roles(BOOLEAN delay_role_switch)
                     } else {
                         bta_dm_cb.switch_delay_timer[i].p_cback =
                             (TIMER_CBACK *)&bta_dm_delay_role_switch_cback;
-                        bta_sys_start_timer(&bta_dm_cb.switch_delay_timer[i], 0, 500);
+                        /* Start the timer if not active */
+                        if (!bta_sys_timer_is_active(&bta_dm_cb.switch_delay_timer[i])) {
+                            bta_sys_start_timer(&bta_dm_cb.switch_delay_timer[i], 0, 500);
+                        }
                     }
                 }
 
@@ -4495,6 +4502,22 @@ void bta_dm_set_encryption (tBTA_DM_MSG *p_data)
 }
 #endif  ///SMP_INCLUDED == TRUE
 
+#if (BTA_HD_INCLUDED == TRUE)
+BOOLEAN bta_dm_check_if_only_hd_connected(BD_ADDR peer_addr)
+{
+    APPL_TRACE_DEBUG("%s: count(%d)", __func__, bta_dm_conn_srvcs.count);
+    for (uint8_t j = 0; j < bta_dm_conn_srvcs.count; j++) {
+        // Check if profiles other than hid are connected
+        if ((bta_dm_conn_srvcs.conn_srvc[j].id != BTA_ID_HD) &&
+            !bdcmp(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr, peer_addr)) {
+            APPL_TRACE_DEBUG("%s: Another profile (id=%d) is connected", __func__, bta_dm_conn_srvcs.conn_srvc[j].id);
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+#endif /* BTA_HD_INCLUDED == TRUE */
+
 #if (BLE_INCLUDED == TRUE)
 /*******************************************************************************
 **
@@ -4975,9 +4998,6 @@ void bta_dm_ble_update_conn_params (tBTA_DM_MSG *p_data)
                                   p_data->ble_update_conn_params.latency,
                                   p_data->ble_update_conn_params.timeout)) {
         APPL_TRACE_ERROR("Update connection parameters failed!");
-    } else {
-        BTM_BleConfigConnParams(p_data->ble_update_conn_params.min_int, p_data->ble_update_conn_params.max_int,
-            p_data->ble_update_conn_params.latency, p_data->ble_update_conn_params.timeout);
     }
 }
 /*******************************************************************************

+ 49 - 9
components/bt/host/bluedroid/bta/dm/bta_dm_cfg.c

@@ -117,11 +117,11 @@ tBTA_DM_CFG *const p_bta_dm_cfg = (tBTA_DM_CFG *) &bta_dm_cfg;
 tBTA_DM_RM *const p_bta_dm_rm_cfg = (tBTA_DM_RM *) &bta_dm_rm_cfg;
 
 #if BLE_INCLUDED == TRUE
+#  define BTA_DM_NUM_PM_ENTRY         10  /* number of entries in bta_dm_pm_cfg except the first */
+#  define BTA_DM_NUM_PM_SPEC          10  /* number of entries in bta_dm_pm_spec */
+#else
 #  define BTA_DM_NUM_PM_ENTRY         8  /* number of entries in bta_dm_pm_cfg except the first */
 #  define BTA_DM_NUM_PM_SPEC          8  /* number of entries in bta_dm_pm_spec */
-#else
-#  define BTA_DM_NUM_PM_ENTRY         6  /* number of entries in bta_dm_pm_cfg except the first */
-#  define BTA_DM_NUM_PM_SPEC          6  /* number of entries in bta_dm_pm_spec */
 #endif
 
 #if (BTA_DM_PM_INCLUDED == TRUE)
@@ -133,10 +133,12 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_CFG bta_dm_pm_cfg[BTA_DM_NUM_PM_ENTRY + 1]
     {BTA_ID_JV,  BTA_APP_ID_1,        2},  /* app BTA_JV_PM_ID_1, reuse ftc spec table */
     {BTA_ID_JV,  BTA_ALL_APP_ID,      3},  /* reuse fts spec table */
     {BTA_ID_HS,  BTA_ALL_APP_ID,      4},  /* HS spec table */
-    {BTA_ID_AVK, BTA_ALL_APP_ID,      5}   /* avk spec table */
+    {BTA_ID_AVK, BTA_ALL_APP_ID,      5},  /* avk spec table */
+    {BTA_ID_HD,  BTA_ALL_APP_ID,      6},  /* hd spec table */
+    {BTA_ID_HH,  BTA_ALL_APP_ID,      7}   /* hh spec table */
 #if BLE_INCLUDED == TRUE
-    , {BTA_ID_GATTC,  BTA_ALL_APP_ID,   6} /* gattc spec table */
-    , {BTA_ID_GATTS,  BTA_ALL_APP_ID,   7} /* gatts spec table */
+    , {BTA_ID_GATTC,  BTA_ALL_APP_ID,   8} /* gattc spec table */
+    , {BTA_ID_GATTS,  BTA_ALL_APP_ID,   9} /* gatts spec table */
 #endif
 };
 
@@ -254,10 +256,48 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = {
             {{BTA_DM_PM_ACTIVE,    0},   {BTA_DM_PM_NO_ACTION, 0}},    /* busy */
             {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}}     /* mode change retry */
         }
+    },
+
+    /* HD : 6 */
+    {
+        (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK),                            /* allow park & sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+        (BTA_DM_PM_SSR3),                                              /* the SSR entry */
+#endif
+        {
+            {{BTA_DM_PM_SNIFF_HD_ACTIVE_IDX, 5000 + BTA_DM_PM_SPEC_TO_OFFSET},   {BTA_DM_PM_NO_ACTION, 0}},   /* conn open sniff */
+            {{BTA_DM_PM_NO_PREF,   0},   {BTA_DM_PM_NO_ACTION, 0}},    /* conn close */
+            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* app open */
+            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* app close */
+            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* sco open  */
+            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* sco close */
+            {{BTA_DM_PM_SNIFF_HD_IDLE_IDX,   5000 + BTA_DM_PM_SPEC_TO_OFFSET},   {BTA_DM_PM_NO_ACTION, 0}},   /* idle */
+            {{BTA_DM_PM_SNIFF_HD_ACTIVE_IDX, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* busy */
+            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}}     /* mode change retry */
+        }
+    },
+
+    /* HH : 7 */
+    {
+        (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK),                            /* allow park & sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+        (BTA_DM_PM_SSR1),                                              /* the SSR entry */
+#endif
+        {
+            {{BTA_DM_PM_SNIFF_HH_OPEN_IDX, BTA_DM_PM_HH_OPEN_DELAY + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}},   /* conn open  sniff */
+            {{BTA_DM_PM_NO_PREF,   0},   {BTA_DM_PM_NO_ACTION, 0}},    /* conn close  */
+            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* app open */
+            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* app close */
+            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* sco open  */
+            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},    /* sco close, used for HH suspend   */
+            {{BTA_DM_PM_SNIFF_HH_IDLE_IDX, BTA_DM_PM_HH_IDLE_DELAY + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}},   /* idle */
+            {{BTA_DM_PM_SNIFF_HH_ACTIVE_IDX, BTA_DM_PM_HH_ACTIVE_DELAY + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}},   /* busy */
+            {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}}     /* mode change retry */
+        }
     }
 
 #if BLE_INCLUDED == TRUE
-    /* GATTC : 6 */
+    /* GATTC : 8 */
     , {
         (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK),                           /* allow park & sniff */
 #if (BTM_SSR_INCLUDED == TRUE)
@@ -278,7 +318,7 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = {
             {{BTA_DM_PM_RETRY,   5000 + BTA_DM_PM_SPEC_TO_OFFSET},   {BTA_DM_PM_NO_ACTION, 0}}    /* mode change retry */
         }
     }
-    /* GATTS : 7 */
+    /* GATTS : 9 */
     , {
         (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK),                           /* allow park & sniff */
 #if (BTM_SSR_INCLUDED == TRUE)
@@ -372,7 +412,7 @@ tBTA_DM_SSR_SPEC bta_dm_ssr_spec[] = {
                            seting default max latency and min remote timeout as 0,
                            and always read individual device preference from HH module */
     {1200,   2, 2},     /* BTA_DM_PM_SSR2 - others (as long as sniff is allowed)*/
-    {360,  160, 2}      /* BTA_DM_PM_SSR3 - HD */
+    {360,  160, 1600}   /* BTA_DM_PM_SSR3 - HD */
 };
 
 tBTA_DM_SSR_SPEC *const p_bta_dm_ssr_spec = (tBTA_DM_SSR_SPEC *) &bta_dm_ssr_spec;

+ 6 - 0
components/bt/host/bluedroid/bta/dm/include/bta_dm_int.h

@@ -26,6 +26,7 @@
 
 #include "common/bt_target.h"
 #include "freertos/semphr.h"
+#include "bta/bta_sys.h"
 #if (BLE_INCLUDED == TRUE && (defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE))
 #include "bta/bta_gatt_api.h"
 #endif
@@ -1596,6 +1597,11 @@ extern void bta_dm_ble_get_energy_info(tBTA_DM_MSG *p_data);
 extern void bta_dm_set_encryption(tBTA_DM_MSG *p_data);
 extern void bta_dm_confirm(tBTA_DM_MSG *p_data);
 extern void bta_dm_key_req(tBTA_DM_MSG *p_data);
+
+#if (BTA_HD_INCLUDED == TRUE)
+extern BOOLEAN bta_dm_check_if_only_hd_connected(BD_ADDR peer_addr);
+#endif /* BTA_HD_INCLUDED */
+
 #if (BTM_OOB_INCLUDED == TRUE)
 extern void bta_dm_loc_oob(tBTA_DM_MSG *p_data);
 extern void bta_dm_oob_reply(tBTA_DM_MSG *p_data);

+ 5 - 1
components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c

@@ -35,6 +35,7 @@
 #include "gatt_int.h"
 #include "osi/allocator.h"
 #include "osi/mutex.h"
+#include "bta_hh_int.h"
 
 #if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
 #include "bta_hh_int.h"
@@ -304,7 +305,10 @@ void bta_gattc_deregister(tBTA_GATTC_CB *p_cb, tBTA_GATTC_RCB  *p_clreg)
             bta_gattc_deregister_cmpl(p_clreg);
         }
     } else {
-        APPL_TRACE_ERROR("bta_gattc_deregister Deregister Failedm unknown client cif");
+        APPL_TRACE_ERROR("Deregister Failed unknown client cif");
+#if defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE)
+        bta_hh_cleanup_disable(BTA_HH_OK);
+#endif
     }
 }
 /*******************************************************************************

+ 774 - 0
components/bt/host/bluedroid/bta/hd/bta_hd_act.c

@@ -0,0 +1,774 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *  Copyright (C) 2005-2012 Broadcom Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+/******************************************************************************
+ *
+ *  This file contains the HID device action functions.
+ *
+ ******************************************************************************/
+#include "common/bt_target.h"
+
+#if defined(BTA_HD_INCLUDED) && (BTA_HD_INCLUDED == TRUE)
+
+#include "bta/bta_sys.h"
+#include "bta_hd_int.h"
+#include "osi/allocator.h"
+#include "osi/osi.h"
+#include "stack/btm_api.h"
+#include <string.h>
+
+static void bta_hd_cback(BD_ADDR bd_addr, uint8_t event, uint32_t data, BT_HDR *pdata);
+
+static bool check_descriptor(uint8_t *data, uint16_t length, bool *has_report_id)
+{
+    uint8_t *ptr = data;
+    *has_report_id = FALSE;
+    while (ptr < data + length) {
+        uint8_t item = *ptr++;
+        switch (item) {
+        case 0xfe: // long item indicator
+            if (ptr < data + length) {
+                ptr += ((*ptr) + 2);
+            } else {
+                return false;
+            }
+            break;
+        case 0x85: // Report ID
+            *has_report_id = TRUE;
+        default:
+            ptr += (item & 0x03);
+            break;
+        }
+    }
+    return (ptr == data + length);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_api_enable
+ *
+ * Description      Enables HID device
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hd_api_enable(tBTA_HD_DATA *p_data)
+{
+    tBTA_HD_STATUS status = BTA_HD_ERROR;
+    tHID_STATUS ret;
+
+    APPL_TRACE_API("%s", __func__);
+
+    HID_DevInit();
+
+    memset(&bta_hd_cb, 0, sizeof(tBTA_HD_CB));
+
+    HID_DevSetSecurityLevel(BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+    /* store parameters */
+    bta_hd_cb.p_cback = p_data->api_enable.p_cback;
+
+    ret = HID_DevRegister(bta_hd_cback);
+    if (ret == HID_SUCCESS) {
+        status = BTA_HD_OK;
+    } else {
+        APPL_TRACE_ERROR("%s: Failed to register HID device (%d)", __func__, ret);
+    }
+
+    /* signal BTA call back event */
+    (*bta_hd_cb.p_cback)(BTA_HD_ENABLE_EVT, (tBTA_HD *)&status);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_api_disable
+ *
+ * Description      Disables HID device
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hd_api_disable(void)
+{
+    tBTA_HD_STATUS status = BTA_HD_ERROR;
+    tHID_STATUS ret;
+
+    APPL_TRACE_API("%s", __func__);
+
+    /* service is not enabled */
+    if (bta_hd_cb.p_cback == NULL)
+        return;
+
+    /* Remove service record */
+    if (bta_hd_cb.sdp_handle != 0) {
+        SDP_DeleteRecord(bta_hd_cb.sdp_handle);
+        bta_sys_remove_uuid(UUID_SERVCLASS_HUMAN_INTERFACE);
+    }
+
+    /* Deregister with lower layer */
+    ret = HID_DevDeregister();
+    if (ret == HID_SUCCESS) {
+        status = BTA_HD_OK;
+    } else {
+        APPL_TRACE_ERROR("%s: Failed to deregister HID device (%d)", __func__, ret);
+    }
+
+    (*bta_hd_cb.p_cback)(BTA_HD_DISABLE_EVT, (tBTA_HD *)&status);
+
+    memset(&bta_hd_cb, 0, sizeof(tBTA_HD_CB));
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_register_act
+ *
+ * Description      Registers SDP record
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hd_register_act(tBTA_HD_DATA *p_data)
+{
+    tBTA_HD ret;
+    tBTA_HD_REGISTER_APP *p_app_data = (tBTA_HD_REGISTER_APP *)p_data;
+    bool use_report_id = FALSE;
+
+    APPL_TRACE_API("%s", __func__);
+
+    ret.reg_status.in_use = FALSE;
+
+    /* Check if len doesn't exceed BTA_HD_APP_DESCRIPTOR_LEN and descriptor
+     * itself is well-formed. Also check if descriptor has Report Id item so we
+     * know if report will have prefix or not. */
+    if (p_app_data->d_len > BTA_HD_APP_DESCRIPTOR_LEN ||
+        !check_descriptor(p_app_data->d_data, p_app_data->d_len, &use_report_id)) {
+        APPL_TRACE_ERROR("%s: Descriptor is too long or malformed", __func__);
+        ret.reg_status.status = BTA_HD_ERROR;
+        (*bta_hd_cb.p_cback)(BTA_HD_REGISTER_APP_EVT, &ret);
+        return;
+    }
+
+    ret.reg_status.status = BTA_HD_OK;
+
+    /* Remove old record if for some reason it's already registered */
+    if (bta_hd_cb.sdp_handle != 0) {
+        SDP_DeleteRecord(bta_hd_cb.sdp_handle);
+    }
+
+    bta_hd_cb.use_report_id = use_report_id;
+    bta_hd_cb.sdp_handle = SDP_CreateRecord();
+    HID_DevAddRecord(bta_hd_cb.sdp_handle, p_app_data->name, p_app_data->description, p_app_data->provider,
+                     p_app_data->subclass, p_app_data->d_len, p_app_data->d_data);
+    bta_sys_add_uuid(UUID_SERVCLASS_HUMAN_INTERFACE);
+
+    HID_DevSetIncomingQos(p_app_data->in_qos.service_type, p_app_data->in_qos.token_rate,
+                          p_app_data->in_qos.token_bucket_size, p_app_data->in_qos.peak_bandwidth,
+                          p_app_data->in_qos.access_latency, p_app_data->in_qos.delay_variation);
+
+    HID_DevSetOutgoingQos(p_app_data->out_qos.service_type, p_app_data->out_qos.token_rate,
+                          p_app_data->out_qos.token_bucket_size, p_app_data->out_qos.peak_bandwidth,
+                          p_app_data->out_qos.access_latency, p_app_data->out_qos.delay_variation);
+
+    // application is registered so we can accept incoming connections
+    HID_DevSetIncomingPolicy(TRUE);
+
+    if (HID_DevGetDevice(&ret.reg_status.bda) == HID_SUCCESS) {
+        ret.reg_status.in_use = TRUE;
+    }
+
+    (*bta_hd_cb.p_cback)(BTA_HD_REGISTER_APP_EVT, &ret);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_unregister_act
+ *
+ * Description      Unregisters SDP record
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hd_unregister_act(UNUSED_ATTR tBTA_HD_DATA *p_data)
+{
+    tBTA_HD_STATUS status = BTA_HD_OK;
+
+    APPL_TRACE_API("%s", __func__);
+
+    // application is no longer registered so we do not want incoming connections
+    HID_DevSetIncomingPolicy(FALSE);
+
+    if (bta_hd_cb.sdp_handle != 0) {
+        SDP_DeleteRecord(bta_hd_cb.sdp_handle);
+    }
+
+    bta_hd_cb.sdp_handle = 0;
+    bta_sys_remove_uuid(UUID_SERVCLASS_HUMAN_INTERFACE);
+
+    (*bta_hd_cb.p_cback)(BTA_HD_UNREGISTER_APP_EVT, (tBTA_HD *)&status);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_unregister2_act
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hd_unregister2_act(tBTA_HD_DATA *p_data)
+{
+    APPL_TRACE_API("%s", __func__);
+
+    // close first
+    bta_hd_close_act(p_data);
+
+    // then unregister
+    bta_hd_unregister_act(p_data);
+
+    if (bta_hd_cb.disable_w4_close) {
+        bta_hd_api_disable();
+    }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_connect_act
+ *
+ * Description      Connect to device (must be virtually plugged)
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_connect_act(tBTA_HD_DATA *p_data)
+{
+    tHID_STATUS ret;
+    tBTA_HD_DEVICE_CTRL *p_ctrl = (tBTA_HD_DEVICE_CTRL *)p_data;
+    tBTA_HD cback_data;
+
+    APPL_TRACE_API("%s", __func__);
+    do {
+        ret = HID_DevPlugDevice(p_ctrl->addr);
+        if (ret != HID_SUCCESS) {
+            APPL_TRACE_WARNING("%s: HID_DevPlugDevice returned %d", __func__, ret);
+            return;
+        }
+
+        ret = HID_DevConnect();
+        if (ret != HID_SUCCESS) {
+            APPL_TRACE_WARNING("%s: HID_DevConnect returned %d", __func__, ret);
+            return;
+        }
+    } while (0);
+
+    bdcpy(cback_data.conn.bda, p_ctrl->addr);
+    cback_data.conn.status = (ret == HID_SUCCESS ? BTA_HD_OK : BTA_HD_ERROR);
+    cback_data.conn.conn_status = BTA_HD_CONN_STATE_CONNECTING;
+    bta_hd_cb.p_cback(BTA_HD_OPEN_EVT, &cback_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_disconnect_act
+ *
+ * Description      Disconnect from device
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_disconnect_act(UNUSED_ATTR tBTA_HD_DATA *p_data)
+{
+    tHID_STATUS ret;
+    tBTA_HD cback_data;
+
+    APPL_TRACE_API("%s", __func__);
+
+    ret = HID_DevDisconnect();
+
+    if (ret != HID_SUCCESS) {
+        APPL_TRACE_WARNING("%s: HID_DevDisconnect returned %d", __func__, ret);
+        return;
+    }
+
+    if (HID_DevGetDevice(&cback_data.conn.bda) == HID_SUCCESS) {
+        cback_data.conn.status = BTA_HD_OK;
+        cback_data.conn.conn_status = BTA_HD_CONN_STATE_DISCONNECTING;
+        bta_hd_cb.p_cback(BTA_HD_CLOSE_EVT, &cback_data);
+    }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_add_device_act
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_add_device_act(tBTA_HD_DATA *p_data)
+{
+    tBTA_HD_DEVICE_CTRL *p_ctrl = (tBTA_HD_DEVICE_CTRL *)p_data;
+
+    APPL_TRACE_API("%s", __func__);
+
+    HID_DevPlugDevice(p_ctrl->addr);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_remove_device_act
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_remove_device_act(tBTA_HD_DATA *p_data)
+{
+    tBTA_HD_DEVICE_CTRL *p_ctrl = (tBTA_HD_DEVICE_CTRL *)p_data;
+
+    APPL_TRACE_API("%s", __func__);
+
+    HID_DevUnplugDevice(p_ctrl->addr);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_send_report_act
+ *
+ * Description      Sends report
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_send_report_act(tBTA_HD_DATA *p_data)
+{
+    tBTA_HD_SEND_REPORT *p_report = (tBTA_HD_SEND_REPORT *)p_data;
+    uint8_t channel;
+    uint8_t report_id;
+    tBTA_HD cback_data;
+    tHID_STATUS ret;
+
+    APPL_TRACE_VERBOSE("%s", __func__);
+
+    channel = p_report->use_intr ? HID_CHANNEL_INTR : HID_CHANNEL_CTRL;
+    report_id = (bta_hd_cb.use_report_id || bta_hd_cb.boot_mode) ? p_report->id : 0x00;
+
+    ret = HID_DevSendReport(channel, p_report->type, report_id, p_report->len, p_report->data);
+
+    /* trigger PM */
+    bta_sys_busy(BTA_ID_HD, 1, bta_hd_cb.bd_addr);
+    bta_sys_idle(BTA_ID_HD, 1, bta_hd_cb.bd_addr);
+
+    cback_data.send_report.status = (ret == HID_SUCCESS ? BTA_HD_OK : BTA_HD_ERROR);
+    cback_data.send_report.reason = ret;
+    cback_data.send_report.report_id = report_id;
+    cback_data.send_report.report_type = p_report->type;
+    bta_hd_cb.p_cback(BTA_HD_SEND_REPORT_EVT, &cback_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_report_error_act
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_report_error_act(tBTA_HD_DATA *p_data)
+{
+    tBTA_HD_REPORT_ERR *p_report = (tBTA_HD_REPORT_ERR *)p_data;
+    tHID_STATUS ret;
+    tBTA_HD cback_data;
+
+    APPL_TRACE_API("%s: error = %d", __func__, p_report->error);
+
+    ret = HID_DevReportError(p_report->error);
+
+    if (ret != HID_SUCCESS) {
+        APPL_TRACE_WARNING("%s: HID_DevReportError returned %d", __func__, ret);
+    }
+
+    cback_data.report_err.status = (ret == HID_SUCCESS ? BTA_HD_OK : BTA_HD_ERROR);
+    cback_data.report_err.reason = ret;
+    bta_hd_cb.p_cback(BTA_HD_REPORT_ERR_EVT, &cback_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_vc_unplug_act
+ *
+ * Description      Sends Virtual Cable Unplug
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_vc_unplug_act(UNUSED_ATTR tBTA_HD_DATA *p_data)
+{
+    tHID_STATUS ret;
+
+    APPL_TRACE_API("%s", __func__);
+
+    bta_hd_cb.vc_unplug = TRUE;
+    ret = HID_DevVirtualCableUnplug();
+
+    if (ret != HID_SUCCESS) {
+        APPL_TRACE_WARNING("%s: HID_DevVirtualCableUnplug returned %d", __func__, ret);
+    }
+
+    /* trigger PM */
+    bta_sys_busy(BTA_ID_HD, 1, bta_hd_cb.bd_addr);
+    bta_sys_idle(BTA_ID_HD, 1, bta_hd_cb.bd_addr);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_open_act
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_open_act(tBTA_HD_DATA *p_data)
+{
+    tBTA_HD_CBACK_DATA *p_cback = (tBTA_HD_CBACK_DATA *)p_data;
+    tBTA_HD cback_data;
+
+    APPL_TRACE_API("%s", __func__);
+
+    HID_DevPlugDevice(p_cback->addr);
+    bta_sys_conn_open(BTA_ID_HD, 1, p_cback->addr);
+
+    bdcpy(cback_data.conn.bda, p_cback->addr);
+    bdcpy(bta_hd_cb.bd_addr, p_cback->addr);
+    cback_data.conn.status = BTA_HD_OK;
+    cback_data.conn.conn_status = BTA_HD_CONN_STATE_CONNECTED;
+    bta_hd_cb.p_cback(BTA_HD_OPEN_EVT, &cback_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_close_act
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_close_act(tBTA_HD_DATA *p_data)
+{
+    tBTA_HD_CBACK_DATA *p_cback = (tBTA_HD_CBACK_DATA *)p_data;
+    tBTA_HD cback_data;
+    tBTA_HD_EVT cback_event = BTA_HD_CLOSE_EVT;
+
+    APPL_TRACE_API("%s", __func__);
+
+    bta_sys_conn_close(BTA_ID_HD, 1, p_cback->addr);
+
+    if (bta_hd_cb.vc_unplug) {
+        bta_hd_cb.vc_unplug = FALSE;
+        HID_DevUnplugDevice(p_cback->addr);
+        cback_event = BTA_HD_VC_UNPLUG_EVT;
+    }
+
+    bdcpy(cback_data.conn.bda, p_cback->addr);
+    memset(bta_hd_cb.bd_addr, 0, sizeof(BD_ADDR));
+    cback_data.conn.status = BTA_HD_OK;
+    cback_data.conn.conn_status = BTA_HD_CONN_STATE_DISCONNECTED;
+    bta_hd_cb.p_cback(cback_event, &cback_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_intr_data_act
+ *
+ * Description      Handles incoming DATA request on intr
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_intr_data_act(tBTA_HD_DATA *p_data)
+{
+    tBTA_HD_CBACK_DATA *p_cback = (tBTA_HD_CBACK_DATA *)p_data;
+    BT_HDR *p_msg = p_cback->p_data;
+    uint16_t len = p_msg->len;
+    uint8_t *p_buf = (uint8_t *)(p_msg + 1) + p_msg->offset;
+    tBTA_HD_INTR_DATA ret;
+
+    APPL_TRACE_API("%s", __func__);
+
+    if (bta_hd_cb.use_report_id || bta_hd_cb.boot_mode) {
+        ret.report_id = *p_buf;
+        len--;
+        p_buf++;
+    } else {
+        ret.report_id = 0;
+    }
+
+    ret.len = len;
+    ret.p_data = p_buf;
+    (*bta_hd_cb.p_cback)(BTA_HD_INTR_DATA_EVT, (tBTA_HD *)&ret);
+    if (p_msg) {
+        osi_free(p_msg);
+    }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_get_report_act
+ *
+ * Description      Handles incoming GET_REPORT request
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_get_report_act(tBTA_HD_DATA *p_data)
+{
+    tBTA_HD_CBACK_DATA *p_cback = (tBTA_HD_CBACK_DATA *)p_data;
+    bool rep_size_follows = p_cback->data;
+    BT_HDR *p_msg = p_cback->p_data;
+    uint8_t *p_buf = (uint8_t *)(p_msg + 1) + p_msg->offset;
+    tBTA_HD_GET_REPORT ret = {0, 0, 0};
+    uint16_t remaining_len = p_msg->len;
+
+    APPL_TRACE_API("%s", __func__);
+    if (remaining_len < 1) {
+        APPL_TRACE_ERROR("%s invalid data, remaining_len:%d", __func__, remaining_len);
+        return;
+    }
+
+    ret.report_type = *p_buf & HID_PAR_REP_TYPE_MASK;
+    p_buf++;
+    remaining_len--;
+
+    if (bta_hd_cb.use_report_id) {
+        if (remaining_len < 1) {
+            APPL_TRACE_ERROR("%s invalid data, remaining_len:%d", __func__, remaining_len);
+            return;
+        }
+        ret.report_id = *p_buf;
+        p_buf++;
+        remaining_len--;
+    }
+
+    if (rep_size_follows) {
+        if (remaining_len < 2) {
+            APPL_TRACE_ERROR("%s invalid data, remaining_len:%d", __func__, remaining_len);
+            return;
+        }
+        ret.buffer_size = *p_buf | (*(p_buf + 1) << 8);
+    }
+
+    (*bta_hd_cb.p_cback)(BTA_HD_GET_REPORT_EVT, (tBTA_HD *)&ret);
+    if (p_msg) {
+        osi_free(p_msg);
+    }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_set_report_act
+ *
+ * Description      Handles incoming SET_REPORT request
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_set_report_act(tBTA_HD_DATA *p_data)
+{
+    tBTA_HD_CBACK_DATA *p_cback = (tBTA_HD_CBACK_DATA *)p_data;
+    BT_HDR *p_msg = p_cback->p_data;
+    uint16_t len = p_msg->len;
+    uint8_t *p_buf = (uint8_t *)(p_msg + 1) + p_msg->offset;
+    tBTA_HD_SET_REPORT ret = {0, 0, 0, NULL};
+
+    APPL_TRACE_API("%s", __func__);
+
+    ret.report_type = *p_buf & HID_PAR_REP_TYPE_MASK;
+    p_buf++;
+    len--;
+
+    if (bta_hd_cb.use_report_id || bta_hd_cb.boot_mode) {
+        ret.report_id = *p_buf;
+        len--;
+        p_buf++;
+    } else {
+        ret.report_id = 0;
+    }
+
+    ret.len = len;
+    ret.p_data = p_buf;
+    (*bta_hd_cb.p_cback)(BTA_HD_SET_REPORT_EVT, (tBTA_HD *)&ret);
+    if (p_msg) {
+        osi_free(p_msg);
+    }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_set_protocol_act
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_set_protocol_act(tBTA_HD_DATA *p_data)
+{
+    tBTA_HD_CBACK_DATA *p_cback = (tBTA_HD_CBACK_DATA *)p_data;
+    tBTA_HD cback_data;
+
+    APPL_TRACE_API("%s", __func__);
+
+    bta_hd_cb.boot_mode = (p_cback->data == HID_PAR_PROTOCOL_BOOT_MODE);
+    cback_data.set_protocol = p_cback->data;
+
+    (*bta_hd_cb.p_cback)(BTA_HD_SET_PROTOCOL_EVT, &cback_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_vc_unplug_done_act
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_vc_unplug_done_act(tBTA_HD_DATA *p_data)
+{
+    tBTA_HD_CBACK_DATA *p_cback = (tBTA_HD_CBACK_DATA *)p_data;
+    tBTA_HD cback_data;
+
+    APPL_TRACE_API("%s", __func__);
+
+    bta_sys_conn_close(BTA_ID_HD, 1, p_cback->addr);
+
+    HID_DevUnplugDevice(p_cback->addr);
+
+    bdcpy(cback_data.conn.bda, p_cback->addr);
+    bdcpy(bta_hd_cb.bd_addr, p_cback->addr);
+    cback_data.conn.status = BTA_HD_OK;
+    cback_data.conn.conn_status = BTA_HD_CONN_STATE_DISCONNECTED;
+    (*bta_hd_cb.p_cback)(BTA_HD_VC_UNPLUG_EVT, &cback_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_suspend_act
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_suspend_act(tBTA_HD_DATA *p_data)
+{
+    tBTA_HD_CBACK_DATA *p_cback = (tBTA_HD_CBACK_DATA *)p_data;
+
+    APPL_TRACE_API("%s", __func__);
+
+    bta_sys_idle(BTA_ID_HD, 1, p_cback->addr);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_exit_suspend_act
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_exit_suspend_act(tBTA_HD_DATA *p_data)
+{
+    tBTA_HD_CBACK_DATA *p_cback = (tBTA_HD_CBACK_DATA *)p_data;
+
+    APPL_TRACE_API("%s", __func__);
+
+    bta_sys_busy(BTA_ID_HD, 1, p_cback->addr);
+    bta_sys_idle(BTA_ID_HD, 1, p_cback->addr);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_cback
+ *
+ * Description      BTA HD callback function
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hd_cback(BD_ADDR bd_addr, uint8_t event, uint32_t data, BT_HDR *pdata)
+{
+    tBTA_HD_CBACK_DATA *p_buf = NULL;
+    uint16_t sm_event = BTA_HD_INVALID_EVT;
+
+    APPL_TRACE_API("%s: event=%d", __func__, event);
+
+    switch (event) {
+    case HID_DHOST_EVT_OPEN:
+        sm_event = BTA_HD_INT_OPEN_EVT;
+        break;
+
+    case HID_DHOST_EVT_CLOSE:
+        sm_event = BTA_HD_INT_CLOSE_EVT;
+        break;
+
+    case HID_DHOST_EVT_GET_REPORT:
+        sm_event = BTA_HD_INT_GET_REPORT_EVT;
+        break;
+
+    case HID_DHOST_EVT_SET_REPORT:
+        sm_event = BTA_HD_INT_SET_REPORT_EVT;
+        break;
+
+    case HID_DHOST_EVT_SET_PROTOCOL:
+        sm_event = BTA_HD_INT_SET_PROTOCOL_EVT;
+        break;
+
+    case HID_DHOST_EVT_INTR_DATA:
+        sm_event = BTA_HD_INT_INTR_DATA_EVT;
+        break;
+
+    case HID_DHOST_EVT_VC_UNPLUG:
+        sm_event = BTA_HD_INT_VC_UNPLUG_EVT;
+        break;
+
+    case HID_DHOST_EVT_SUSPEND:
+        sm_event = BTA_HD_INT_SUSPEND_EVT;
+        break;
+
+    case HID_DHOST_EVT_EXIT_SUSPEND:
+        sm_event = BTA_HD_INT_EXIT_SUSPEND_EVT;
+        break;
+    }
+
+    if (sm_event != BTA_HD_INVALID_EVT &&
+        (p_buf = (tBTA_HD_CBACK_DATA *)osi_malloc(sizeof(tBTA_HD_CBACK_DATA) + sizeof(BT_HDR))) != NULL) {
+        p_buf->hdr.event = sm_event;
+        bdcpy(p_buf->addr, bd_addr);
+        p_buf->data = data;
+        p_buf->p_data = pdata;
+
+        bta_sys_sendmsg(p_buf);
+    }
+}
+#endif /* BTA_HD_INCLUDED */

+ 287 - 0
components/bt/host/bluedroid/bta/hd/bta_hd_api.c

@@ -0,0 +1,287 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *  Copyright (C) 2005-2012 Broadcom Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+/******************************************************************************
+ *
+ *  This file contains the HID DEVICE API in the subsystem of BTA.
+ *
+ ******************************************************************************/
+#include "common/bt_target.h"
+
+#if defined(BTA_HD_INCLUDED) && (BTA_HD_INCLUDED == TRUE)
+
+#include "bta/bta_hd_api.h"
+#include "bta_hd_int.h"
+#include "osi/allocator.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+static const tBTA_SYS_REG bta_hd_reg = {bta_hd_hdl_event, BTA_HdDisable};
+/*******************************************************************************
+ *
+ * Function         BTA_HdEnable
+ *
+ * Description      Enables HID device
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HdEnable(tBTA_HD_CBACK *p_cback)
+{
+    tBTA_HD_API_ENABLE *p_buf;
+    APPL_TRACE_API("%s", __func__);
+    bta_sys_register(BTA_ID_HD, &bta_hd_reg);
+    p_buf = (tBTA_HD_API_ENABLE *)osi_malloc((uint16_t)sizeof(tBTA_HD_API_ENABLE));
+    if (p_buf != NULL) {
+        memset(p_buf, 0, sizeof(tBTA_HD_API_ENABLE));
+        p_buf->hdr.event = BTA_HD_API_ENABLE_EVT;
+        p_buf->p_cback = p_cback;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+/*******************************************************************************
+ *
+ * Function         BTA_HdDisable
+ *
+ * Description      Disables HID device.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HdDisable(void)
+{
+    BT_HDR *p_buf;
+    APPL_TRACE_API("%s", __func__);
+    bta_sys_deregister(BTA_ID_HD);
+    if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR))) != NULL) {
+        p_buf->event = BTA_HD_API_DISABLE_EVT;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+/*******************************************************************************
+ *
+ * Function         BTA_HdRegisterApp
+ *
+ * Description      This function is called when application should be
+ *registered
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HdRegisterApp(tBTA_HD_APP_INFO *p_app_info, tBTA_HD_QOS_INFO *p_in_qos, tBTA_HD_QOS_INFO *p_out_qos)
+{
+    tBTA_HD_REGISTER_APP *p_buf;
+    APPL_TRACE_API("%s", __func__);
+    if ((p_buf = (tBTA_HD_REGISTER_APP *)osi_malloc(sizeof(tBTA_HD_REGISTER_APP))) != NULL) {
+        p_buf->hdr.event = BTA_HD_API_REGISTER_APP_EVT;
+        if (p_app_info->p_name) {
+            strncpy(p_buf->name, p_app_info->p_name, BTA_HD_APP_NAME_LEN);
+            p_buf->name[BTA_HD_APP_NAME_LEN] = '\0';
+        } else {
+            p_buf->name[0] = '\0';
+        }
+        if (p_app_info->p_description) {
+            strncpy(p_buf->description, p_app_info->p_description, BTA_HD_APP_DESCRIPTION_LEN);
+            p_buf->description[BTA_HD_APP_DESCRIPTION_LEN] = '\0';
+        } else {
+            p_buf->description[0] = '\0';
+        }
+        if (p_app_info->p_provider) {
+            strncpy(p_buf->provider, p_app_info->p_provider, BTA_HD_APP_PROVIDER_LEN);
+            p_buf->provider[BTA_HD_APP_PROVIDER_LEN] = '\0';
+        } else {
+            p_buf->provider[0] = '\0';
+        }
+        p_buf->subclass = p_app_info->subclass;
+        p_buf->d_len = p_app_info->descriptor.dl_len;
+        memcpy(p_buf->d_data, p_app_info->descriptor.dsc_list, p_app_info->descriptor.dl_len);
+        // copy qos data as-is
+        memcpy(&p_buf->in_qos, p_in_qos, sizeof(tBTA_HD_QOS_INFO));
+        memcpy(&p_buf->out_qos, p_out_qos, sizeof(tBTA_HD_QOS_INFO));
+        bta_sys_sendmsg(p_buf);
+    }
+}
+/*******************************************************************************
+ *
+ * Function         BTA_HdUnregisterApp
+ *
+ * Description      This function is called when application should be
+ *unregistered
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HdUnregisterApp(void)
+{
+    BT_HDR *p_buf;
+    APPL_TRACE_API("%s", __func__);
+    if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR))) != NULL) {
+        p_buf->event = BTA_HD_API_UNREGISTER_APP_EVT;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+/*******************************************************************************
+ *
+ * Function         BTA_HdSendReport
+ *
+ * Description      This function is called when report is to be sent
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HdSendReport(tBTA_HD_REPORT *p_report)
+{
+    tBTA_HD_SEND_REPORT *p_buf;
+    APPL_TRACE_VERBOSE("%s", __func__);
+    if (p_report->len > BTA_HD_REPORT_LEN) {
+        APPL_TRACE_WARNING("%s, report len (%d) > MTU len (%d), can't send report."
+                           " Increase value of HID_DEV_MTU_SIZE to send larger reports",
+                           __func__, p_report->len, BTA_HD_REPORT_LEN);
+        return;
+    }
+    if ((p_buf = (tBTA_HD_SEND_REPORT *)osi_malloc(sizeof(tBTA_HD_SEND_REPORT))) != NULL) {
+        p_buf->hdr.event = BTA_HD_API_SEND_REPORT_EVT;
+        p_buf->use_intr = p_report->use_intr;
+        p_buf->type = p_report->type;
+        p_buf->id = p_report->id;
+        p_buf->len = p_report->len;
+        memcpy(p_buf->data, p_report->p_data, p_report->len);
+        bta_sys_sendmsg(p_buf);
+    }
+}
+/*******************************************************************************
+ *
+ * Function         BTA_HdVirtualCableUnplug
+ *
+ * Description      This function is called when VCU shall be sent
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HdVirtualCableUnplug(void)
+{
+    BT_HDR *p_buf;
+    APPL_TRACE_API("%s", __func__);
+    if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR))) != NULL) {
+        p_buf->event = BTA_HD_API_VC_UNPLUG_EVT;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HdConnect
+ *
+ * Description      This function is called when connection to host shall be
+ *                  made
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HdConnect(BD_ADDR addr)
+{
+    tBTA_HD_DEVICE_CTRL *p_buf;
+    APPL_TRACE_API("%s", __func__);
+
+    if ((p_buf = (tBTA_HD_DEVICE_CTRL *)osi_malloc(sizeof(tBTA_HD_DEVICE_CTRL))) != NULL) {
+        p_buf->hdr.event = BTA_HD_API_CONNECT_EVT;
+        memcpy(p_buf->addr, addr, sizeof(BD_ADDR));
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HdDisconnect
+ *
+ * Description      This function is called when host shall be disconnected
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HdDisconnect(void)
+{
+    BT_HDR *p_buf;
+    APPL_TRACE_API("%s", __func__);
+    if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR))) != NULL) {
+        p_buf->event = BTA_HD_API_DISCONNECT_EVT;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+/*******************************************************************************
+ *
+ * Function         BTA_HdAddDevice
+ *
+ * Description      This function is called when a device is virtually cabled
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HdAddDevice(BD_ADDR addr)
+{
+    tBTA_HD_DEVICE_CTRL *p_buf;
+    APPL_TRACE_API("%s", __func__);
+    if ((p_buf = (tBTA_HD_DEVICE_CTRL *)osi_malloc(sizeof(tBTA_HD_DEVICE_CTRL))) != NULL) {
+        p_buf->hdr.event = BTA_HD_API_ADD_DEVICE_EVT;
+        memcpy(p_buf->addr, addr, sizeof(BD_ADDR));
+        bta_sys_sendmsg(p_buf);
+    }
+}
+/*******************************************************************************
+ *
+ * Function         BTA_HdRemoveDevice
+ *
+ * Description      This function is called when a device is virtually uncabled
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HdRemoveDevice(BD_ADDR addr)
+{
+    tBTA_HD_DEVICE_CTRL *p_buf;
+    APPL_TRACE_API("%s", __func__);
+    if ((p_buf = (tBTA_HD_DEVICE_CTRL *)osi_malloc(sizeof(tBTA_HD_DEVICE_CTRL))) != NULL) {
+        p_buf->hdr.event = BTA_HD_API_REMOVE_DEVICE_EVT;
+        memcpy(p_buf->addr, addr, sizeof(BD_ADDR));
+        bta_sys_sendmsg(p_buf);
+    }
+}
+/*******************************************************************************
+ *
+ * Function         BTA_HdReportError
+ *
+ * Description      This function is called when reporting error for set report
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HdReportError(uint8_t error)
+{
+    tBTA_HD_REPORT_ERR *p_buf;
+    APPL_TRACE_API("%s", __func__);
+    if ((p_buf = (tBTA_HD_REPORT_ERR *)osi_malloc(sizeof(tBTA_HD_REPORT_ERR))) != NULL) {
+        p_buf->hdr.event = BTA_HD_API_REPORT_ERROR_EVT;
+        p_buf->error = error;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+#endif /* BTA_HD_INCLUDED */

+ 320 - 0
components/bt/host/bluedroid/bta/hd/bta_hd_main.c

@@ -0,0 +1,320 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *  Copyright (C) 2005-2012 Broadcom Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+/******************************************************************************
+ *
+ *  This file contains the HID host main functions and state machine.
+ *
+ ******************************************************************************/
+#include "common/bt_target.h"
+
+#if defined(BTA_HD_INCLUDED) && (BTA_HD_INCLUDED == TRUE)
+
+#include "bta/bta_hd_api.h"
+#include "bta_hd_int.h"
+#include <string.h>
+
+/*****************************************************************************
+ * Constants and types
+ ****************************************************************************/
+/* state machine states */
+enum {
+    BTA_HD_INIT_ST,
+    BTA_HD_IDLE_ST,              /* not connected, waiting for connection */
+    BTA_HD_CONN_ST,              /* host connected */
+    BTA_HD_TRANSIENT_TO_INIT_ST, /* transient state: going back from CONN to INIT */
+};
+typedef uint8_t tBTA_HD_STATE;
+
+/* state machine actions */
+enum {
+    BTA_HD_REGISTER_ACT,
+    BTA_HD_UNREGISTER_ACT,
+    BTA_HD_UNREGISTER2_ACT,
+    BTA_HD_CONNECT_ACT,
+    BTA_HD_DISCONNECT_ACT,
+    BTA_HD_ADD_DEVICE_ACT,
+    BTA_HD_REMOVE_DEVICE_ACT,
+    BTA_HD_SEND_REPORT_ACT,
+    BTA_HD_REPORT_ERROR_ACT,
+    BTA_HD_VC_UNPLUG_ACT,
+    BTA_HD_OPEN_ACT,
+    BTA_HD_CLOSE_ACT,
+    BTA_HD_INTR_DATA_ACT,
+    BTA_HD_GET_REPORT_ACT,
+    BTA_HD_SET_REPORT_ACT,
+    BTA_HD_SET_PROTOCOL_ACT,
+    BTA_HD_VC_UNPLUG_DONE_ACT,
+    BTA_HD_SUSPEND_ACT,
+    BTA_HD_EXIT_SUSPEND_ACT,
+    BTA_HD_NUM_ACTIONS
+};
+
+#define BTA_HD_IGNORE BTA_HD_NUM_ACTIONS
+
+typedef void (*tBTA_HD_ACTION)(tBTA_HD_DATA *p_data);
+/* action functions */
+const tBTA_HD_ACTION bta_hd_action[] = {
+    bta_hd_register_act,       bta_hd_unregister_act, bta_hd_unregister2_act,   bta_hd_connect_act,
+    bta_hd_disconnect_act,     bta_hd_add_device_act, bta_hd_remove_device_act, bta_hd_send_report_act,
+    bta_hd_report_error_act,   bta_hd_vc_unplug_act,  bta_hd_open_act,          bta_hd_close_act,
+    bta_hd_intr_data_act,      bta_hd_get_report_act, bta_hd_set_report_act,    bta_hd_set_protocol_act,
+    bta_hd_vc_unplug_done_act, bta_hd_suspend_act,    bta_hd_exit_suspend_act,
+};
+
+/* state table information */
+#define BTA_HD_ACTION 0     /* position of action */
+#define BTA_HD_NEXT_STATE 1 /* position of next state */
+#define BTA_HD_NUM_COLS 2   /* number of columns */
+
+const uint8_t bta_hd_st_init[][BTA_HD_NUM_COLS] = {
+    /* Event                               Action                     Next state
+     */
+    /* BTA_HD_API_REGISTER_APP_EVT   */ {BTA_HD_REGISTER_ACT, BTA_HD_IDLE_ST},
+    /* BTA_HD_API_UNREGISTER_APP_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+    /* BTA_HD_API_CONNECT_EVT        */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+    /* BTA_HD_API_DISCONNECT_EVT     */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+    /* BTA_HD_API_ADD_DEVICE_EVT     */ {BTA_HD_ADD_DEVICE_ACT, BTA_HD_INIT_ST},
+    /* BTA_HD_API_REMOVE_DEVICE_EVT  */ {BTA_HD_REMOVE_DEVICE_ACT, BTA_HD_INIT_ST},
+    /* BTA_HD_API_SEND_REPORT_EVT    */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+    /* BTA_HD_API_REPORT_ERROR_EVT   */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+    /* BTA_HD_API_VC_UNPLUG_EVT      */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+    /* BTA_HD_INT_OPEN_EVT           */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+    /* BTA_HD_INT_CLOSE_EVT          */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+    /* BTA_HD_INT_INTR_DATA_EVT      */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+    /* BTA_HD_INT_GET_REPORT_EVT     */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+    /* BTA_HD_INT_SET_REPORT_EVT     */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+    /* BTA_HD_INT_SET_PROTOCOL_EVT   */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+    /* BTA_HD_INT_VC_UNPLUG_EVT      */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+    /* BTA_HD_INT_SUSPEND_EVT        */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+    /* BTA_HD_INT_EXIT_SUSPEND_EVT   */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+};
+
+const uint8_t bta_hd_st_idle[][BTA_HD_NUM_COLS] = {
+    /* Event                               Action                     Next state
+     */
+    /* BTA_HD_API_REGISTER_APP_EVT   */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+    /* BTA_HD_API_UNREGISTER_APP_EVT */ {BTA_HD_UNREGISTER_ACT, BTA_HD_INIT_ST},
+    /* BTA_HD_API_CONNECT_EVT        */ {BTA_HD_CONNECT_ACT, BTA_HD_IDLE_ST},
+    /* BTA_HD_API_DISCONNECT_EVT     */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+    /* BTA_HD_API_ADD_DEVICE_EVT     */ {BTA_HD_ADD_DEVICE_ACT, BTA_HD_IDLE_ST},
+    /* BTA_HD_API_REMOVE_DEVICE_EVT  */ {BTA_HD_REMOVE_DEVICE_ACT, BTA_HD_IDLE_ST},
+    /* BTA_HD_API_SEND_REPORT_EVT    */ {BTA_HD_SEND_REPORT_ACT, BTA_HD_IDLE_ST},
+    /* BTA_HD_API_REPORT_ERROR_EVT   */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+    /* BTA_HD_API_VC_UNPLUG_EVT      */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+    /* BTA_HD_INT_OPEN_EVT           */ {BTA_HD_OPEN_ACT, BTA_HD_CONN_ST},
+    /* BTA_HD_INT_CLOSE_EVT          */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+    /* BTA_HD_INT_INTR_DATA_EVT      */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+    /* BTA_HD_INT_GET_REPORT_EVT     */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+    /* BTA_HD_INT_SET_REPORT_EVT     */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+    /* BTA_HD_INT_SET_PROTOCOL_EVT   */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+    /* BTA_HD_INT_VC_UNPLUG_EVT      */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+    /* BTA_HD_INT_SUSPEND_EVT        */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+    /* BTA_HD_INT_EXIT_SUSPEND_EVT   */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+};
+
+const uint8_t bta_hd_st_conn[][BTA_HD_NUM_COLS] = {
+    /* Event                               Action Next state */
+    /* BTA_HD_API_REGISTER_APP_EVT   */ {BTA_HD_IGNORE, BTA_HD_CONN_ST},
+    /* BTA_HD_API_UNREGISTER_APP_EVT */ {BTA_HD_DISCONNECT_ACT, BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_API_CONNECT_EVT        */ {BTA_HD_IGNORE, BTA_HD_CONN_ST},
+    /* BTA_HD_API_DISCONNECT_EVT     */ {BTA_HD_DISCONNECT_ACT, BTA_HD_CONN_ST},
+    /* BTA_HD_API_ADD_DEVICE_EVT     */ {BTA_HD_ADD_DEVICE_ACT, BTA_HD_CONN_ST},
+    /* BTA_HD_API_REMOVE_DEVICE_EVT  */ {BTA_HD_REMOVE_DEVICE_ACT, BTA_HD_CONN_ST},
+    /* BTA_HD_API_SEND_REPORT_EVT    */ {BTA_HD_SEND_REPORT_ACT, BTA_HD_CONN_ST},
+    /* BTA_HD_API_REPORT_ERROR_EVT   */ {BTA_HD_REPORT_ERROR_ACT, BTA_HD_CONN_ST},
+    /* BTA_HD_API_VC_UNPLUG_EVT      */ {BTA_HD_VC_UNPLUG_ACT, BTA_HD_CONN_ST},
+    /* BTA_HD_INT_OPEN_EVT           */ {BTA_HD_IGNORE, BTA_HD_CONN_ST},
+    /* BTA_HD_INT_CLOSE_EVT          */ {BTA_HD_CLOSE_ACT, BTA_HD_IDLE_ST},
+    /* BTA_HD_INT_INTR_DATA_EVT      */ {BTA_HD_INTR_DATA_ACT, BTA_HD_CONN_ST},
+    /* BTA_HD_INT_GET_REPORT_EVT     */ {BTA_HD_GET_REPORT_ACT, BTA_HD_CONN_ST},
+    /* BTA_HD_INT_SET_REPORT_EVT     */ {BTA_HD_SET_REPORT_ACT, BTA_HD_CONN_ST},
+    /* BTA_HD_INT_SET_PROTOCOL_EVT   */ {BTA_HD_SET_PROTOCOL_ACT, BTA_HD_CONN_ST},
+    /* BTA_HD_INT_VC_UNPLUG_EVT      */ {BTA_HD_VC_UNPLUG_DONE_ACT, BTA_HD_IDLE_ST},
+    /* BTA_HD_INT_SUSPEND_EVT        */ {BTA_HD_SUSPEND_ACT, BTA_HD_CONN_ST},
+    /* BTA_HD_INT_EXIT_SUSPEND_EVT   */ {BTA_HD_EXIT_SUSPEND_ACT, BTA_HD_CONN_ST},
+};
+
+const uint8_t bta_hd_st_transient_to_init[][BTA_HD_NUM_COLS] = {
+    /* Event                               Action Next state */
+    /* BTA_HD_API_REGISTER_APP_EVT   */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_API_UNREGISTER_APP_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_API_CONNECT_EVT        */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_API_DISCONNECT_EVT     */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_API_ADD_DEVICE_EVT     */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_API_REMOVE_DEVICE_EVT  */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_API_SEND_REPORT_EVT    */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_API_REPORT_ERROR_EVT   */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_API_VC_UNPLUG_EVT      */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_INT_OPEN_EVT           */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_INT_CLOSE_EVT          */ {BTA_HD_UNREGISTER2_ACT, BTA_HD_INIT_ST},
+    /* BTA_HD_INT_INTR_DATA_EVT      */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_INT_GET_REPORT_EVT     */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_INT_SET_REPORT_EVT     */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_INT_SET_PROTOCOL_EVT   */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_INT_VC_UNPLUG_EVT      */ {BTA_HD_UNREGISTER2_ACT, BTA_HD_INIT_ST},
+    /* BTA_HD_INT_SUSPEND_EVT        */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_INT_EXIT_SUSPEND_EVT   */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
+};
+
+/* type for state table */
+typedef const uint8_t (*tBTA_HD_ST_TBL)[BTA_HD_NUM_COLS];
+/* state table */
+const tBTA_HD_ST_TBL bta_hd_st_tbl[] = {bta_hd_st_init, bta_hd_st_idle, bta_hd_st_conn, bta_hd_st_transient_to_init};
+
+/*****************************************************************************
+ * Global data
+ ****************************************************************************/
+#if BTA_DYNAMIC_MEMORY == FALSE
+tBTA_HD_CB bta_hd_cb;
+#else
+tBTA_HD_CB *bta_hd_cb_ptr;
+#endif
+
+static const char *bta_hd_evt_code(tBTA_HD_INT_EVT evt_code);
+static const char *bta_hd_state_code(tBTA_HD_STATE state_code);
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_sm_execute
+ *
+ * Description      State machine event handling function for HID Device
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hd_sm_execute(uint16_t event, tBTA_HD_DATA *p_data)
+{
+    tBTA_HD_ST_TBL state_table;
+    tBTA_HD_STATE prev_state;
+    uint8_t action;
+    tBTA_HD cback_data;
+
+    APPL_TRACE_EVENT("%s: state=%s (%d) event=%s (%d)", __func__, bta_hd_state_code(bta_hd_cb.state), bta_hd_cb.state,
+                     bta_hd_evt_code(event), event);
+
+    prev_state = bta_hd_cb.state;
+    memset(&cback_data, 0, sizeof(tBTA_HD));
+    state_table = bta_hd_st_tbl[bta_hd_cb.state];
+    event &= 0xff;
+
+    if ((action = state_table[event][BTA_HD_ACTION]) < BTA_HD_IGNORE) {
+        (*bta_hd_action[action])(p_data);
+    }
+
+    bta_hd_cb.state = state_table[event][BTA_HD_NEXT_STATE];
+
+    if (bta_hd_cb.state != prev_state) {
+        APPL_TRACE_EVENT("%s: [new] state=%s (%d)", __func__, bta_hd_state_code(bta_hd_cb.state), bta_hd_cb.state);
+    }
+    return;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_hdl_event
+ *
+ * Description      HID device main event handling function.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+bool bta_hd_hdl_event(BT_HDR *p_msg)
+{
+    APPL_TRACE_API("%s: p_msg->event=%d", __func__, p_msg->event);
+
+    switch (p_msg->event) {
+    case BTA_HD_API_ENABLE_EVT:
+        bta_hd_api_enable((tBTA_HD_DATA *)p_msg);
+        break;
+    case BTA_HD_API_DISABLE_EVT:
+        if (bta_hd_cb.state == BTA_HD_CONN_ST) {
+            APPL_TRACE_WARNING("%s: host connected, disconnect before disabling", __func__);
+            // unregister (and disconnect)
+            bta_hd_cb.disable_w4_close = TRUE;
+            bta_hd_sm_execute(BTA_HD_API_UNREGISTER_APP_EVT, (tBTA_HD_DATA *)p_msg);
+        } else {
+            bta_hd_api_disable();
+        }
+        break;
+    default:
+        bta_hd_sm_execute(p_msg->event, (tBTA_HD_DATA *)p_msg);
+    }
+    return (TRUE);
+}
+
+static const char *bta_hd_evt_code(tBTA_HD_INT_EVT evt_code)
+{
+    switch (evt_code) {
+    case BTA_HD_API_REGISTER_APP_EVT:
+        return "BTA_HD_API_REGISTER_APP_EVT";
+    case BTA_HD_API_UNREGISTER_APP_EVT:
+        return "BTA_HD_API_UNREGISTER_APP_EVT";
+    case BTA_HD_API_CONNECT_EVT:
+        return "BTA_HD_API_CONNECT_EVT";
+    case BTA_HD_API_DISCONNECT_EVT:
+        return "BTA_HD_API_DISCONNECT_EVT";
+    case BTA_HD_API_ADD_DEVICE_EVT:
+        return "BTA_HD_API_ADD_DEVICE_EVT";
+    case BTA_HD_API_REMOVE_DEVICE_EVT:
+        return "BTA_HD_API_REMOVE_DEVICE_EVT";
+    case BTA_HD_API_SEND_REPORT_EVT:
+        return "BTA_HD_API_SEND_REPORT_EVT";
+    case BTA_HD_API_REPORT_ERROR_EVT:
+        return "BTA_HD_API_REPORT_ERROR_EVT";
+    case BTA_HD_API_VC_UNPLUG_EVT:
+        return "BTA_HD_API_VC_UNPLUG_EVT";
+    case BTA_HD_INT_OPEN_EVT:
+        return "BTA_HD_INT_OPEN_EVT";
+    case BTA_HD_INT_CLOSE_EVT:
+        return "BTA_HD_INT_CLOSE_EVT";
+    case BTA_HD_INT_INTR_DATA_EVT:
+        return "BTA_HD_INT_INTR_DATA_EVT";
+    case BTA_HD_INT_GET_REPORT_EVT:
+        return "BTA_HD_INT_GET_REPORT_EVT";
+    case BTA_HD_INT_SET_REPORT_EVT:
+        return "BTA_HD_INT_SET_REPORT_EVT";
+    case BTA_HD_INT_SET_PROTOCOL_EVT:
+        return "BTA_HD_INT_SET_PROTOCOL_EVT";
+    case BTA_HD_INT_VC_UNPLUG_EVT:
+        return "BTA_HD_INT_VC_UNPLUG_EVT";
+    case BTA_HD_INT_SUSPEND_EVT:
+        return "BTA_HD_INT_SUSPEND_EVT";
+    case BTA_HD_INT_EXIT_SUSPEND_EVT:
+        return "BTA_HD_INT_EXIT_SUSPEND_EVT";
+    default:
+        return "<unknown>";
+    }
+}
+
+static const char *bta_hd_state_code(tBTA_HD_STATE state_code)
+{
+    switch (state_code) {
+    case BTA_HD_INIT_ST:
+        return "BTA_HD_INIT_ST";
+    case BTA_HD_IDLE_ST:
+        return "BTA_HD_IDLE_ST";
+    case BTA_HD_CONN_ST:
+        return "BTA_HD_CONN_ST";
+    case BTA_HD_TRANSIENT_TO_INIT_ST:
+        return "BTA_HD_TRANSIENT_TO_INIT_ST";
+    default:
+        return "<unknown>";
+    }
+}
+#endif /* BTA_HD_INCLUDED */

+ 168 - 0
components/bt/host/bluedroid/bta/hd/include/bta_hd_int.h

@@ -0,0 +1,168 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *  Copyright (C) 2005-2012 Broadcom Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+/******************************************************************************
+ *
+ *  This file contains BTA HID Device internal definitions
+ *
+ ******************************************************************************/
+#ifndef BTA_HD_INT_H
+#define BTA_HD_INT_H
+
+#include "bta/bta_hd_api.h"
+#include "bta/bta_sys.h"
+#include "stack/hiddefs.h"
+
+enum {
+    BTA_HD_API_REGISTER_APP_EVT = BTA_SYS_EVT_START(BTA_ID_HD),
+    BTA_HD_API_UNREGISTER_APP_EVT,
+    BTA_HD_API_CONNECT_EVT,
+    BTA_HD_API_DISCONNECT_EVT,
+    BTA_HD_API_ADD_DEVICE_EVT,
+    BTA_HD_API_REMOVE_DEVICE_EVT,
+    BTA_HD_API_SEND_REPORT_EVT,
+    BTA_HD_API_REPORT_ERROR_EVT,
+    BTA_HD_API_VC_UNPLUG_EVT,
+    BTA_HD_INT_OPEN_EVT,
+    BTA_HD_INT_CLOSE_EVT,
+    BTA_HD_INT_INTR_DATA_EVT,
+    BTA_HD_INT_GET_REPORT_EVT,
+    BTA_HD_INT_SET_REPORT_EVT,
+    BTA_HD_INT_SET_PROTOCOL_EVT,
+    BTA_HD_INT_VC_UNPLUG_EVT,
+    BTA_HD_INT_SUSPEND_EVT,
+    BTA_HD_INT_EXIT_SUSPEND_EVT,
+    /* handled outside state machine */
+    BTA_HD_API_ENABLE_EVT,
+    BTA_HD_API_DISABLE_EVT
+};
+typedef uint16_t tBTA_HD_INT_EVT;
+#define BTA_HD_INVALID_EVT (BTA_HD_API_DISABLE_EVT + 1)
+typedef struct {
+    BT_HDR hdr;
+    tBTA_HD_CBACK *p_cback;
+} tBTA_HD_API_ENABLE;
+#define BTA_HD_APP_NAME_LEN 50
+#define BTA_HD_APP_DESCRIPTION_LEN 50
+#define BTA_HD_APP_PROVIDER_LEN 50
+#define BTA_HD_APP_DESCRIPTOR_LEN 2048
+#define BTA_HD_STATE_DISABLED 0x00
+#define BTA_HD_STATE_ENABLED 0x01
+#define BTA_HD_STATE_IDLE 0x02
+#define BTA_HD_STATE_CONNECTED 0x03
+#define BTA_HD_STATE_DISABLING 0x04
+#define BTA_HD_STATE_REMOVING 0x05
+typedef struct {
+    BT_HDR hdr;
+    char name[BTA_HD_APP_NAME_LEN + 1];
+    char description[BTA_HD_APP_DESCRIPTION_LEN + 1];
+    char provider[BTA_HD_APP_PROVIDER_LEN + 1];
+    uint8_t subclass;
+    uint16_t d_len;
+    uint8_t d_data[BTA_HD_APP_DESCRIPTOR_LEN];
+    tBTA_HD_QOS_INFO in_qos;
+    tBTA_HD_QOS_INFO out_qos;
+} tBTA_HD_REGISTER_APP;
+
+#define BTA_HD_REPORT_LEN HID_DEV_MTU_SIZE
+
+typedef struct {
+    BT_HDR hdr;
+    bool use_intr;
+    uint8_t type;
+    uint8_t id;
+    uint16_t len;
+    uint8_t data[BTA_HD_REPORT_LEN];
+} tBTA_HD_SEND_REPORT;
+
+typedef struct {
+    BT_HDR hdr;
+    BD_ADDR addr;
+} tBTA_HD_DEVICE_CTRL;
+
+typedef struct {
+    BT_HDR hdr;
+    uint8_t error;
+} tBTA_HD_REPORT_ERR;
+
+/* union of all event data types */
+typedef union {
+    BT_HDR hdr;
+    tBTA_HD_API_ENABLE api_enable;
+    tBTA_HD_REGISTER_APP register_app;
+    tBTA_HD_SEND_REPORT send_report;
+    tBTA_HD_DEVICE_CTRL device_ctrl;
+    tBTA_HD_REPORT_ERR report_err;
+} tBTA_HD_DATA;
+
+typedef struct {
+    BT_HDR hdr;
+    BD_ADDR addr;
+    uint32_t data;
+    BT_HDR *p_data;
+} tBTA_HD_CBACK_DATA;
+
+/******************************************************************************
+ * Main Control Block
+ ******************************************************************************/
+typedef struct {
+    tBTA_HD_CBACK *p_cback;
+    uint32_t sdp_handle;
+    uint8_t trace_level;
+    uint8_t state;
+    BD_ADDR bd_addr;
+    bool use_report_id;
+    bool boot_mode;
+    bool vc_unplug;
+    bool disable_w4_close;
+} tBTA_HD_CB;
+
+#if BTA_DYNAMIC_MEMORY == FALSE
+extern tBTA_HD_CB bta_hd_cb;
+#else
+extern tBTA_HD_CB *bta_hd_cb_ptr;
+#define bta_hd_cb (*bta_hd_cb_ptr)
+#endif
+
+/*****************************************************************************
+ *  Function prototypes
+ ****************************************************************************/
+extern bool bta_hd_hdl_event(BT_HDR *p_msg);
+extern void bta_hd_api_enable(tBTA_HD_DATA *p_data);
+extern void bta_hd_api_disable(void);
+extern void bta_hd_register_act(tBTA_HD_DATA *p_data);
+extern void bta_hd_unregister_act(tBTA_HD_DATA *p_data);
+extern void bta_hd_unregister2_act(tBTA_HD_DATA *p_data);
+extern void bta_hd_connect_act(tBTA_HD_DATA *p_data);
+extern void bta_hd_disconnect_act(tBTA_HD_DATA *p_data);
+extern void bta_hd_add_device_act(tBTA_HD_DATA *p_data);
+extern void bta_hd_remove_device_act(tBTA_HD_DATA *p_data);
+extern void bta_hd_send_report_act(tBTA_HD_DATA *p_data);
+extern void bta_hd_report_error_act(tBTA_HD_DATA *p_data);
+extern void bta_hd_vc_unplug_act(tBTA_HD_DATA *p_data);
+extern void bta_hd_open_act(tBTA_HD_DATA *p_data);
+extern void bta_hd_close_act(tBTA_HD_DATA *p_data);
+extern void bta_hd_intr_data_act(tBTA_HD_DATA *p_data);
+extern void bta_hd_get_report_act(tBTA_HD_DATA *p_data);
+extern void bta_hd_set_report_act(tBTA_HD_DATA *p_data);
+extern void bta_hd_set_protocol_act(tBTA_HD_DATA *p_data);
+extern void bta_hd_vc_unplug_done_act(tBTA_HD_DATA *p_data);
+extern void bta_hd_suspend_act(tBTA_HD_DATA *p_data);
+extern void bta_hd_exit_suspend_act(tBTA_HD_DATA *p_data);
+
+#endif

+ 1 - 1
components/bt/host/bluedroid/bta/hf_client/bta_hf_client_main.c

@@ -214,7 +214,7 @@ const UINT8 bta_hf_client_st_closing[][BTA_HF_CLIENT_NUM_COLS] = {
     /* DISC_OK_EVT */           {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_CLOSING_ST},
     /* DISC_FAIL_EVT */         {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_CLOSING_ST},
     /* SCO_OPEN_EVT */          {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_CLOSING_ST},
-    /* SCO_CLOSE_EVT */         {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_CLOSING_ST},
+    /* SCO_CLOSE_EVT */         {BTA_HF_CLIENT_SCO_CONN_CLOSE, BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_CLOSING_ST},
     /* SEND_AT_CMD_EVT */       {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_CLOSING_ST},
 #if (BTM_SCO_HCI_INCLUDED == TRUE )
     /* CI_SCO_DATA_EVT */       {BTA_HF_CLIENT_IGNORE,         BTA_HF_CLIENT_IGNORE,          BTA_HF_CLIENT_CLOSING_ST},

+ 38 - 12
components/bt/host/bluedroid/bta/hh/bta_hh_act.c

@@ -323,6 +323,7 @@ void bta_hh_start_sdp(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
 
     p_cb->sec_mask  = p_data->api_conn.sec_mask;
     p_cb->mode      = p_data->api_conn.mode;
+    p_cb->new_mode  = p_data->api_conn.mode;
     bta_hh_cb.p_cur = p_cb;
 
 #if (BTA_HH_LE_INCLUDED == TRUE)
@@ -451,6 +452,8 @@ void bta_hh_sdp_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
             HID_HostRemoveDev( p_cb->incoming_hid_handle);
         }
         conn_dat.status = status;
+        /* check if host initiate the connection*/
+        conn_dat.is_orig = !p_cb->incoming_conn;
         (* bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn_dat);
 
         /* move state machine W4_CONN ->IDLE */
@@ -521,6 +524,8 @@ void bta_hh_open_cmpl_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
 
     memset((void *)&conn, 0, sizeof (tBTA_HH_CONN));
     conn.handle = dev_handle;
+    /* check if host initiate the connection*/
+    conn.is_orig = !p_cb->incoming_conn;
     bdcpy(conn.bda, p_cb->addr);
 
     /* increase connection number */
@@ -587,6 +592,7 @@ void bta_hh_open_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
     APPL_TRACE_EVENT ("bta_hh_open_act:  Device[%d] connected", dev_handle);
 #endif
 
+    p_cb->incoming_conn = TRUE;
     /* SDP has been done */
     if (p_cb->app_id != 0) {
         bta_hh_sm_execute(p_cb, BTA_HH_OPEN_CMPL_EVT, p_data);
@@ -594,7 +600,6 @@ void bta_hh_open_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
         /*  app_id == 0 indicates an incoming conenction request arrives without SDP
             performed, do it first */
     {
-        p_cb->incoming_conn = TRUE;
         /* store the handle here in case sdp fails - need to disconnect */
         p_cb->incoming_hid_handle = dev_handle;
 
@@ -676,6 +681,11 @@ void bta_hh_handsk_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
     case BTA_HH_SET_IDLE_EVT :
         cback_data.handle  = p_cb->hid_handle;
         cback_data.status = bta_hh_get_trans_status(p_data->hid_cback.data);
+        if (cback_data.status == BTA_HH_OK) {
+            p_cb->mode = p_cb->new_mode;
+        } else {
+            p_cb->new_mode = p_cb->mode;
+        }
         (* bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH *)&cback_data);
         p_cb->w4_evt = 0;
         break;
@@ -684,6 +694,8 @@ void bta_hh_handsk_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
     case BTA_HH_OPEN_EVT:
         conn.status = p_data->hid_cback.data ? BTA_HH_ERR_PROTO : BTA_HH_OK;
         conn.handle = p_cb->hid_handle;
+        /* check if host initiate the connection*/
+        conn.is_orig = !p_cb->incoming_conn;
         bdcpy(conn.bda, p_cb->addr);
         (* bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH *)&conn);
 #if BTA_HH_DEBUG
@@ -787,6 +799,8 @@ void bta_hh_open_failure(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
     conn_dat.handle = p_cb->hid_handle;
     conn_dat.status = (reason == HID_ERR_AUTH_FAILED) ?
                       BTA_HH_ERR_AUTH_FAILED : BTA_HH_ERR;
+    /* check if host initiate the connection*/
+    conn_dat.is_orig = !p_cb->incoming_conn;
     bdcpy(conn_dat.bda, p_cb->addr);
     HID_HostCloseDev(p_cb->hid_handle);
 
@@ -836,6 +850,8 @@ void bta_hh_close_act (tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
         /* Failure in opening connection */
         conn_dat.handle = p_cb->hid_handle;
         conn_dat.status = (reason == HID_ERR_AUTH_FAILED) ? BTA_HH_ERR_AUTH_FAILED : BTA_HH_ERR;
+        /* check if host initiate the connection*/
+        conn_dat.is_orig = !p_cb->incoming_conn;
         bdcpy(conn_dat.bda, p_cb->addr);
         HID_HostCloseDev(p_cb->hid_handle);
 
@@ -1019,7 +1035,9 @@ void bta_hh_maint_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
 *******************************************************************************/
 void bta_hh_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
 {
+    tHID_STATUS status;
     tBTA_HH_CBDATA     cbdata = {BTA_HH_OK, 0};
+    tBTA_HH_API_SENDDATA send_data = {BTA_HH_OK, 0, 0};
     UINT16  event = (p_data->api_sndcmd.t_type - BTA_HH_FST_BTE_TRANS_EVT) +
                     BTA_HH_FST_TRANS_CB_EVT;
 
@@ -1031,25 +1049,33 @@ void bta_hh_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
     {
 
         cbdata.handle = p_cb->hid_handle;
+        send_data.handle = p_cb->hid_handle;
 
         /* match up BTE/BTA report/boot mode def */
         if (p_data->api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL) {
+            p_cb->new_mode = p_data->api_sndcmd.param;
             p_data->api_sndcmd.param = ( p_data->api_sndcmd.param == BTA_HH_PROTO_RPT_MODE) ? \
                                        HID_PAR_PROTOCOL_REPORT : HID_PAR_PROTOCOL_BOOT_MODE;
         }
 
-        if (HID_HostWriteDev (p_cb->hid_handle,
-                              p_data->api_sndcmd.t_type,
-                              p_data->api_sndcmd.param,
-                              p_data->api_sndcmd.data,
-                              p_data->api_sndcmd.rpt_id,
-                              p_data->api_sndcmd.p_data) != HID_SUCCESS) {
-            APPL_TRACE_ERROR("HID_HostWriteDev Error ");
+        status = HID_HostWriteDev(p_cb->hid_handle, p_data->api_sndcmd.t_type, p_data->api_sndcmd.param,
+                                  p_data->api_sndcmd.data, p_data->api_sndcmd.rpt_id, p_data->api_sndcmd.p_data);
+        if (status != HID_SUCCESS) {
+            APPL_TRACE_ERROR("HID_HostWriteDev status:%d", status);
             cbdata.status = BTA_HH_ERR;
+            send_data.status = BTA_HH_ERR;
 
-            if (p_data->api_sndcmd.t_type != HID_TRANS_CONTROL &&
-                    p_data->api_sndcmd.t_type != HID_TRANS_DATA) {
-                (* bta_hh_cb.p_cback)(event, (tBTA_HH *)&cbdata);
+            if (p_data->api_sndcmd.t_type != HID_TRANS_CONTROL) {
+                switch (p_data->api_sndcmd.t_type) {
+                case HID_TRANS_DATA:
+                    event = BTA_HH_DATA_EVT;
+                    send_data.reason = status;
+                    (*bta_hh_cb.p_cback)(event, (tBTA_HH *)&send_data);
+                    break;
+                default:
+                    (*bta_hh_cb.p_cback)(event, (tBTA_HH *)&cbdata);
+                    break;
+                }
             } else if (p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG) {
                 (* bta_hh_cb.p_cback)(BTA_HH_VC_UNPLUG_EVT, (tBTA_HH *)&cbdata);
             }
@@ -1070,6 +1096,7 @@ void bta_hh_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
                 p_cb->w4_evt = event;
                 break;
             case HID_TRANS_DATA:  /* output report */
+                (*bta_hh_cb.p_cback)(BTA_HH_DATA_EVT, (tBTA_HH *)&send_data);
             /* fall through */
             case HID_TRANS_CONTROL:
                 /* no handshake event will be generated */
@@ -1098,7 +1125,6 @@ void bta_hh_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
                 bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr);
             }
         }
-
     }
     return;
 }

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini